合同编辑详情开发

This commit is contained in:
朱昊天
2026-06-02 21:27:44 +08:00
parent 9f4e1c39ad
commit 323da20f2a
19 changed files with 1301 additions and 30 deletions

View File

@@ -29,3 +29,46 @@ export function completeProductionTask(taskId) {
method: 'post'
})
}
export function uncompleteProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/uncomplete',
method: 'post'
})
}
export function startProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/start',
method: 'post'
})
}
export function pauseProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/pause',
method: 'post'
})
}
export function resumeProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId + '/resume',
method: 'post'
})
}
export function updateProductionTask(data) {
return request({
url: '/mes/production/task',
method: 'put',
data
})
}
export function deleteProductionTask(taskId) {
return request({
url: '/mes/production/task/' + taskId,
method: 'delete'
})
}

View File

@@ -0,0 +1,40 @@
import request from '@/utils/request'
export function listContract(query) {
return request({
url: '/oa/contract/list',
method: 'get',
params: query
})
}
export function getContract(contractId) {
return request({
url: '/oa/contract/' + contractId,
method: 'get'
})
}
export function addContract(data) {
return request({
url: '/oa/contract',
method: 'post',
data: data
})
}
export function updateContract(data) {
return request({
url: '/oa/contract',
method: 'put',
data: data
})
}
export function delContract(contractId) {
return request({
url: '/oa/contract/' + contractId,
method: 'delete'
})
}

View File

