fix:修复了一点点问题,目前点击用户详情的话已有的角色会显示了,然后修复了角色启用和禁用的状态表示做反了,合同中新增了合同类别

This commit is contained in:
Maple 2025-08-15 10:07:36 +08:00
parent 66d4a1bbfe
commit c5c7aeaa61
8 changed files with 172 additions and 26 deletions

View File

@ -18,6 +18,10 @@
<a-descriptions-item label="合同金额"> <a-descriptions-item label="合同金额">
<span class="font-medium text-green-600">{{ (contractDetail.amount || 0).toLocaleString() }}</span> <span class="font-medium text-green-600">{{ (contractDetail.amount || 0).toLocaleString() }}</span>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="合同类别">
{{ contractDetail.category || '-' }}
</a-descriptions-item>
<a-descriptions-item label="已收款金额"> <a-descriptions-item label="已收款金额">
<span class="font-medium text-blue-600">{{ (contractDetail.receivedAmount || 0).toLocaleString() }}</span> <span class="font-medium text-blue-600">{{ (contractDetail.receivedAmount || 0).toLocaleString() }}</span>
</a-descriptions-item> </a-descriptions-item>
@ -74,6 +78,7 @@ interface ContractDetail {
code: string code: string
projectId: string projectId: string
type: string type: string
category?: string
productService: string productService: string
paymentDate: string | null paymentDate: string | null
performanceDeadline: string | null performanceDeadline: string | null

View File

@ -46,6 +46,21 @@
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item field="category" label="合同类别">
<a-select v-model="contractData.category" placeholder="请选择合同类别" allow-clear>
<a-option value="框架协议">框架协议</a-option>
<a-option value="单次合同">单次合同</a-option>
<a-option value="三年长协">三年长协</a-option>
<a-option value="两年长协">两年长协</a-option>
<a-option value="派工单">派工单</a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="12"> <a-col :span="12">
<a-form-item field="signDate" label="签订日期"> <a-form-item field="signDate" label="签订日期">

View File

@ -135,6 +135,7 @@ interface ContractItem {
code: string code: string
projectId: string projectId: string
type: string type: string
category?: string
productService: string productService: string
paymentDate: string | null paymentDate: string | null
performanceDeadline: string | null performanceDeadline: string | null
@ -165,6 +166,7 @@ const searchForm = reactive({
contractCode: '', contractCode: '',
client: '', client: '',
status: '', status: '',
category: '',
signDateRange: [] as [string, string] | [], signDateRange: [] as [string, string] | [],
page: 1, page: 1,
size: 10, size: 10,
@ -196,6 +198,21 @@ const queryFormColumns = [
], ],
}, },
}, },
{
field: 'category',
label: '合同类别',
type: 'select' as const,
props: {
placeholder: '请选择合同类别',
options: [
{ label: '框架协议', value: '框架协议' },
{ label: '单次合同', value: '单次合同' },
{ label: '三年长协', value: '三年长协' },
{ label: '两年长协', value: '两年长协' },
{ label: '派工单', value: '派工单' }
]
}
},
{ {
field: 'signDateRange', field: 'signDateRange',
label: '签署时间', label: '签署时间',
@ -218,6 +235,7 @@ const tableColumns: TableColumnData[] = [
{ title: '签署日期', dataIndex: 'signDate', slotName: 'signDate', width: 120 }, { title: '签署日期', dataIndex: 'signDate', slotName: 'signDate', width: 120 },
{ title: '履约期限', dataIndex: 'performanceDeadline', slotName: 'performanceDeadline', width: 120 }, { title: '履约期限', dataIndex: 'performanceDeadline', slotName: 'performanceDeadline', width: 120 },
{ title: '付款日期', dataIndex: 'paymentDate', slotName: 'paymentDate', width: 120 }, { title: '付款日期', dataIndex: 'paymentDate', slotName: 'paymentDate', width: 120 },
{ title: '合同类别', dataIndex: 'category', width: 120 },
{ title: '合同状态', dataIndex: 'contractStatus', slotName: 'status', width: 100 }, { title: '合同状态', dataIndex: 'contractStatus', slotName: 'status', width: 100 },
{ title: '销售人员', dataIndex: 'salespersonName', width: 100 }, { title: '销售人员', dataIndex: 'salespersonName', width: 100 },
{ title: '销售部门', dataIndex: 'salespersonDeptName', width: 100 }, { title: '销售部门', dataIndex: 'salespersonDeptName', width: 100 },
@ -239,6 +257,7 @@ const fetchContractList = async () => {
code: searchForm.contractCode, code: searchForm.contractCode,
customer: searchForm.client, customer: searchForm.client,
contractStatus: searchForm.status, contractStatus: searchForm.status,
category: (searchForm as any).category || undefined,
signDateStart: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[0] : undefined, signDateStart: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[0] : undefined,
signDateEnd: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[1] : undefined, signDateEnd: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[1] : undefined,
} }
@ -325,6 +344,8 @@ const reset = () => {
status: '', status: '',
signDateRange: [], signDateRange: [],
page: 1, page: 1,
category: '',
size: 10, size: 10,
}) })
pagination.current = 1 pagination.current = 1
@ -354,6 +375,7 @@ const newContractData = ref<ContractItem>({
code: '', code: '',
projectId: '', projectId: '',
type: '支出合同', type: '支出合同',
category: '',
productService: '', productService: '',
paymentDate: null, paymentDate: null,
performanceDeadline: null, performanceDeadline: null,
@ -387,6 +409,7 @@ const openAddModal = () => {
code: '', code: '',
projectId: '', projectId: '',
type: '支出合同', type: '支出合同',
category: '',
productService: '', productService: '',
paymentDate: null, paymentDate: null,
performanceDeadline: null, performanceDeadline: null,
@ -444,6 +467,7 @@ const handleAddSubmit = async () => {
salespersonId: (newContractData.value as any).salespersonId || '', salespersonId: (newContractData.value as any).salespersonId || '',
signDate: newContractData.value.signDate || null, signDate: newContractData.value.signDate || null,
type: newContractData.value.type || '支出合同', type: newContractData.value.type || '支出合同',
category: newContractData.value.category || '',
} }
// ID // ID
@ -535,6 +559,7 @@ const handleEditSubmit = async () => {
productService: editedContractData.value.productService || '', productService: editedContractData.value.productService || '',
projectId: editedContractData.value.projectId || '', projectId: editedContractData.value.projectId || '',
salespersonId: editedContractData.value.salespersonId || '', salespersonId: editedContractData.value.salespersonId || '',
category: editedContractData.value.category || '',
signDate: editedContractData.value.signDate || null, signDate: editedContractData.value.signDate || null,
type: editedContractData.value.type || '', type: editedContractData.value.type || '',
}; };

View File

@ -18,6 +18,10 @@
<a-descriptions-item label="合同金额"> <a-descriptions-item label="合同金额">
<span class="font-medium text-green-600">{{ (contractDetail.amount || 0).toLocaleString() }}</span> <span class="font-medium text-green-600">{{ (contractDetail.amount || 0).toLocaleString() }}</span>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="合同类别">
{{ contractDetail.category || '-' }}
</a-descriptions-item>
<a-descriptions-item label="已收款金额"> <a-descriptions-item label="已收款金额">
<span class="font-medium text-blue-600">{{ (contractDetail.receivedAmount || 0).toLocaleString() }}</span> <span class="font-medium text-blue-600">{{ (contractDetail.receivedAmount || 0).toLocaleString() }}</span>
</a-descriptions-item> </a-descriptions-item>
@ -74,6 +78,7 @@ interface ContractDetail {
code: string code: string
projectId: string projectId: string
type: string type: string
category?: string
productService: string productService: string
paymentDate: string | null paymentDate: string | null
performanceDeadline: string | null performanceDeadline: string | null

View File

@ -46,6 +46,20 @@
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item field="category" label="合同类别">
<a-select v-model="contractData.category" placeholder="请选择合同类别" allow-clear>
<a-option value="框架协议">框架协议</a-option>
<a-option value="单次合同">单次合同</a-option>
<a-option value="三年长协">三年长协</a-option>
<a-option value="两年长协">两年长协</a-option>
<a-option value="派工单">派工单</a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :span="12"> <a-col :span="12">
<a-form-item field="signDate" label="签订日期"> <a-form-item field="signDate" label="签订日期">

View File

@ -136,6 +136,7 @@ interface ContractItem {
code: string code: string
projectId: string projectId: string
type: string type: string
category?: string
productService: string productService: string
paymentDate: string | null paymentDate: string | null
performanceDeadline: string | null performanceDeadline: string | null
@ -166,6 +167,7 @@ const searchForm = reactive({
contractCode: '', contractCode: '',
client: '', client: '',
status: '', status: '',
category: '',
signDateRange: [] as [string, string] | [], signDateRange: [] as [string, string] | [],
page: 1, page: 1,
size: 10, size: 10,
@ -186,6 +188,17 @@ const queryFormColumns = [
], ],
}, },
}, },
{ field: 'category', label: '合同类别', type: 'select' as const, props: {
placeholder: '请选择合同类别',
options: [
{ label: '框架协议', value: '框架协议' },
{ label: '单次合同', value: '单次合同' },
{ label: '三年长协', value: '三年长协' },
{ label: '两年长协', value: '两年长协' },
{ label: '派工单', value: '派工单' },
],
}
},
{ field: 'signDateRange', label: '签署时间', type: 'range-picker' as const, props: { { field: 'signDateRange', label: '签署时间', type: 'range-picker' as const, props: {
placeholder: ['开始日期', '结束日期'], format: 'YYYY-MM-DD', placeholder: ['开始日期', '结束日期'], format: 'YYYY-MM-DD',
} }
@ -198,6 +211,7 @@ const tableColumns: TableColumnData[] = [
{ title: '项目名称', dataIndex: 'projectName', width: 250, ellipsis: true, tooltip: true }, { title: '项目名称', dataIndex: 'projectName', width: 250, ellipsis: true, tooltip: true },
{ title: '客户名称', dataIndex: 'customer', width: 200, ellipsis: true, tooltip: true }, { title: '客户名称', dataIndex: 'customer', width: 200, ellipsis: true, tooltip: true },
{ title: '合同金额', dataIndex: 'amount', slotName: 'contractAmount', width: 120 }, { title: '合同金额', dataIndex: 'amount', slotName: 'contractAmount', width: 120 },
{ title: '合同类别', dataIndex: 'category', width: 120 },
{ title: '已收款金额', dataIndex: 'receivedAmount', slotName: 'receivedAmount', width: 120 }, { title: '已收款金额', dataIndex: 'receivedAmount', slotName: 'receivedAmount', width: 120 },
{ title: '未收款金额', dataIndex: 'pendingAmount', width: 120 }, { title: '未收款金额', dataIndex: 'pendingAmount', width: 120 },
{ title: '签署日期', dataIndex: 'signDate', slotName: 'signDate', width: 120 }, { title: '签署日期', dataIndex: 'signDate', slotName: 'signDate', width: 120 },
@ -312,6 +326,9 @@ const fetchContractList = async () => {
pageSize: searchForm.size, pageSize: searchForm.size,
code: searchForm.contractCode, code: searchForm.contractCode,
customer: searchForm.client, customer: searchForm.client,
category: (searchForm as any).category || undefined,
contractStatus: searchForm.status, contractStatus: searchForm.status,
signDateStart: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[0] : undefined, signDateStart: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[0] : undefined,
signDateEnd: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[1] : undefined, signDateEnd: Array.isArray(searchForm.signDateRange) && searchForm.signDateRange.length === 2 ? searchForm.signDateRange[1] : undefined,
@ -393,6 +410,7 @@ const reset = () => {
contractCode: '', contractCode: '',
client: '', client: '',
status: '', status: '',
category: '',
signDateRange: [], signDateRange: [],
page: 1, page: 1,
size: 10, size: 10,
@ -421,6 +439,7 @@ const showAddModal = ref(false)
const newContractData = ref<ContractItem>({ const newContractData = ref<ContractItem>({
contractId: '', customer: '', code: '', projectId: '', type: '收入合同', contractId: '', customer: '', code: '', projectId: '', type: '收入合同',
productService: '', paymentDate: null, performanceDeadline: null, productService: '', paymentDate: null, performanceDeadline: null,
category: '',
paymentAddress: '', amount: 0, accountNumber: '', notes: '', paymentAddress: '', amount: 0, accountNumber: '', notes: '',
contractStatus: '未执行', contractText: '', projectName: '', contractStatus: '未执行', contractText: '', projectName: '',
salespersonName: null, salespersonDeptName: '', settlementAmount: null, salespersonName: null, salespersonDeptName: '', settlementAmount: null,
@ -432,6 +451,7 @@ const openAddModal = () => {
Object.assign(newContractData.value, { Object.assign(newContractData.value, {
contractId: '', customer: '', code: '', projectId: '', type: '收入合同', contractId: '', customer: '', code: '', projectId: '', type: '收入合同',
productService: '', paymentDate: null, performanceDeadline: null, productService: '', paymentDate: null, performanceDeadline: null,
category: '',
paymentAddress: '', amount: 0, accountNumber: '', notes: '', paymentAddress: '', amount: 0, accountNumber: '', notes: '',
contractStatus: '未执行', contractText: '', projectName: '', contractStatus: '未执行', contractText: '', projectName: '',
salespersonName: null, salespersonDeptName: '', settlementAmount: null, salespersonName: null, salespersonDeptName: '', settlementAmount: null,
@ -464,6 +484,7 @@ const handleAddSubmit = async () => {
// projectId // projectId
projectName: newContractData.value.projectName || '', projectName: newContractData.value.projectName || '',
salespersonId: (newContractData.value as any).salespersonId || '', salespersonId: (newContractData.value as any).salespersonId || '',
category: newContractData.value.category || '',
signDate: newContractData.value.signDate || null, signDate: newContractData.value.signDate || null,
type: newContractData.value.type || '收入合同', type: newContractData.value.type || '收入合同',
} }
@ -534,6 +555,7 @@ const handleEditSubmit = async () => {
productService: editedContractData.value.productService || '', productService: editedContractData.value.productService || '',
projectId: editedContractData.value.projectId || '', projectId: editedContractData.value.projectId || '',
salespersonId: editedContractData.value.salespersonId || '', salespersonId: editedContractData.value.salespersonId || '',
category: editedContractData.value.category || '',
signDate: editedContractData.value.signDate || null, signDate: editedContractData.value.signDate || null,
type: editedContractData.value.type || '', type: editedContractData.value.type || '',
}; };

View File

@ -22,8 +22,8 @@
</a-form-item> </a-form-item>
<a-form-item label="状态" field="status"> <a-form-item label="状态" field="status">
<a-select v-model="form.status" placeholder="请选择状态"> <a-select v-model="form.status" placeholder="请选择状态">
<a-option :value="0" label="正常" /> <a-option :value="1" label="正常" />
<a-option :value="1" label="停用" /> <a-option :value="0" label="停用" />
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item label="描述" field="remark"> <a-form-item label="描述" field="remark">

View File

@ -15,6 +15,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Message, type TreeNodeData } from '@arco-design/web-vue' import { Message, type TreeNodeData } from '@arco-design/web-vue'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
import { nextTick } from 'vue'
import { addUserNew, getUserDetailNew, updateUserNew } from '@/apis/system/user-new' import { addUserNew, getUserDetailNew, updateUserNew } from '@/apis/system/user-new'
import { type ColumnItem, GiForm } from '@/components/GiForm' import { type ColumnItem, GiForm } from '@/components/GiForm'
import type { Status } from '@/types/global' import type { Status } from '@/types/global'
@ -186,7 +187,7 @@ const columns: ColumnItem[] = reactive([
field: 'roleIds', field: 'roleIds',
type: 'select', type: 'select',
span: 12, span: 12,
required: true, //required: true,
props: { props: {
options: roleList, options: roleList,
multiple: true, multiple: true,
@ -347,15 +348,12 @@ const save = async () => {
// //
const onAdd = async () => { const onAdd = async () => {
reset() reset()
if (!deptList.value.length) { // v-model
await getDeptList() await Promise.all([
} deptList.value.length ? Promise.resolve() : getDeptList(),
if (!roleList.value.length) { roleList.value.length ? Promise.resolve() : getRoleList(),
await getRoleList() postList.value.length ? Promise.resolve() : getPostList(),
} ])
if (!postList.value.length) {
await getPostList()
}
dataId.value = '' dataId.value = ''
visible.value = true visible.value = true
} }
@ -365,29 +363,91 @@ const onUpdate = async (id: string) => {
try { try {
reset() reset()
dataId.value = id dataId.value = id
if (!deptList.value.length) { // //
await getDeptList() await Promise.all([
} deptList.value.length ? Promise.resolve() : getDeptList(),
if (!roleList.value.length) { roleList.value.length ? Promise.resolve() : getRoleList(),
await getRoleList() postList.value.length ? Promise.resolve() : getPostList(),
} ])
if (!postList.value.length) {
await getPostList()
}
// 使API // 使API
const { data } = await getUserDetailNew(id) const { data } = await getUserDetailNew(id)
if (!data) { if (!data) {
return Message.error('获取用户详情失败') return Message.error('获取用户详情失败')
} }
// API // API
Object.keys(form).forEach(key => { Object.keys(form).forEach(key => {
if (data[key] !== undefined) { if ((data as any)[key] !== undefined) {
form[key] = data[key] ;(form as any)[key] = (data as any)[key]
} }
}) })
// / ID
const normalizeIdArray = (val: any): string[] => {
if (Array.isArray(val)) return val.map(v => String(v))
if (typeof val === 'string') return val.split(',').map(s => s.trim()).filter(Boolean)
return []
}
//
form.deptId = data.deptId ? String(data.deptId) : ''
//
if ((data as any).postIds !== undefined) {
form.postIds = normalizeIdArray((data as any).postIds)
}
// roleIds / roles / roleIdList
const roleIdsFromArray = normalizeIdArray((data as any).roleIds)
const roleIdsFromRoles = Array.isArray((data as any).roles)
? (data as any).roles.map((r: any) => String(r.roleId ?? r.id ?? r.role_id)).filter(Boolean)
: []
const roleIdsFromList = normalizeIdArray((data as any).roleIdList)
let mergedRoleIds = roleIdsFromArray.length
? roleIdsFromArray
: (roleIdsFromRoles.length ? roleIdsFromRoles : roleIdsFromList)
// IDID
if (!mergedRoleIds.length) {
const namesStr = (data as any).roleName || (data as any).roleNames
const roleNames: string[] = Array.isArray(namesStr)
? (namesStr as any[]).map(n => String(n))
: (typeof namesStr === 'string' ? namesStr.split(/,|/).map(s => s.trim()).filter(Boolean) : [])
if (roleNames.length && Array.isArray(roleList.value)) {
const labelToId = new Map<string, string>((roleList.value || []).map(opt => [String(opt.label), String(opt.value)]))
const ids = roleNames.map(n => labelToId.get(n)).filter((v): v is string => !!v)
if (ids.length) mergedRoleIds = ids
}
}
form.roleIds = mergedRoleIds
//
try {
const optionValSet = new Set((roleList.value || []).map(o => String(o.value)))
const fromRolesMap = new Map<string, string>()
if (Array.isArray((data as any).roles)) {
;(data as any).roles.forEach((r: any) => {
const id = String(r.roleId ?? r.id ?? r.role_id)
const name = r.roleName ?? r.name ?? r.role_key ?? id
if (id) fromRolesMap.set(id, String(name))
})
}
const toAppend: any[] = []
mergedRoleIds.forEach(id => {
const sId = String(id)
if (!optionValSet.has(sId)) {
toAppend.push({ label: fromRolesMap.get(sId) || sId, value: sId, disabled: false })
}
})
if (toAppend.length) {
//
roleList.value = [...(roleList.value || []), ...toAppend]
}
} catch (_) {}
visible.value = true visible.value = true
} catch (error) { } catch (error) {
console.error('获取用户详情失败', error) console.error('获取用户详情失败', error)