✨ 组织编码/平台公司、合同计费客商角色与基础模块查看按钮
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,6 +38,7 @@ export const createOption = () => ({
|
|||||||
delBtn: false,
|
delBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
|
menuWidth: 320,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -249,6 +249,15 @@ export const option = createCrudOption([
|
|||||||
hide: true,
|
hide: true,
|
||||||
labelWidth: 0,
|
labelWidth: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '客商',
|
||||||
|
prop: 'partyName',
|
||||||
|
search: true,
|
||||||
|
searchOrder: 11,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
hide: true,
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '合同编号',
|
label: '合同编号',
|
||||||
prop: 'contractNo',
|
prop: 'contractNo',
|
||||||
@@ -266,7 +275,7 @@ export const option = createCrudOption([
|
|||||||
align: 'left',
|
align: 'left',
|
||||||
headerAlign: 'left',
|
headerAlign: 'left',
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 7,
|
searchOrder: 1,
|
||||||
searchPlaceholder: '请输入',
|
searchPlaceholder: '请输入',
|
||||||
order: 180,
|
order: 180,
|
||||||
slot: true,
|
slot: true,
|
||||||
@@ -346,7 +355,7 @@ export const option = createCrudOption([
|
|||||||
rules: selectRule('签约类型'),
|
rules: selectRule('签约类型'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '生效类型',
|
label: '合同状态',
|
||||||
prop: 'effectiveType',
|
prop: 'effectiveType',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
search: true,
|
search: true,
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('airport_master_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('airport_master_edit')"
|
v-if="hasPermission('airport_master_edit')"
|
||||||
@@ -279,7 +286,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
|
|||||||
@@ -68,6 +68,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.currency_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.currency_edit"
|
v-if="permission.currency_edit"
|
||||||
@@ -171,7 +178,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
menuFixed: 'right',
|
menuFixed: 'right',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.customer_type_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.customer_type_edit"
|
v-if="permission.customer_type_edit"
|
||||||
@@ -102,7 +109,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '中文名称',
|
label: '中文名称',
|
||||||
|
|||||||
@@ -76,6 +76,13 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.fee_item_view"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="permission.fee_item_edit"
|
v-if="permission.fee_item_edit"
|
||||||
@@ -141,7 +148,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '费用类型',
|
label: '费用类型',
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
v-if="hasPermission('measurement_unit_view')"
|
||||||
|
type="primary"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
v-if="hasPermission('measurement_unit_edit')"
|
v-if="hasPermission('measurement_unit_edit')"
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|||||||
@@ -134,6 +134,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('port_terminal_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('port_terminal_edit')"
|
v-if="hasPermission('port_terminal_edit')"
|
||||||
@@ -370,7 +377,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="hasPermission('railway_station_view')"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="hasPermission('railway_station_edit')"
|
v-if="hasPermission('railway_station_edit')"
|
||||||
@@ -250,7 +257,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
selection: true,
|
selection: true,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
menuWidth: 180,
|
menuWidth: 220,
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
label: '编码',
|
label: '编码',
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
<el-descriptions-item label="运输方式">{{
|
<el-descriptions-item label="运输方式">{{
|
||||||
transportModeLabel(draft.transportMode)
|
transportModeLabel(draft.transportMode)
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="默认方案">{{
|
|
||||||
isDefaultPlan(draft) ? '是' : '否'
|
|
||||||
}}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="备注">{{ displayValue(draft.remark) }}</el-descriptions-item>
|
<el-descriptions-item label="备注">{{ displayValue(draft.remark) }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-form
|
<el-form
|
||||||
@@ -68,16 +65,6 @@
|
|||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value" /></el-select></el-form-item
|
:value="item.value" /></el-select></el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col :span="8"
|
|
||||||
><el-form-item
|
|
||||||
><el-checkbox v-model="draft.defaultPlan" :disabled="readonly">默认方案</el-checkbox
|
|
||||||
><el-tooltip content="同一运输方式仅支持配置一个默认计费方案" placement="top">
|
|
||||||
<el-icon class="billing-plan-editor__default-tip"
|
|
||||||
><InfoFilled
|
|
||||||
/></el-icon> </el-tooltip
|
|
||||||
></el-form-item
|
|
||||||
></el-col
|
|
||||||
>
|
|
||||||
<el-col :span="24"
|
<el-col :span="24"
|
||||||
><el-form-item label="备注"
|
><el-form-item label="备注"
|
||||||
><el-input
|
><el-input
|
||||||
@@ -397,6 +384,7 @@ import { InfoFilled } from '@element-plus/icons-vue';
|
|||||||
import { getDictionary } from '@/api/system/dictbiz';
|
import { getDictionary } from '@/api/system/dictbiz';
|
||||||
import SectionCard from '@/components/section-card/main.vue';
|
import SectionCard from '@/components/section-card/main.vue';
|
||||||
import { currencyUnit } from '@/utils/currency';
|
import { currencyUnit } from '@/utils/currency';
|
||||||
|
// InfoFilled 仅用于保底计费重量列头提示
|
||||||
|
|
||||||
const clone = value => JSON.parse(JSON.stringify(value));
|
const clone = value => JSON.parse(JSON.stringify(value));
|
||||||
/** 计费要素与计量单位维度的对应关系(这些要素可选计费单位) */
|
/** 计费要素与计量单位维度的对应关系(这些要素可选计费单位) */
|
||||||
@@ -535,10 +523,24 @@ export default {
|
|||||||
handler(value) {
|
handler(value) {
|
||||||
if (this.modelValue) {
|
if (this.modelValue) {
|
||||||
this.draft = this.normalizePlan(value);
|
this.draft = this.normalizePlan(value);
|
||||||
|
this.applyDefaultPartySelection();
|
||||||
this.loadRuleItems();
|
this.loadRuleItems();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
modelValue(visible) {
|
||||||
|
if (visible) {
|
||||||
|
this.$nextTick(() => this.applyDefaultPartySelection());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
partyOptions: {
|
||||||
|
deep: true,
|
||||||
|
handler() {
|
||||||
|
if (this.modelValue) {
|
||||||
|
this.applyDefaultPartySelection();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayValue(value) {
|
displayValue(value) {
|
||||||
@@ -558,13 +560,6 @@ export default {
|
|||||||
);
|
);
|
||||||
return this.displayValue(option?.label || this.draft.transportModeLabel || value);
|
return this.displayValue(option?.label || this.draft.transportModeLabel || value);
|
||||||
},
|
},
|
||||||
isDefaultPlan(plan) {
|
|
||||||
return (
|
|
||||||
plan?.defaultPlan === true ||
|
|
||||||
plan?.defaultPlan === 1 ||
|
|
||||||
['true', '1'].includes(String(plan?.defaultPlan).toLowerCase())
|
|
||||||
);
|
|
||||||
},
|
|
||||||
normalizePlan(value = {}) {
|
normalizePlan(value = {}) {
|
||||||
const plan = {
|
const plan = {
|
||||||
planName: '',
|
planName: '',
|
||||||
@@ -574,10 +569,11 @@ export default {
|
|||||||
customerName: '',
|
customerName: '',
|
||||||
transportMode: '',
|
transportMode: '',
|
||||||
transportModeLabel: '',
|
transportModeLabel: '',
|
||||||
defaultPlan: false,
|
|
||||||
remark: '',
|
remark: '',
|
||||||
...clone(value || {}),
|
...clone(value || {}),
|
||||||
};
|
};
|
||||||
|
// 一个客商对应一个方案,不再维护默认方案字段
|
||||||
|
delete plan.defaultPlan;
|
||||||
plan.rules = (value?.rules?.length ? value.rules : [defaultRule()]).map(rule =>
|
plan.rules = (value?.rules?.length ? value.rules : [defaultRule()]).map(rule =>
|
||||||
this.normalizeRule(rule)
|
this.normalizeRule(rule)
|
||||||
);
|
);
|
||||||
@@ -589,6 +585,28 @@ export default {
|
|||||||
);
|
);
|
||||||
return matched?.label || '';
|
return matched?.label || '';
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 仅一个可选客商时默认选中(客户合同仅一个甲方的常见场景)
|
||||||
|
*/
|
||||||
|
applyDefaultPartySelection() {
|
||||||
|
if (this.readonly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = this.partyOptions || [];
|
||||||
|
if (options.length !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const current = String(this.draft.partyRowId || '');
|
||||||
|
const only = options[0];
|
||||||
|
const onlyValue = String(only?.value || only?.partyRowId || '');
|
||||||
|
if (!onlyValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (current && current === onlyValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.handlePartyChange(only.value || only.partyRowId);
|
||||||
|
},
|
||||||
handlePartyChange(partyRowId) {
|
handlePartyChange(partyRowId) {
|
||||||
const matched = (this.partyOptions || []).find(
|
const matched = (this.partyOptions || []).find(
|
||||||
item => String(item.value) === String(partyRowId)
|
item => String(item.value) === String(partyRowId)
|
||||||
|
|||||||
@@ -299,25 +299,27 @@
|
|||||||
><el-radio label="system">系统生成</el-radio
|
><el-radio label="system">系统生成</el-radio
|
||||||
><el-radio label="manual">账单导入生成</el-radio></el-radio-group
|
><el-radio label="manual">账单导入生成</el-radio></el-radio-group
|
||||||
>
|
>
|
||||||
<el-table :data="plans" border class="change-table"
|
<el-table :data="plans" border class="change-table">
|
||||||
><el-table-column type="index" label="序号" width="70" /><el-table-column
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
prop="planName"
|
<el-table-column prop="planName" label="方案名称" min-width="180" />
|
||||||
label="方案名称"
|
<el-table-column label="适用客商" min-width="180">
|
||||||
min-width="220"
|
<template #default="{ row }">
|
||||||
/><el-table-column label="默认方案" min-width="120"
|
{{ row.customerName || billingPlanCustomerLabel(row) || '-' }}
|
||||||
><template #default="{ row }">{{
|
</template>
|
||||||
row.defaultPlan ? '是' : '否'
|
</el-table-column>
|
||||||
}}</template></el-table-column
|
<el-table-column prop="remark" label="备注" min-width="200" />
|
||||||
><el-table-column prop="remark" label="备注" min-width="260" /><el-table-column
|
<el-table-column v-if="!pageReadonly" label="操作" width="180">
|
||||||
v-if="!pageReadonly"
|
<template #default="{ row, $index }">
|
||||||
label="操作"
|
<el-link type="primary" @click="editPlan(row, $index)">编辑</el-link>
|
||||||
width="180"
|
<el-link type="danger" @click="plans.splice($index, 1)">删除</el-link>
|
||||||
><template #default="{ row, $index }"
|
</template>
|
||||||
><el-link type="primary" @click="editPlan(row, $index)">编辑</el-link
|
</el-table-column>
|
||||||
><el-link type="danger" @click="plans.splice($index, 1)">删除</el-link></template
|
<el-table-column v-else label="操作" width="100">
|
||||||
></el-table-column
|
<template #default="{ row, $index }">
|
||||||
></el-table
|
<el-link type="primary" @click="editPlan(row, $index)">查看</el-link>
|
||||||
>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="change-section">
|
<section class="change-section">
|
||||||
@@ -491,7 +493,9 @@
|
|||||||
v-model="planDialogVisible"
|
v-model="planDialogVisible"
|
||||||
:value="planEditor"
|
:value="planEditor"
|
||||||
:index="planEditorIndex"
|
:index="planEditorIndex"
|
||||||
|
:readonly="pageReadonly"
|
||||||
:settlement-currency="form.settlementCurrency"
|
:settlement-currency="form.settlementCurrency"
|
||||||
|
:party-options="billingPartyOptions"
|
||||||
@save="savePlan"
|
@save="savePlan"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -630,6 +634,45 @@ const normalizeCustomPeriods = (periods = []) =>
|
|||||||
endDay: Number(item?.endDay) > 0 ? Number(item.endDay) : '',
|
endDay: Number(item?.endDay) > 0 ? Number(item.endDay) : '',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const createPartyRow = (row = {}) => ({
|
||||||
|
id: row.id || `${Date.now()}${Math.floor(Math.random() * 1000)}`,
|
||||||
|
customerId: row.customerId || '',
|
||||||
|
customerName: row.customerName || '',
|
||||||
|
creditCode: row.creditCode || row.unifiedCreditCode || '',
|
||||||
|
contactId: row.contactId || '',
|
||||||
|
contactName: row.contactName || '',
|
||||||
|
contactPhone: row.contactPhone || '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const partyRoleLabel = role => {
|
||||||
|
if (role === 'A') return '甲方';
|
||||||
|
if (role === 'B') return '乙方';
|
||||||
|
if (role === 'C') return '丙方';
|
||||||
|
return role || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizePartyRows = (partyJson, fallbackName, requireOne) => {
|
||||||
|
const rows = (() => {
|
||||||
|
if (Array.isArray(partyJson)) return partyJson;
|
||||||
|
if (!partyJson) return [];
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(partyJson);
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})().map(item => createPartyRow(item));
|
||||||
|
if (rows.length) return rows;
|
||||||
|
if (fallbackName) {
|
||||||
|
return String(fallbackName)
|
||||||
|
.split(/[、,]/)
|
||||||
|
.map(name => name.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(name => createPartyRow({ customerName: name }));
|
||||||
|
}
|
||||||
|
return requireOne ? [createPartyRow()] : [];
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { BillingPlanEditor, ContractAttachmentSection, ElImageViewer, OpenFileViewer },
|
components: { BillingPlanEditor, ContractAttachmentSection, ElImageViewer, OpenFileViewer },
|
||||||
data() {
|
data() {
|
||||||
@@ -637,6 +680,9 @@ export default {
|
|||||||
form: {},
|
form: {},
|
||||||
period: [],
|
period: [],
|
||||||
plans: [],
|
plans: [],
|
||||||
|
partyARows: [],
|
||||||
|
partyBRows: [],
|
||||||
|
partyCRows: [],
|
||||||
attachments: [],
|
attachments: [],
|
||||||
contractFiles: [],
|
contractFiles: [],
|
||||||
contractFileRows: [],
|
contractFileRows: [],
|
||||||
@@ -675,7 +721,7 @@ export default {
|
|||||||
settlementModeDictOptions: [],
|
settlementModeDictOptions: [],
|
||||||
contractFormatDictOptions: [],
|
contractFormatDictOptions: [],
|
||||||
planDialogVisible: false,
|
planDialogVisible: false,
|
||||||
planEditor: { planName: '', defaultPlan: false, remark: '', rules: [] },
|
planEditor: { planName: '', remark: '', rules: [] },
|
||||||
planEditorIndex: -1,
|
planEditorIndex: -1,
|
||||||
billingElements: [
|
billingElements: [
|
||||||
'按重量',
|
'按重量',
|
||||||
@@ -756,6 +802,29 @@ export default {
|
|||||||
isSettlementRuleChange() {
|
isSettlementRuleChange() {
|
||||||
return this.form.changeType === '结算规则变更';
|
return this.form.changeType === '结算规则变更';
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 计费方案适用客商:客户合同仅甲方;承运商合同仅乙方、丙方
|
||||||
|
*/
|
||||||
|
billingPartyOptions() {
|
||||||
|
const category = String(this.form.contractCategory || '').trim();
|
||||||
|
const allowedRoles =
|
||||||
|
category === '承运商合同' ? ['B', 'C'] : category === '客户合同' ? ['A'] : ['A', 'B', 'C'];
|
||||||
|
return [
|
||||||
|
...this.partyARows.map(row => ({ ...row, partyRole: 'A' })),
|
||||||
|
...this.partyBRows.map(row => ({ ...row, partyRole: 'B' })),
|
||||||
|
...this.partyCRows.map(row => ({ ...row, partyRole: 'C' })),
|
||||||
|
]
|
||||||
|
.filter(row => allowedRoles.includes(row.partyRole))
|
||||||
|
.filter(row => row.customerName || row.customerId)
|
||||||
|
.map(row => ({
|
||||||
|
value: row.id,
|
||||||
|
label: `${partyRoleLabel(row.partyRole)}-${row.customerName || row.customerId}`,
|
||||||
|
partyRole: row.partyRole,
|
||||||
|
partyRowId: row.id,
|
||||||
|
customerId: row.customerId,
|
||||||
|
customerName: row.customerName,
|
||||||
|
}));
|
||||||
|
},
|
||||||
changeAttachmentLocationOptions() {
|
changeAttachmentLocationOptions() {
|
||||||
if (this.isSettlementRuleChange) {
|
if (this.isSettlementRuleChange) {
|
||||||
return ['变更材料'];
|
return ['变更材料'];
|
||||||
@@ -890,6 +959,9 @@ export default {
|
|||||||
};
|
};
|
||||||
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
||||||
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
||||||
|
this.partyARows = normalizePartyRows(data.partyAJson, data.partyA, true);
|
||||||
|
this.partyBRows = normalizePartyRows(data.partyBJson, data.partyB, true);
|
||||||
|
this.partyCRows = normalizePartyRows(data.partyCJson, data.partyC, false);
|
||||||
this.plans = this.parse(data.billingPlanJson);
|
this.plans = this.parse(data.billingPlanJson);
|
||||||
this.attachments = this.mergeChangeAttachments(
|
this.attachments = this.mergeChangeAttachments(
|
||||||
this.parse(data.attachmentsJson),
|
this.parse(data.attachmentsJson),
|
||||||
@@ -1048,10 +1120,32 @@ export default {
|
|||||||
.replace(/\D/g, '')
|
.replace(/\D/g, '')
|
||||||
.replace(/^0+/, '');
|
.replace(/^0+/, '');
|
||||||
},
|
},
|
||||||
addPlan() { this.planEditorIndex = -1; this.planEditor = { planName: `计费方案${this.plans.length + 1}`, defaultPlan: !this.plans.length, remark: '', rules: [{}] }; this.planDialogVisible = true; },
|
addPlan() {
|
||||||
editPlan(row, index) { this.planEditorIndex = index; this.planEditor = JSON.parse(JSON.stringify(row)); this.planDialogVisible = true; },
|
this.planEditorIndex = -1;
|
||||||
toggleDefaultPlan(value) { if (value) this.plans.forEach(item => { item.defaultPlan = false; }); },
|
this.planEditor = {
|
||||||
savePlan(value, index) { if (index < 0) this.plans.push(value); else this.plans.splice(index, 1, value); if (value.defaultPlan) this.plans.forEach((item, current) => { if (current !== (index < 0 ? this.plans.length - 1 : index)) item.defaultPlan = false; }); },
|
planName: `计费方案${this.plans.length + 1}`,
|
||||||
|
remark: '',
|
||||||
|
rules: [{}],
|
||||||
|
};
|
||||||
|
this.planDialogVisible = true;
|
||||||
|
},
|
||||||
|
editPlan(row, index) {
|
||||||
|
this.planEditorIndex = index;
|
||||||
|
this.planEditor = JSON.parse(JSON.stringify(row));
|
||||||
|
this.planDialogVisible = true;
|
||||||
|
},
|
||||||
|
billingPlanCustomerLabel(row) {
|
||||||
|
const matched = this.billingPartyOptions.find(
|
||||||
|
item => String(item.partyRowId) === String(row.partyRowId)
|
||||||
|
);
|
||||||
|
return matched?.label || row.customerName || '';
|
||||||
|
},
|
||||||
|
savePlan(value, index) {
|
||||||
|
const nextPlan = { ...value };
|
||||||
|
delete nextPlan.defaultPlan;
|
||||||
|
if (index < 0) this.plans.push(nextPlan);
|
||||||
|
else this.plans.splice(index, 1, nextPlan);
|
||||||
|
},
|
||||||
handleSettlementTypeChange(value) { if (value !== '月结') { this.settlementRule.billCycleType = ''; this.settlementRule.billCutoffDay = ''; this.settlementRule.customPeriods = []; } else if (this.settlementRule.billCycleType === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; if (value !== '固定天数周期结算') this.settlementRule.cycleDays = ''; },
|
handleSettlementTypeChange(value) { if (value !== '月结') { this.settlementRule.billCycleType = ''; this.settlementRule.billCutoffDay = ''; this.settlementRule.customPeriods = []; } else if (this.settlementRule.billCycleType === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; if (value !== '固定天数周期结算') this.settlementRule.cycleDays = ''; },
|
||||||
handleCycleTypeChange(value) { if (value !== '固定截单日') this.settlementRule.billCutoffDay = ''; if (value === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; },
|
handleCycleTypeChange(value) { if (value !== '固定截单日') this.settlementRule.billCutoffDay = ''; if (value === '自定义多周期') this.settlementRule.customPeriods = normalizeCustomPeriods(this.settlementRule.customPeriods || []); else this.settlementRule.customPeriods = []; },
|
||||||
attachmentUrl(row = {}) { return row.url || row.link || row.fileUrl || row.downloadUrl || row.domain || ''; },
|
attachmentUrl(row = {}) { return row.url || row.link || row.fileUrl || row.downloadUrl || row.domain || ''; },
|
||||||
|
|||||||
@@ -1685,12 +1685,21 @@ export default {
|
|||||||
{ role: 'C', label: '丙方', rows: this.partyCRows },
|
{ role: 'C', label: '丙方', rows: this.partyCRows },
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 计费方案适用客商:
|
||||||
|
* - 客户合同:仅甲方(仅 1 个甲方时编辑器自动选中)
|
||||||
|
* - 承运商合同:仅乙方、丙方(应付明细按这些方案生成)
|
||||||
|
*/
|
||||||
billingPartyOptions() {
|
billingPartyOptions() {
|
||||||
|
const category = String(this.form.contractCategory || '').trim();
|
||||||
|
const allowedRoles =
|
||||||
|
category === '承运商合同' ? ['B', 'C'] : category === '客户合同' ? ['A'] : ['A', 'B', 'C'];
|
||||||
return [
|
return [
|
||||||
...this.partyARows.map(row => ({ ...row, partyRole: 'A' })),
|
...this.partyARows.map(row => ({ ...row, partyRole: 'A' })),
|
||||||
...this.partyBRows.map(row => ({ ...row, partyRole: 'B' })),
|
...this.partyBRows.map(row => ({ ...row, partyRole: 'B' })),
|
||||||
...this.partyCRows.map(row => ({ ...row, partyRole: 'C' })),
|
...this.partyCRows.map(row => ({ ...row, partyRole: 'C' })),
|
||||||
]
|
]
|
||||||
|
.filter(row => allowedRoles.includes(row.partyRole))
|
||||||
.filter(row => row.customerName || row.customerId)
|
.filter(row => row.customerName || row.customerId)
|
||||||
.map(row => ({
|
.map(row => ({
|
||||||
value: row.id,
|
value: row.id,
|
||||||
@@ -2315,7 +2324,6 @@ export default {
|
|||||||
if (!this.validatePartyRows(true)) return false;
|
if (!this.validatePartyRows(true)) return false;
|
||||||
return (
|
return (
|
||||||
this.validateBillingPlanBindings() &&
|
this.validateBillingPlanBindings() &&
|
||||||
this.validateBillingPlanDefault() &&
|
|
||||||
this.validateSettlementRules() &&
|
this.validateSettlementRules() &&
|
||||||
this.validatePaymentRatios()
|
this.validatePaymentRatios()
|
||||||
);
|
);
|
||||||
@@ -2911,10 +2919,17 @@ export default {
|
|||||||
validateBillingPlanBindings() {
|
validateBillingPlanBindings() {
|
||||||
if (!this.billingPlanRows.length) return true;
|
if (!this.billingPlanRows.length) return true;
|
||||||
const partyIds = new Set(this.billingPartyOptions.map(item => String(item.partyRowId)));
|
const partyIds = new Set(this.billingPartyOptions.map(item => String(item.partyRowId)));
|
||||||
|
const category = String(this.form.contractCategory || '').trim();
|
||||||
|
const roleHint =
|
||||||
|
category === '承运商合同'
|
||||||
|
? '请选择乙方或丙方客商'
|
||||||
|
: category === '客户合同'
|
||||||
|
? '请选择甲方客商'
|
||||||
|
: '请选择适用客商';
|
||||||
for (let index = 0; index < this.billingPlanRows.length; index += 1) {
|
for (let index = 0; index < this.billingPlanRows.length; index += 1) {
|
||||||
const plan = this.billingPlanRows[index];
|
const plan = this.billingPlanRows[index];
|
||||||
if (!plan.partyRowId || !partyIds.has(String(plan.partyRowId))) {
|
if (!plan.partyRowId || !partyIds.has(String(plan.partyRowId))) {
|
||||||
this.$message.warning(`计费方案第${index + 1}个请选择适用客商`);
|
this.$message.warning(`计费方案第${index + 1}个${roleHint}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3169,21 +3184,13 @@ export default {
|
|||||||
openBillingPlan(row = {}, index = -1) {
|
openBillingPlan(row = {}, index = -1) {
|
||||||
this.billingPlanIndex = index;
|
this.billingPlanIndex = index;
|
||||||
this.billingPlanForm =
|
this.billingPlanForm =
|
||||||
index < 0
|
index < 0 ? { planName: '', transportMode: '', remark: '', rules: [] } : clone(row);
|
||||||
? { planName: '', transportMode: '', defaultPlan: false, remark: '', rules: [] }
|
|
||||||
: clone(row);
|
|
||||||
this.billingPlanBox = true;
|
this.billingPlanBox = true;
|
||||||
this.$nextTick(() => this.$refs.billingPlanEditor?.ensureTransportModes?.());
|
this.$nextTick(() => this.$refs.billingPlanEditor?.ensureTransportModes?.());
|
||||||
},
|
},
|
||||||
saveBillingPlan(plan, index) {
|
saveBillingPlan(plan, index) {
|
||||||
const nextPlan = clone(plan);
|
const nextPlan = clone(plan);
|
||||||
if (this.isDefaultBillingPlan(nextPlan)) {
|
delete nextPlan.defaultPlan;
|
||||||
this.billingPlanRows.forEach((item, itemIndex) => {
|
|
||||||
if (itemIndex !== index && item.transportMode === nextPlan.transportMode) {
|
|
||||||
item.defaultPlan = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (index < 0) this.billingPlanRows.push(nextPlan);
|
if (index < 0) this.billingPlanRows.push(nextPlan);
|
||||||
else this.billingPlanRows.splice(index, 1, nextPlan);
|
else this.billingPlanRows.splice(index, 1, nextPlan);
|
||||||
this.billingPlanBox = false;
|
this.billingPlanBox = false;
|
||||||
@@ -3193,31 +3200,6 @@ export default {
|
|||||||
this.billingPlanRows.splice(index, 1);
|
this.billingPlanRows.splice(index, 1);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isDefaultBillingPlan(plan) {
|
|
||||||
return (
|
|
||||||
plan?.defaultPlan === true ||
|
|
||||||
plan?.defaultPlan === 1 ||
|
|
||||||
['true', '1'].includes(String(plan?.defaultPlan).toLowerCase())
|
|
||||||
);
|
|
||||||
},
|
|
||||||
validateBillingPlanDefault() {
|
|
||||||
if (!this.billingPlanRows.length) return true;
|
|
||||||
const defaultCountByTransportMode = this.billingPlanRows.reduce((result, plan) => {
|
|
||||||
const transportMode = plan.transportMode || '';
|
|
||||||
result[transportMode] =
|
|
||||||
(result[transportMode] || 0) + Number(this.isDefaultBillingPlan(plan));
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
const invalidTransportMode = Object.entries(defaultCountByTransportMode).find(
|
|
||||||
([, count]) => count > 1
|
|
||||||
);
|
|
||||||
if (invalidTransportMode) {
|
|
||||||
const [transportMode, count] = invalidTransportMode;
|
|
||||||
this.$message.warning(`运输方式“${transportMode}”仅支持配置一个默认计费方案`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
isFixedCycleSettlementType(value) {
|
isFixedCycleSettlementType(value) {
|
||||||
return value === '按固定天数周期' || value === '固定天数周期结算';
|
return value === '按固定天数周期' || value === '固定天数周期结算';
|
||||||
},
|
},
|
||||||
@@ -3551,8 +3533,7 @@ export default {
|
|||||||
return list
|
return list
|
||||||
.map(item => {
|
.map(item => {
|
||||||
if (!item || typeof item !== 'object') return String(item ?? '');
|
if (!item || typeof item !== 'object') return String(item ?? '');
|
||||||
const name = item.planName || item.name || '未命名方案';
|
return item.planName || item.name || '未命名方案';
|
||||||
return item.defaultPlan ? `${name}(默认)` : name;
|
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('、');
|
.join('、');
|
||||||
|
|||||||
@@ -761,6 +761,96 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<template v-if="showProjectContractSection">
|
||||||
|
<div class="dialog-section-title project-apply-form__table-title">项目合同</div>
|
||||||
|
<el-table
|
||||||
|
v-loading="projectContractLoading"
|
||||||
|
:data="projectContractRows"
|
||||||
|
border
|
||||||
|
class="project-apply-form__table"
|
||||||
|
>
|
||||||
|
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||||
|
<el-table-column
|
||||||
|
prop="contractCategory"
|
||||||
|
label="合同类型"
|
||||||
|
min-width="120"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="contractNo"
|
||||||
|
label="合同编号"
|
||||||
|
min-width="140"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-link
|
||||||
|
v-if="row.id && row.contractNo"
|
||||||
|
type="primary"
|
||||||
|
@click.stop="openProjectContractDetail(row)"
|
||||||
|
>
|
||||||
|
{{ row.contractNo }}
|
||||||
|
</el-link>
|
||||||
|
<span v-else>{{ row.contractNo || '' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="contractName"
|
||||||
|
label="合同名称"
|
||||||
|
min-width="160"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="partyA"
|
||||||
|
label="甲方"
|
||||||
|
min-width="140"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="partyB"
|
||||||
|
label="乙方"
|
||||||
|
min-width="140"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="partyC"
|
||||||
|
label="丙方"
|
||||||
|
min-width="140"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="startDate"
|
||||||
|
label="开始日期"
|
||||||
|
min-width="120"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="endDate"
|
||||||
|
label="结束日期"
|
||||||
|
min-width="120"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="contractAmount"
|
||||||
|
label="合同金额"
|
||||||
|
min-width="120"
|
||||||
|
align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ formatAmount(row.contractAmount) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="!isChangeDialog && !isNewProjectDialog"
|
v-if="!isChangeDialog && !isNewProjectDialog"
|
||||||
class="dialog-section-title project-apply-form__table-title"
|
class="dialog-section-title project-apply-form__table-title"
|
||||||
@@ -990,6 +1080,7 @@
|
|||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent } from 'vue';
|
||||||
import * as api from '@/api/business/project-apply';
|
import * as api from '@/api/business/project-apply';
|
||||||
|
import { getList as getContractManageList } from '@/api/business/contract-manage';
|
||||||
import {
|
import {
|
||||||
loadHcsImmediateEnabled,
|
loadHcsImmediateEnabled,
|
||||||
repush as hcsRepush,
|
repush as hcsRepush,
|
||||||
@@ -1387,6 +1478,8 @@ export default {
|
|||||||
'zip',
|
'zip',
|
||||||
],
|
],
|
||||||
changeRows: [],
|
changeRows: [],
|
||||||
|
projectContractRows: [],
|
||||||
|
projectContractLoading: false,
|
||||||
changeRecordDetailVisible: false,
|
changeRecordDetailVisible: false,
|
||||||
changeRecordDetail: null,
|
changeRecordDetail: null,
|
||||||
changeRecordDetailRows: [],
|
changeRecordDetailRows: [],
|
||||||
@@ -1463,6 +1556,9 @@ export default {
|
|||||||
isNewProjectDialog() {
|
isNewProjectDialog() {
|
||||||
return ['add', 'majorSupplement'].includes(this.dialogType);
|
return ['add', 'majorSupplement'].includes(this.dialogType);
|
||||||
},
|
},
|
||||||
|
showProjectContractSection() {
|
||||||
|
return this.dialogReadonly && !this.isChangeDialog && !this.isNewProjectDialog && !this.isPublicViewPage;
|
||||||
|
},
|
||||||
isProjectFormPage() {
|
isProjectFormPage() {
|
||||||
return this.isFormPageInstance;
|
return this.isFormPageInstance;
|
||||||
},
|
},
|
||||||
@@ -2111,6 +2207,8 @@ export default {
|
|||||||
this.attachmentRows = [];
|
this.attachmentRows = [];
|
||||||
this.selectedAttachmentRows = [];
|
this.selectedAttachmentRows = [];
|
||||||
this.changeRows = [];
|
this.changeRows = [];
|
||||||
|
this.projectContractRows = [];
|
||||||
|
this.projectContractLoading = false;
|
||||||
this.selectedCustomerId = [];
|
this.selectedCustomerId = [];
|
||||||
this.selectedCarrierIds = [];
|
this.selectedCarrierIds = [];
|
||||||
},
|
},
|
||||||
@@ -2159,6 +2257,40 @@ export default {
|
|||||||
this.syncSelectedCustomerOptions();
|
this.syncSelectedCustomerOptions();
|
||||||
this.ensureCurrentPlatformOption();
|
this.ensureCurrentPlatformOption();
|
||||||
this.ensureCurrentBusinessDeptOption();
|
this.ensureCurrentBusinessDeptOption();
|
||||||
|
this.loadProjectContracts(row?.id);
|
||||||
|
},
|
||||||
|
loadProjectContracts(projectId) {
|
||||||
|
if (!this.showProjectContractSection || !projectId) {
|
||||||
|
this.projectContractRows = [];
|
||||||
|
this.projectContractLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.projectContractLoading = true;
|
||||||
|
getContractManageList(1, 1000, { projectId })
|
||||||
|
.then(res => {
|
||||||
|
const data = res.data?.data;
|
||||||
|
const records = Array.isArray(data) ? data : data?.records || [];
|
||||||
|
this.projectContractRows = records.filter(
|
||||||
|
item => String(item.projectId) === String(projectId)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.projectContractRows = [];
|
||||||
|
this.$message.error('项目合同加载失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.projectContractLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openProjectContractDetail(row) {
|
||||||
|
if (!row?.id) {
|
||||||
|
this.$message.warning('合同信息不完整,无法跳转');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: '/business/contract-manage/detail',
|
||||||
|
query: { id: row.id, name: '合同详情' },
|
||||||
|
});
|
||||||
},
|
},
|
||||||
fillDefaultUsers() {
|
fillDefaultUsers() {
|
||||||
const userId = this.userInfo?.userId || this.userInfo?.id || '';
|
const userId = this.userInfo?.userId || this.userInfo?.id || '';
|
||||||
|
|||||||
@@ -20,6 +20,13 @@
|
|||||||
@on-load="onLoad"
|
@on-load="onLoad"
|
||||||
>
|
>
|
||||||
<template #menu="{ row, index }">
|
<template #menu="{ row, index }">
|
||||||
|
<el-link
|
||||||
|
v-if="permission.business_dept_config_view"
|
||||||
|
type="primary"
|
||||||
|
@click="$refs.crud.rowView(row, index)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
v-if="permission.business_dept_config_edit"
|
v-if="permission.business_dept_config_edit"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -117,7 +124,7 @@ export default {
|
|||||||
editBtn: false,
|
editBtn: false,
|
||||||
delBtn: false,
|
delBtn: false,
|
||||||
viewBtn: false,
|
viewBtn: false,
|
||||||
menuWidth: 140,
|
menuWidth: 220,
|
||||||
dialogWidth: 900,
|
dialogWidth: 900,
|
||||||
dialogClickModal: false,
|
dialogClickModal: false,
|
||||||
labelPosition: 'right',
|
labelPosition: 'right',
|
||||||
|
|||||||
+44
-105
@@ -203,7 +203,6 @@ import { mapGetters } from 'vuex';
|
|||||||
import website from '@/config/website';
|
import website from '@/config/website';
|
||||||
import func from '@/utils/func';
|
import func from '@/utils/func';
|
||||||
|
|
||||||
const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
||||||
/**
|
/**
|
||||||
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
||||||
@@ -323,7 +322,7 @@ export default {
|
|||||||
{
|
{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
const deptCode = String(value || '').trim();
|
const deptCode = String(value || '').trim();
|
||||||
// 组织编码非必填,为空直接通过
|
// 组织编码非必填,为空直接通过;不再校验 GWWL/上级编码+三位数字格式
|
||||||
if (!deptCode) {
|
if (!deptCode) {
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
@@ -332,34 +331,6 @@ export default {
|
|||||||
callback(new Error('组织编码不能超过30个字符'));
|
callback(new Error('组织编码不能超过30个字符'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const parentId = this.normalizeParentId(this.form?.parentId);
|
|
||||||
// 顶级组织不选择上级时,编码不依赖上级编码
|
|
||||||
if (!parentId) {
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.parentDept || String(this.parentDept.id) !== String(parentId)) {
|
|
||||||
this.loadParentDeptCode(parentId);
|
|
||||||
callback(new Error('正在加载上级组织编码,请稍后重试'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.parentDeptCode) {
|
|
||||||
callback(new Error('上级组织未配置组织编码,请先完善上级组织编码'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 公司:GWWL+三位数字;部门:所属公司编码+三位数字;其他:上级编码+三位数字(中间不加-)
|
|
||||||
let expectedPrefix = this.parentDeptCode;
|
|
||||||
const category = Number(this.form?.deptCategory);
|
|
||||||
if (category === 2) {
|
|
||||||
expectedPrefix = 'GWWL';
|
|
||||||
} else if (category === 3 && this.form?.belongCompanyCode) {
|
|
||||||
expectedPrefix = String(this.form.belongCompanyCode).trim();
|
|
||||||
}
|
|
||||||
const pattern = new RegExp(`^${escapeRegExp(expectedPrefix)}\\d{3}$`);
|
|
||||||
if (!pattern.test(deptCode)) {
|
|
||||||
callback(new Error(`组织编码格式应为:${expectedPrefix}三位数字(不足补零,中间不加-)`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
@@ -431,50 +402,22 @@ export default {
|
|||||||
{ label: '是', value: 1 },
|
{ label: '是', value: 1 },
|
||||||
],
|
],
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
value: 0,
|
|
||||||
width: 120,
|
width: 120,
|
||||||
order: 36,
|
order: 36,
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
searchPlaceholder: '请选择是否平台公司',
|
searchPlaceholder: '请选择是否平台公司',
|
||||||
formatter: row => (Number(row.isPlatformCompany) === 1 ? '是' : '否'),
|
formatter: row => (Number(row.isPlatformCompany) === 1 ? '是' : '否'),
|
||||||
change: ({ value }) => this.handlePlatformCompanyChange(value),
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择是否平台公司',
|
|
||||||
trigger: 'change',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '金蝶部门代码',
|
|
||||||
prop: 'kingdeeDeptCode',
|
|
||||||
minWidth: 140,
|
|
||||||
order: 35,
|
|
||||||
maxlength: 64,
|
|
||||||
showWordLimit: true,
|
|
||||||
// 仅平台公司维护/展示金蝶组织代码;非平台公司列表留空
|
|
||||||
addDisplay: false,
|
|
||||||
editDisplay: false,
|
|
||||||
viewDisplay: false,
|
|
||||||
formatter: row =>
|
|
||||||
Number(row.isPlatformCompany) === 1 ? String(row.kingdeeDeptCode || '').trim() : '',
|
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
const code = String(value || '').trim();
|
if (value === undefined || value === null || value === '') {
|
||||||
if (!code) {
|
callback(new Error('请选择是否平台公司'));
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (code.length > 64) {
|
|
||||||
callback(new Error('金蝶部门代码不能超过64个字符'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
},
|
},
|
||||||
trigger: 'blur',
|
trigger: 'change',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -487,7 +430,6 @@ export default {
|
|||||||
{ label: '是', value: 1 },
|
{ label: '是', value: 1 },
|
||||||
],
|
],
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
value: 0,
|
|
||||||
width: 120,
|
width: 120,
|
||||||
order: 34,
|
order: 34,
|
||||||
search: true,
|
search: true,
|
||||||
@@ -496,8 +438,14 @@ export default {
|
|||||||
formatter: row => (Number(row.isBusinessDept) === 1 ? '是' : '否'),
|
formatter: row => (Number(row.isBusinessDept) === 1 ? '是' : '否'),
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
validator: (rule, value, callback) => {
|
||||||
message: '请选择是否业务部门',
|
// 不能用 required:true:值为 0(否)时会被当成空
|
||||||
|
if (value === undefined || value === null || value === '') {
|
||||||
|
callback(new Error('请选择是否业务部门'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
trigger: 'change',
|
trigger: 'change',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -988,6 +936,7 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* 提交前将组织类型规范为 Integer;空状态/排序字段去掉,避免 "" 反序列化失败。
|
* 提交前将组织类型规范为 Integer;空状态/排序字段去掉,避免 "" 反序列化失败。
|
||||||
* 排序为空时由后端默认填充 1。
|
* 排序为空时由后端默认填充 1。
|
||||||
|
* 是否平台公司 / 是否业务部门强制规范为数字 0/1,避免下拉值类型导致漏更新。
|
||||||
*/
|
*/
|
||||||
prepareDeptSubmitRow(row) {
|
prepareDeptSubmitRow(row) {
|
||||||
const category = this.resolveDeptCategoryValue(row.deptCategory);
|
const category = this.resolveDeptCategoryValue(row.deptCategory);
|
||||||
@@ -995,6 +944,8 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
row.deptCategory = category;
|
row.deptCategory = category;
|
||||||
|
row.isPlatformCompany = Number(row.isPlatformCompany) === 1 ? 1 : 0;
|
||||||
|
row.isBusinessDept = Number(row.isBusinessDept) === 1 ? 1 : 0;
|
||||||
if (row.status === '' || row.status === null || row.status === undefined) {
|
if (row.status === '' || row.status === null || row.status === undefined) {
|
||||||
delete row.status;
|
delete row.status;
|
||||||
} else {
|
} else {
|
||||||
@@ -1007,6 +958,9 @@ export default {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
normalizeYesNoFlag(value) {
|
||||||
|
return Number(value) === 1 ? 1 : 0;
|
||||||
|
},
|
||||||
resolveDeptCategoryValue(value) {
|
resolveDeptCategoryValue(value) {
|
||||||
if (value === null || value === undefined || value === '') {
|
if (value === null || value === undefined || value === '') {
|
||||||
this.$message.warning('请选择组织类型');
|
this.$message.warning('请选择组织类型');
|
||||||
@@ -1163,21 +1117,6 @@ export default {
|
|||||||
row.parentId = 0;
|
row.parentId = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handlePlatformCompanyChange(value) {
|
|
||||||
const isPlatform = Number(value) === 1;
|
|
||||||
this.syncKingdeeDeptCodeDisplay(isPlatform);
|
|
||||||
if (!isPlatform && this.form) {
|
|
||||||
this.form.kingdeeDeptCode = '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
syncKingdeeDeptCodeDisplay(isPlatformCompany) {
|
|
||||||
const column = this.findColumn(this.option.column, 'kingdeeDeptCode');
|
|
||||||
if (!column) return;
|
|
||||||
const visible = Number(isPlatformCompany) === 1;
|
|
||||||
column.addDisplay = visible;
|
|
||||||
column.editDisplay = visible;
|
|
||||||
column.viewDisplay = visible;
|
|
||||||
},
|
|
||||||
isRootDept(row) {
|
isRootDept(row) {
|
||||||
return row && (row.parentId === 0 || String(row.parentId) === '0');
|
return row && (row.parentId === 0 || String(row.parentId) === '0');
|
||||||
},
|
},
|
||||||
@@ -1322,9 +1261,6 @@ export default {
|
|||||||
rowSave(row, done, loading) {
|
rowSave(row, done, loading) {
|
||||||
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
row.deptCode = String(row.deptCode || '').trim();
|
row.deptCode = String(row.deptCode || '').trim();
|
||||||
// 合同前缀/流水已迁至业务部门配置;组织管理仅维护平台公司金蝶代码
|
|
||||||
row.kingdeeDeptCode =
|
|
||||||
Number(row.isPlatformCompany) === 1 ? String(row.kingdeeDeptCode || '').trim() : '';
|
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
this.normalizeTopParent(row);
|
this.normalizeTopParent(row);
|
||||||
if (!this.prepareDeptSubmitRow(row)) {
|
if (!this.prepareDeptSubmitRow(row)) {
|
||||||
@@ -1370,9 +1306,6 @@ export default {
|
|||||||
rowUpdate(row, index, done, loading) {
|
rowUpdate(row, index, done, loading) {
|
||||||
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
row.deptCode = String(row.deptCode || '').trim();
|
row.deptCode = String(row.deptCode || '').trim();
|
||||||
// 合同前缀/流水已迁至业务部门配置;组织管理仅维护平台公司金蝶代码
|
|
||||||
row.kingdeeDeptCode =
|
|
||||||
Number(row.isPlatformCompany) === 1 ? String(row.kingdeeDeptCode || '').trim() : '';
|
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
this.normalizeTopParent(row);
|
this.normalizeTopParent(row);
|
||||||
if (!this.prepareDeptSubmitRow(row)) {
|
if (!this.prepareDeptSubmitRow(row)) {
|
||||||
@@ -1479,34 +1412,40 @@ export default {
|
|||||||
beforeOpen(done, type) {
|
beforeOpen(done, type) {
|
||||||
if (type === 'add') {
|
if (type === 'add') {
|
||||||
this.form.tenantId = this.form.tenantId || this.userInfo.tenantId || website.tenantId;
|
this.form.tenantId = this.form.tenantId || this.userInfo.tenantId || website.tenantId;
|
||||||
if (this.form.isPlatformCompany === undefined || this.form.isPlatformCompany === null) {
|
this.form.isPlatformCompany = this.normalizeYesNoFlag(this.form.isPlatformCompany);
|
||||||
this.form.isPlatformCompany = 0;
|
this.form.isBusinessDept = this.normalizeYesNoFlag(this.form.isBusinessDept);
|
||||||
}
|
|
||||||
if (this.form.isBusinessDept === undefined || this.form.isBusinessDept === null) {
|
|
||||||
this.form.isBusinessDept = 0;
|
|
||||||
}
|
|
||||||
this.syncKingdeeDeptCodeDisplay(this.form.isPlatformCompany);
|
|
||||||
this.initData(this.form.tenantId);
|
this.initData(this.form.tenantId);
|
||||||
this.loadParentDeptCode(this.form.parentId);
|
this.loadParentDeptCode(this.form.parentId);
|
||||||
|
done();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (type === 'edit') {
|
if (type === 'edit') {
|
||||||
this.initData(this.form.tenantId || this.userInfo.tenantId || website.tenantId);
|
this.initData(this.form.tenantId || this.userInfo.tenantId || website.tenantId);
|
||||||
}
|
}
|
||||||
if (['edit', 'view'].includes(type)) {
|
if (['edit', 'view'].includes(type)) {
|
||||||
getDept(this.form.id).then(res => {
|
// 等详情返回后再打开弹窗,避免异步回填覆盖用户已改值;就地赋值保持 Avue 表单引用
|
||||||
this.form = Object.assign(res.data.data, {
|
getDept(this.form.id)
|
||||||
hasChildren: this.form.hasChildren,
|
.then(res => {
|
||||||
|
const detail = res.data.data || {};
|
||||||
|
Object.assign(this.form, detail, {
|
||||||
|
hasChildren: this.form.hasChildren,
|
||||||
|
isPlatformCompany: this.normalizeYesNoFlag(detail.isPlatformCompany),
|
||||||
|
isBusinessDept: this.normalizeYesNoFlag(detail.isBusinessDept),
|
||||||
|
});
|
||||||
|
if (this.form.parentId === '0') {
|
||||||
|
this.form.parentId = '';
|
||||||
|
}
|
||||||
|
this.loadParentDeptCode(this.form.parentId);
|
||||||
|
if (Object.prototype.hasOwnProperty.call(this.form, 'leaderId')) {
|
||||||
|
const splitResult = func.split(this.form.leaderId);
|
||||||
|
this.form.leaderId = Array.isArray(splitResult) ? splitResult : [];
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
if (this.form.parentId === '0') {
|
return;
|
||||||
this.form.parentId = '';
|
|
||||||
}
|
|
||||||
this.syncKingdeeDeptCodeDisplay(this.form.isPlatformCompany);
|
|
||||||
this.loadParentDeptCode(this.form.parentId);
|
|
||||||
if (this.form.hasOwnProperty('leaderId')) {
|
|
||||||
const splitResult = func.split(this.form.leaderId);
|
|
||||||
this.form.leaderId = Array.isArray(splitResult) ? splitResult : [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user