add:agv模块看板
This commit is contained in:
260
nl-vue/src/views/nl_agv/car/form.vue
Normal file
260
nl-vue/src/views/nl_agv/car/form.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<xn-form-container
|
||||
:title="formData.carId ? '编辑车辆信息' : '新增车辆信息'"
|
||||
:width="900"
|
||||
:visible="visible"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<div class="form-content">
|
||||
<!-- 左侧:图片预览区域 -->
|
||||
<div class="image-preview-section" v-if="formData.carId && formData.icon">
|
||||
<div class="preview-title">车辆图片预览</div>
|
||||
<div class="preview-container">
|
||||
<a-image :src="formData.icon" :preview="true" class="car-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:表单区域 -->
|
||||
<div class="form-section" :class="{ 'full-width': !formData.carId || !formData.icon }">
|
||||
<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<a-form-item label="车辆ID:" name="carId">
|
||||
<a-input
|
||||
v-model:value="formData.carId"
|
||||
placeholder="请输入车辆ID"
|
||||
:disabled="!!formData.carId"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="车辆类型:" name="type">
|
||||
<a-input
|
||||
v-model:value="formData.type"
|
||||
placeholder="请输入车辆类型(如:PS车、NT车等)"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="车辆图片:" name="icon">
|
||||
<a-upload
|
||||
v-model:file-list="fileList"
|
||||
name="file"
|
||||
list-type="picture-card"
|
||||
class="car-uploader"
|
||||
:show-upload-list="true"
|
||||
:before-upload="beforeUpload"
|
||||
:custom-request="handleUpload"
|
||||
@remove="handleRemove"
|
||||
:max-count="1"
|
||||
>
|
||||
<div v-if="fileList.length < 1">
|
||||
<plus-outlined />
|
||||
<div style="margin-top: 8px">上传图片</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<div class="upload-tip">支持jpg、png格式,建议尺寸200x200像素</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button class="xn-mr8" @click="onClose">关闭</a-button>
|
||||
<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
|
||||
</template>
|
||||
</xn-form-container>
|
||||
</template>
|
||||
|
||||
<script setup name="nlAgvCarForm">
|
||||
import { required } from '@/utils/formRules'
|
||||
import carApi from '@/api/agv/carApi'
|
||||
import fileApi from '@/api/dev/fileApi'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
// 默认是关闭状态
|
||||
const visible = ref(false)
|
||||
const emit = defineEmits({ successful: null })
|
||||
const formRef = ref()
|
||||
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
const submitLoading = ref(false)
|
||||
const fileList = ref([])
|
||||
|
||||
// 打开抽屉
|
||||
const onOpen = (record) => {
|
||||
visible.value = true
|
||||
formData.value = {}
|
||||
fileList.value = []
|
||||
|
||||
if (record) {
|
||||
submitLoading.value = true
|
||||
const param = {
|
||||
carId: record.carId
|
||||
}
|
||||
carApi
|
||||
.detail(param)
|
||||
.then((data) => {
|
||||
formData.value = Object.assign({}, data)
|
||||
// 如果有图片,设置文件列表
|
||||
if (data.icon) {
|
||||
fileList.value = [
|
||||
{
|
||||
uid: '-1',
|
||||
name: 'car-image.png',
|
||||
status: 'done',
|
||||
url: data.icon
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭抽屉
|
||||
const onClose = () => {
|
||||
formRef.value.resetFields()
|
||||
fileList.value = []
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 默认要校验的
|
||||
const formRules = {
|
||||
carId: [required('请输入车辆ID')],
|
||||
type: [required('请输入车辆类型')]
|
||||
}
|
||||
|
||||
// 上传前校验
|
||||
const beforeUpload = (file) => {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
|
||||
if (!isJpgOrPng) {
|
||||
message.error('只能上传 JPG/PNG 格式的图片!')
|
||||
return false
|
||||
}
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
if (!isLt5M) {
|
||||
message.error('图片大小不能超过 5MB!')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 自定义上传
|
||||
const handleUpload = ({ file, onSuccess, onError }) => {
|
||||
const uploadFormData = new FormData()
|
||||
uploadFormData.append('file', file)
|
||||
|
||||
fileApi
|
||||
.fileUploadDynamicReturnUrl(uploadFormData)
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
// 保存文件URL到表单数据
|
||||
formData.value.icon = res
|
||||
message.success('上传成功')
|
||||
onSuccess(res)
|
||||
} else {
|
||||
message.error('上传失败')
|
||||
onError(new Error('上传失败'))
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
message.error('上传失败: ' + error.message)
|
||||
onError(error)
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const handleRemove = () => {
|
||||
formData.value.icon = ''
|
||||
}
|
||||
|
||||
// 验证并提交数据
|
||||
const onSubmit = () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
submitLoading.value = true
|
||||
const apiMethod = formData.value.carId && formData.value.id ? carApi.edit : carApi.save
|
||||
apiMethod(formData.value)
|
||||
.then(() => {
|
||||
message.success('保存成功')
|
||||
onClose()
|
||||
emit('successful')
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
// 调用这个函数将子组件的一些数据和方法暴露出去
|
||||
defineExpose({
|
||||
onOpen
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.form-content {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.image-preview-section {
|
||||
flex: 0 0 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.preview-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
|
||||
.car-image {
|
||||
max-width: 100%;
|
||||
max-height: 400px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-section {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
&.full-width {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.car-uploader {
|
||||
:deep(.ant-upload-select-picture-card) {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
:deep(.ant-upload-list-picture-card-container) {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
149
nl-vue/src/views/nl_agv/car/index.vue
Normal file
149
nl-vue/src/views/nl_agv/car/index.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<a-card :bordered="false" :body-style="{ 'padding-bottom': '0px' }" class="mb-2">
|
||||
<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="6">
|
||||
<a-form-item label="关键词" name="searchKey">
|
||||
<a-input v-model:value="searchFormState.searchKey" placeholder="请输入车辆ID或类型" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-form-item label="车辆类型" name="type">
|
||||
<a-input v-model:value="searchFormState.type" placeholder="请输入车辆类型" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<a-button type="primary" @click="tableRef.refresh(true)">查询</a-button>
|
||||
<a-button class="xn-mg08" @click="reset">重置</a-button>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-card>
|
||||
<a-card :bordered="false">
|
||||
<s-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:alert="options.alert.show"
|
||||
bordered
|
||||
:row-key="(record) => record.carId"
|
||||
:tool-config="toolConfig"
|
||||
:row-selection="options.rowSelection"
|
||||
>
|
||||
<template #operator class="table-operator">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="formRef.onOpen()">
|
||||
<template #icon><plus-outlined /></template>
|
||||
新增车辆
|
||||
</a-button>
|
||||
<xn-batch-button
|
||||
buttonName="批量删除"
|
||||
icon="DeleteOutlined"
|
||||
buttonDanger
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
@batchCallBack="deleteBatchCar"
|
||||
/>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'icon'">
|
||||
<a-image v-if="record.icon" :width="50" :src="record.icon" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-space>
|
||||
<a @click="formRef.onOpen(record)">编辑</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm title="确定要删除此车辆吗?" @confirm="deleteCar(record)">
|
||||
<a-button type="link" danger size="small">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</s-table>
|
||||
</a-card>
|
||||
<Form ref="formRef" @successful="tableRef.refresh(true)" />
|
||||
</template>
|
||||
|
||||
<script setup name="nlAgvCar">
|
||||
import Form from './form.vue'
|
||||
import carApi from '@/api/agv/carApi'
|
||||
|
||||
const searchFormState = ref({})
|
||||
const searchFormRef = ref()
|
||||
const tableRef = ref()
|
||||
const formRef = ref()
|
||||
const toolConfig = { refresh: true, height: true, columnSetting: false, striped: false }
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '车辆ID',
|
||||
dataIndex: 'carId',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '车辆类型',
|
||||
dataIndex: 'type',
|
||||
width: '150px'
|
||||
},
|
||||
{
|
||||
title: '车辆图片',
|
||||
dataIndex: 'icon',
|
||||
width: '120px'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
width: '180px'
|
||||
}
|
||||
]
|
||||
|
||||
let selectedRowKeys = ref([])
|
||||
|
||||
// 列表选择配置
|
||||
const options = {
|
||||
alert: {
|
||||
show: false,
|
||||
clear: () => {
|
||||
selectedRowKeys = ref([])
|
||||
}
|
||||
},
|
||||
rowSelection: {
|
||||
onChange: (selectedRowKey, selectedRows) => {
|
||||
selectedRowKeys.value = selectedRowKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loadData = (parameter) => {
|
||||
return carApi.list(Object.assign(parameter, searchFormState.value)).then((res) => {
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
searchFormRef.value.resetFields()
|
||||
tableRef.value.refresh(true)
|
||||
}
|
||||
|
||||
// 删除
|
||||
const deleteCar = (record) => {
|
||||
let params = [
|
||||
{
|
||||
carId: record.carId
|
||||
}
|
||||
]
|
||||
carApi.delete(params).then(() => {
|
||||
tableRef.value.refresh(true)
|
||||
})
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const deleteBatchCar = (params) => {
|
||||
carApi.delete(params).then(() => {
|
||||
tableRef.value.clearRefreshSelected()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user