@@ -49,6 +49,7 @@
<el-form :inline="true" class="filter-form">
<el-form-item label="状态">
<el-select v-model="filters.status" placeholder="全部" clearable style="width: 140px;">
<el-option label="未开始" value="0" />
<el-option label="进行中" value="1" />
<el-option label="已完成" value="2" />
<el-option label="已暂停" value="3" />
@@ -101,7 +102,7 @@
<div class="task-item__meta">
<span v-if="t.planStartTime || t.planEndTime">计划 {{ formatTimeRange(t.planStartTime, t.planEndTime) }}</span>
<span v-if="t.createBy" style="margin-left: 10px;">创建 {{ t.createBy }}</span>
<span v-if="t.updateTime" style="margin-left: 10px;">更新 {{ formatTime(t.updateTime) }}</span>
<span v-if="t.updateTime" style="margin-left: 10px;">状态 {{ statusLabel(t.status) }} {{ formatTime(t.updateTime) }}</span>
</div>
<el-progress :percentage="taskProgressPercent(t)" :stroke-width="8" :show-text="false" />
</div>
@@ -120,15 +121,15 @@
<span class="meta-main">{{ selectedTask.taskName || selectedTask.taskCode || ('任务' + selectedTask.taskId) }}</span>
<el-tag size="small" :type="statusTagType(selectedTask.status)" effect="light" style="margin-left: 8px;">{{ statusLabel(selectedTask.status) }}</el-tag>
</div>
<el-button
v-if="String(selectedTask.status) === '1'"
size="small"
type="primary"
:loading="completeLoading"
@click="completeSelectedTask"
>
完成任务
</el-button>
<div class="task-actions">
<el-button v-if="String(selectedTask.status) === '0'" size="small" type="success" :loading="statusLoading" @click="startSelectedTask">开始</el-button>
<el-button v-if="String(selectedTask.status) === '1'" size="small" type="warning" :loading="statusLoading" @click="pauseSelectedTask">暂停</el-button>
<el-button v-if="String(selectedTask.status) === '3'" size="small" type="success" :loading="statusLoading" @click="resumeSelectedTask">继续</el-button>
<el-button v-if="String(selectedTask.status) !== '2'" size="small" type="primary" :loading="completeLoading" @click="completeSelectedTask">完成</el-button>
<el-button v-if="String(selectedTask.status) === '2'" size="small" type="warning" :loading="statusLoading" @click="uncompleteSelectedTask">撤销完成</el-button>
<el-button v-if="String(selectedTask.status) !== '2'" size="small" @click="openEdit">编辑</el-button>
<el-button size="small" type="danger" :loading="deleteLoading" @click="deleteSelectedTask">删除</el-button>
</div>
</div>
</div>
</template>
@@ -225,8 +226,8 @@
<el-col :span="8">
<el-form-item label="状态" prop="status">
<el-select v-model="addForm.status" placeholder="请选择">
<el-option label="未开始" value="0" />
<el-option label="进行中" value="1" />
<el-option label="已完成" value="2" />
<el-option label="已暂停" value="3" />
</el-select>
</el-form-item>
@@ -288,12 +289,83 @@
<el-button type="primary" :loading="addSaving" @click="submitAdd">保存</el-button>
</template>
</el-dialog>
<el-dialog v-model="editOpen" title="编辑生产任务" width="1100px" top="5vh" append-to-body>
<el-form ref="editFormRef" :model="editForm" :rules="addRules" label-width="100px">
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="任务编号" prop="taskCode">
<el-input v-model="editForm.taskCode" placeholder="可不填" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="editForm.taskName" placeholder="请输入任务名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划开始" prop="planStartTime">
<el-date-picker v-model="editForm.planStartTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划结束" prop="planEndTime">
<el-date-picker v-model="editForm.planEndTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="editForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-divider content-position="left">生产产品明细</el-divider>
<div style="margin-bottom: 8px;">
<el-button type="primary" @click="addEditProductLine">新增产品行</el-button>
</div>
<el-table :data="editProducts" border size="small" :header-cell-style="{ background: '#f5f7fa' }">
<el-table-column label="产品" min-width="220">
<template #default="scope">
<el-select v-model="scope.row.productId" filterable clearable placeholder="请选择" style="width: 100%;" @change="onProductPicked(scope.row)">
<el-option v-for="p in productOptions" :key="p.productId" :label="p.productName" :value="p.productId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="计划数量" width="140" align="right">
<template #default="scope">
<el-input-number v-model="scope.row.planQty" :min="0" :precision="4" controls-position="right" style="width: 120px;" />
</template>
</el-table-column>
<el-table-column label="单位" width="140">
<template #default="scope">
<el-input v-model="scope.row.unit" placeholder="单位" />
</template>
</el-table-column>
<el-table-column label="备注" min-width="200">
<template #default="scope">
<el-input v-model="scope.row.remark" placeholder="备注" />
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template #default="scope">
<el-button type="danger" link @click="removeEditProductLine(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="editOpen = false">取消</el-button>
<el-button type="primary" :loading="editSaving" @click="submitEdit">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup name="Production">
import { computed, onMounted, ref } from 'vue'
import { addProductionTask, completeProductionTask, getProductionTask, listProductionTask } from '@/api/mes/productionTask'
import { addProductionTask, completeProductionTask, deleteProductionTask, getProductionTask, listProductionTask, pauseProductionTask, resumeProductionTask, startProductionTask, uncompleteProductionTask, updateProductionTask } from '@/api/mes/productionTask'
import { listProductBase } from '@/api/mat/product'
import { ElMessage, ElMessageBox } from 'element-plus'
@@ -315,11 +387,13 @@ const filters = ref({
const addOpen = ref(false)
const addSaving = ref(false)
const completeLoading = ref(false)
const statusLoading = ref(false)
const deleteLoading = ref(false)
const addFormRef = ref()
const addForm = ref({
taskCode: '',
taskName: '',
status: '1',
status: '0',
planStartTime: '',
planEndTime: '',
remark: ''
@@ -330,6 +404,18 @@ const addRules = {
const productOptions = ref([])
const addProducts = ref([])
const editOpen = ref(false)
const editSaving = ref(false)
const editFormRef = ref()
const editForm = ref({
taskId: null,
taskCode: '',
taskName: '',
planStartTime: '',
planEndTime: '',
remark: ''
})
const editProducts = ref([])
function toNumber(v) {
const n = Number(v)
@@ -457,6 +543,7 @@ function onCustomRangePicked(v) {
function statusLabel(v) {
const s = String(v || '')
if (s === '0') return '未开始'
if (s === '1') return '进行中'
if (s === '2') return '已完成'
if (s === '3') return '已暂停'
@@ -465,6 +552,7 @@ function statusLabel(v) {
function statusTagType(v) {
const s = String(v || '')
if (s === '0') return 'info'
if (s === '1') return 'success'
if (s === '2') return 'danger'
if (s === '3') return 'warning'
@@ -548,7 +636,7 @@ function openAdd() {
addForm.value = {
taskCode: '',
taskName: '',
status: '1',
status: '0',
planStartTime: '',
planEndTime: '',
remark: ''
@@ -625,6 +713,7 @@ function submitAdd() {
const taskId = res && res.data ? res.data : null
ElMessage.success('已新增')
addOpen.value = false
filters.value.status = ''
return loadTasks().then(() => {
if (taskId != null) {
selectedTaskId.value = taskId
@@ -638,6 +727,75 @@ function submitAdd() {
})
}
function openEdit() {
const taskId = selectedTaskId.value
if (taskId == null) return
ensureProductOptions()
loading.value = true
return getProductionTask(taskId)
.then((res) => {
const data = res && res.data ? res.data : {}
const task = data.task || {}
editForm.value = {
taskId: task.taskId,
taskCode: task.taskCode || '',
taskName: task.taskName || '',
planStartTime: task.planStartTime || '',
planEndTime: task.planEndTime || '',
remark: task.remark || ''
}
const rows = Array.isArray(data.products) ? data.products : []
editProducts.value = rows.map((p) => ({
productId: p.productId,
planQty: p.planQty || 0,
unit: p.unit || '',
remark: p.remark || ''
}))
if (!editProducts.value.length) {
editProducts.value = [{ productId: null, planQty: 0, unit: '', remark: '' }]
}
editOpen.value = true
})
.finally(() => {
loading.value = false
})
}
function addEditProductLine() {
editProducts.value.push({ productId: null, planQty: 0, unit: '', remark: '' })
}
function removeEditProductLine(idx) {
editProducts.value.splice(idx, 1)
}
function submitEdit() {
if (!editFormRef.value) return
editFormRef.value.validate((valid) => {
if (!valid) return
const task = Object.assign({}, editForm.value)
const products = mergeProductLines(editProducts.value).map((p) => ({
productId: p.productId,
planQty: p.planQty || 0,
unit: p.unit || '',
remark: p.remark || ''
}))
editSaving.value = true
updateProductionTask({ task, products })
.then(() => {
ElMessage.success('已保存')
editOpen.value = false
const taskId = selectedTaskId.value
return loadTasks().then(() => {
if (taskId != null) return selectTask(taskId)
})
})
.finally(() => {
editSaving.value = false
})
})
}
function completeSelectedTask() {
const task = selectedTask.value
const taskId = selectedTaskId.value
@@ -664,6 +822,101 @@ function completeSelectedTask() {
})
}
function uncompleteSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return ElMessageBox.confirm('撤销完成后将回到进行中,且回执会清空(再次完成会重新生成),是否继续?', '确认撤销', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => uncompleteProductionTask(taskId))
.then(() => {
ElMessage.success('已撤销完成')
return loadTasks().then(() => selectTask(taskId))
})
.catch((e) => {
const s = String(e || '')
if (s && s !== 'cancel' && s !== 'close') {
ElMessage.error('操作失败')
}
})
.finally(() => {
statusLoading.value = false
})
}
function startSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return startProductionTask(taskId)
.then(() => {
ElMessage.success('已开始')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function pauseSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return pauseProductionTask(taskId)
.then(() => {
ElMessage.success('已暂停')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function resumeSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
statusLoading.value = true
return resumeProductionTask(taskId)
.then(() => {
ElMessage.success('已继续')
return loadTasks().then(() => selectTask(taskId))
})
.finally(() => {
statusLoading.value = false
})
}
function deleteSelectedTask() {
const taskId = selectedTaskId.value
if (taskId == null) return
deleteLoading.value = true
return ElMessageBox.confirm('删除后将不在列表展示,是否继续?', '确认删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => deleteProductionTask(taskId))
.then(() => {
ElMessage.success('已删除')
selectedTaskId.value = null
productRows.value = []
materialRows.value = []
return loadTasks()
})
.catch((e) => {
const s = String(e || '')
if (s && s !== 'cancel' && s !== 'close') {
ElMessage.error('操作失败')
}
})
.finally(() => {
deleteLoading.value = false
})
}
onMounted(() => {
applyDatePreset()
})
@@ -695,6 +948,12 @@ onMounted(() => {
min-width: 0;
}
.task-actions {
display: flex;
align-items: center;
gap: 8px;
}
.card-meta {
display: flex;
align-items: center;

View File

@@ -0,0 +1,284 @@
<template>
<div class="app-container">
<el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="合同号" prop="contractNo">
<el-input v-model="queryParams.contractNo" placeholder="请输入合同号" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="供方" prop="partyA">
<el-input v-model="queryParams.partyA" placeholder="请输入供方" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="需方" prop="partyB">
<el-input v-model="queryParams.partyB" placeholder="请输入需方" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item label="已生效" prop="effectiveFlag">
<el-select v-model="queryParams.effectiveFlag" placeholder="全部" clearable style="width: 140px">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</el-form-item>
<el-form-item label="签订日期">
<el-date-picker
v-model="queryParams.signDateRange"
type="daterange"
range-separator="-"
start-placeholder="开始"
end-placeholder="结束"
value-format="YYYY-MM-DD"
style="width: 260px"
/>
</el-form-item>
<el-form-item label="交货日期">
<el-date-picker
v-model="queryParams.deliveryDateRange"
type="daterange"
range-separator="-"
start-placeholder="开始"
end-placeholder="结束"
value-format="YYYY-MM-DD"
style="width: 260px"
/>
</el-form-item>
<el-form-item label="签订地点" prop="signPlace">
<el-input v-model="queryParams.signPlace" placeholder="请输入签订地点" clearable @keyup.enter="handleQuery" style="width: 200px" />
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button size="small" icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="mb8 toolbar">
<el-button size="small" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
<div class="toolbar-right">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</div>
</div>
<el-table v-loading="loading" :data="contractList">
<el-table-column label="合同号" prop="contractNo" min-width="150">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.contractNo" />
<span v-else>{{ row.contractNo }}</span>
</template>
</el-table-column>
<el-table-column label="供方" prop="partyA" min-width="220">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyA" />
<span v-else>{{ row.partyA }}</span>
</template>
</el-table-column>
<el-table-column label="需方" prop="partyB" min-width="220">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyB" />
<span v-else>{{ row.partyB }}</span>
</template>
</el-table-column>
<el-table-column label="签订日期" prop="signDate" width="140" align="center">
<template #default="{ row }">
<el-date-picker
v-if="isEditing(row)"
v-model="editRow.signDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
style="width: 120px"
/>
<span v-else>{{ formatDate(row.signDate) }}</span>
</template>
</el-table-column>
<el-table-column label="交货日期" prop="deliveryDate" width="140" align="center">
<template #default="{ row }">
<el-date-picker
v-if="isEditing(row)"
v-model="editRow.deliveryDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
style="width: 120px"
/>
<span v-else>{{ formatDate(row.deliveryDate) }}</span>
</template>
</el-table-column>
<el-table-column label="签订地点" prop="signPlace" min-width="160">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.signPlace" />
<span v-else>{{ row.signPlace }}</span>
</template>
</el-table-column>
<el-table-column label="供方地址" prop="partyAAddress" min-width="260" :show-overflow-tooltip="true">
<template #default="{ row }">
<el-input v-if="isEditing(row)" v-model="editRow.partyAAddress" />
<span v-else>{{ row.partyAAddress }}</span>
</template>
</el-table-column>
<el-table-column label="已生效" prop="effectiveFlag" width="100" align="center">
<template #default="{ row }">
<el-select v-if="isEditing(row)" v-model="editRow.effectiveFlag" style="width: 90px">
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
<el-tag v-else :type="row.effectiveFlag === '1' ? 'success' : 'info'" effect="light">{{ row.effectiveFlag === '1' ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="160" align="center" class-name="small-padding fixed-width">
<template #default="{ row }">
<template v-if="isEditing(row)">
<el-button link type="primary" icon="Check" :loading="saving" @click="saveRow">保存</el-button>
<el-button link type="primary" icon="Close" :disabled="saving" @click="cancelEdit">取消</el-button>
</template>
<template v-else>
<el-button link type="primary" icon="Edit" :disabled="editingId !== null" @click="startEdit(row)">修改</el-button>
<el-button link type="primary" icon="Delete" :disabled="editingId !== null" @click="deleteRow(row)">删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</div>
</template>
<script setup name="ContractEdit">
import { getCurrentInstance, onMounted, ref } from 'vue'
import { delContract, listContract, updateContract } from '@/api/oms/contract'
const { proxy } = getCurrentInstance()
const showSearch = ref(true)
const loading = ref(false)
const total = ref(0)
const contractList = ref([])
const queryRef = ref()
const queryParams = ref({
pageNum: 1,
pageSize: 10,
contractNo: '',
partyA: '',
partyB: '',
effectiveFlag: '',
signDateRange: [],
deliveryDateRange: [],
signPlace: ''
})
const editingId = ref(null)
const editRow = ref({})
const saving = ref(false)
function buildQuery() {
const q = { ...queryParams.value }
const signRange = Array.isArray(q.signDateRange) ? q.signDateRange : []
const deliveryRange = Array.isArray(q.deliveryDateRange) ? q.deliveryDateRange : []
delete q.signDateRange
delete q.deliveryDateRange
q.signDateStart = signRange[0] ? `${signRange[0]} 00:00:00` : ''
q.signDateEnd = signRange[1] ? `${signRange[1]} 23:59:59` : ''
q.deliveryDateStart = deliveryRange[0] ? `${deliveryRange[0]} 00:00:00` : ''
q.deliveryDateEnd = deliveryRange[1] ? `${deliveryRange[1]} 23:59:59` : ''
return q
}
function getList() {
loading.value = true
return listContract(buildQuery())
.then((res) => {
contractList.value = res?.rows || []
total.value = res?.total || 0
})
.finally(() => {
loading.value = false
})
}
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
function resetQuery() {
queryRef.value?.resetFields()
queryParams.value.signDateRange = []
queryParams.value.deliveryDateRange = []
handleQuery()
}
function isEditing(row) {
return row && editingId.value != null && String(row.contractId) === String(editingId.value)
}
function startEdit(row) {
editingId.value = row.contractId
editRow.value = {
contractId: row.contractId,
contractNo: row.contractNo || '',
partyA: row.partyA || '',
partyB: row.partyB || '',
effectiveFlag: row.effectiveFlag != null ? String(row.effectiveFlag) : '0',
signDate: row.signDate ? formatDate(row.signDate) : '',
deliveryDate: row.deliveryDate ? formatDate(row.deliveryDate) : '',
signPlace: row.signPlace || '',
partyAAddress: row.partyAAddress || '',
partyBAddress: row.partyBAddress || '',
remark: row.remark || ''
}
}
function cancelEdit() {
editingId.value = null
editRow.value = {}
}
function saveRow() {
if (!editRow.value?.contractId) return
saving.value = true
return updateContract({ ...editRow.value })
.then(() => {
proxy.$modal.msgSuccess('保存成功')
cancelEdit()
return getList()
})
.finally(() => {
saving.value = false
})
}
function deleteRow(row) {
if (!row?.contractId) return
proxy.$modal.confirm('是否确认删除该合同?').then(() => {
return delContract(row.contractId)
}).then(() => {
proxy.$modal.msgSuccess('删除成功')
cancelEdit()
getList()
})
}
function handleExport() {
proxy.download('oa/contract/export', {
...buildQuery()
}, `contract_${new Date().getTime()}.xlsx`)
}
function formatDate(v) {
if (!v) return ''
const d = new Date(v)
if (Number.isNaN(d.getTime())) return ''
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
}
onMounted(() => {
getList()
})
</script>
<style scoped>
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

View File

@@ -500,21 +500,26 @@ function handleAdd() {
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const userId = row.userId || ids.value
// let userId
// if (row && row.userId) {
// userId = row.userId
// } else if (ids.value && ids.value.length > 0) {
// userId = ids.value[0]
// } else {
// return
// }
let userId
if (row && row.userId) {
userId = row.userId
} else if (ids.value && ids.value.length > 0) {
userId = ids.value[0]
} else {
return
}
getUser(userId).then(response => {
form.value = response.data
postOptions.value = response.data.posts
roleOptions.value = response.data.roles
form.value.postIds = response.data.postIds
form.value.roleIds = response.data.roleIds
const data = response && response.data ? response.data : {}
const user = data.user ? data.user : {}
form.value = {
...form.value,
...user,
deptId: user.deptId != null ? Number(user.deptId) : undefined,
postIds: Array.isArray(data.postIds) ? data.postIds.map((v) => Number(v)) : [],
roleIds: Array.isArray(data.roleIds) ? data.roleIds.map((v) => Number(v)) : []
}
postOptions.value = data.posts || []
roleOptions.value = data.roles || []
open.value = true
title.value = "修改用户"
form.value.password = ""