Merge remote-tracking branch 'websoft/master'
# Conflicts: # src/views/settlement/receivable-payable-detail.vue
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
# 2026-08-31
|
||||||
|
|
||||||
|
## 客商档案「所属组织」改为单选级联(customer-archive.vue)
|
||||||
|
- 表单区 `el-tree-select`(多选勾选树)→ `el-cascader` 单选级联;`deptCascaderProps` 开 `checkStrictly: true`,可任意层级选中(不必选到叶子)。
|
||||||
|
- 引入 computed `deptCascaderValue`(get/set)做「部门 ID ↔ 根到节点路径」双向转换:
|
||||||
|
- `archiveForm.deptId` 仍为选中部门 ID 数组(单选只一个),后端字段 `deptIds` 逗号串 / `deptName` 不变,保存逻辑 `normalizeArchive` 无需改。
|
||||||
|
- getter 依赖 `deptTree`,部门树异步加载完成后详情回显自动刷新(解决 created 里 initDeptTree 与 openArchive 并发的时序问题)。
|
||||||
|
- `onDeptChange(path)` 改为取路径末级 → 写 `deptId / deptIds / deptName`;新增 `findDeptPath(id)`、`findDeptLabel(id)` 递归查找。
|
||||||
|
- `normalizeDeptIds(detail)` 单选只取第一个 ID(历史多选数据自动收敛)。
|
||||||
|
- 列表搜索区 `renderDeptSearch` 同步改为 `h(ElCascader, ...)`(import 从 ElTreeSelect 换 ElCascader),`searchChange` 取路径末级 ID 转部门名称。
|
||||||
|
</content>
|
||||||
|
</invoke>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { getDeptTree } from '@/api/system/dept';
|
import { getDeptTree } from '@/api/system/dept';
|
||||||
import { ElTreeSelect } from 'element-plus';
|
import { ElCascader } from 'element-plus';
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所属组织 统一搜索 mixin
|
* 所属组织 统一搜索 mixin
|
||||||
* ------------------------------------------------------------------
|
* ------------------------------------------------------------------
|
||||||
* 全站「所属组织」搜索栏统一为树形下拉(el-tree-select),风格与客户档案
|
* 全站「所属组织」搜索栏统一为级联选择器(el-cascader,单选),风格与客商档案
|
||||||
* (vehicle/customer-archive.vue)保持一致。
|
* (vehicle/customer-archive.vue)保持一致。
|
||||||
*
|
*
|
||||||
* 接入步骤(在使用了 avue-crud 的页面中):
|
* 接入步骤(在使用了 avue-crud 的页面中):
|
||||||
@@ -15,24 +15,40 @@ import { h } from 'vue';
|
|||||||
*
|
*
|
||||||
* 说明:
|
* 说明:
|
||||||
* - 自动识别 organizationName / deptName 两种 prop,并挂载 column.renderSearch
|
* - 自动识别 organizationName / deptName 两种 prop,并挂载 column.renderSearch
|
||||||
* - 树节点标识统一用 id(node-key='id'),返回值为部门 id
|
* - 树节点标识统一用 id,级联值为「根 → 选中节点」的 id 路径数组
|
||||||
|
* - checkStrictly 打开,任意层级(含非末级)都可直接选中
|
||||||
* - 页面若已有 excludeExternalOrganization / normalizeOrgTree 等方法,
|
* - 页面若已有 excludeExternalOrganization / normalizeOrgTree 等方法,
|
||||||
* 组件自身方法优先级更高,会覆盖本 mixin 的默认实现
|
* 组件自身方法优先级更高,会覆盖本 mixin 的默认实现
|
||||||
* - 搜索值(id)需在各自的 searchChange / normalizeSearch 中按后端要求
|
* - 搜索值需在各自的 searchChange / normalizeSearch 中按后端要求转换为部门名称:
|
||||||
* 转换为部门名称(参考 contract-manage 的 normalizeSearch)
|
* 级联值是路径数组,统一用 findOrgById(路径)?.rawLabel 取末级名称
|
||||||
|
* - 表单区(新增/编辑)需要回显时,可用 findOrgPath(deptId) 把 id 转成路径,
|
||||||
|
* 参考 customer-archive 的 deptCascaderValue 计算属性
|
||||||
*/
|
*/
|
||||||
const ORG_PROPS = ['organizationName', 'deptName'];
|
const ORG_PROPS = ['organizationName', 'deptName'];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 树形组织数据,仅供搜索栏 el-tree-select 使用;
|
// 树形组织数据,仅供搜索栏 el-cascader 使用;
|
||||||
// 与页面自身 organizationOptions(多为表单扁平列表)隔离,避免相互覆盖
|
// 与页面自身 organizationOptions(多为表单扁平列表)隔离,避免相互覆盖
|
||||||
organizationTreeOptions: [],
|
organizationTreeOptions: [],
|
||||||
organizationTreeFlatOptions: [],
|
organizationTreeFlatOptions: [],
|
||||||
organizationLoading: false,
|
organizationLoading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
// 所属组织级联配置:checkStrictly 允许选中任意层级,不必选到末级
|
||||||
|
organizationCascaderProps() {
|
||||||
|
return {
|
||||||
|
value: 'id',
|
||||||
|
label: 'label',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadOrganizationOptions() {
|
loadOrganizationOptions() {
|
||||||
if (this.organizationLoading) return;
|
if (this.organizationLoading) return;
|
||||||
@@ -90,25 +106,67 @@ export default {
|
|||||||
...this.flattenOrgTree(item.children || []),
|
...this.flattenOrgTree(item.children || []),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
// 兼容两种入参:级联路径数组(取末级)或单个部门 id
|
||||||
findOrgById(id) {
|
findOrgById(id) {
|
||||||
const value = Array.isArray(id) ? id.at(-1) : id;
|
const value = Array.isArray(id) ? id.at(-1) : id;
|
||||||
return this.organizationTreeFlatOptions.find(item => String(item.id) === String(value));
|
return this.organizationTreeFlatOptions.find(item => String(item.id) === String(value));
|
||||||
},
|
},
|
||||||
renderOrganizationSearch(scope, prop = 'organizationName') {
|
// 由部门 id 反查「根 → 该节点」的 id 路径,供级联回显(找不到返回 null)
|
||||||
return h(ElTreeSelect, {
|
findOrgPath(id, tree = this.organizationTreeOptions, parents = []) {
|
||||||
modelValue: scope.row?.[prop] || '',
|
const target = Array.isArray(id) ? id.at(-1) : id;
|
||||||
'onUpdate:modelValue': value => {
|
if (target === undefined || target === null || target === '') return null;
|
||||||
if (scope.row) scope.row[prop] = value;
|
for (const node of tree || []) {
|
||||||
|
const path = [...parents, String(node.id)];
|
||||||
|
if (String(node.id) === String(target)) return path;
|
||||||
|
const matched = this.findOrgPath(target, node.children, path);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
// 由部门 id 取组织名称(末级),供表单提交
|
||||||
|
findOrgName(id) {
|
||||||
|
return this.findOrgById(id)?.rawLabel || '';
|
||||||
|
},
|
||||||
|
// 组织名称 → 级联路径(表单回显用;部门树异步加载完成后会自动重算)
|
||||||
|
resolveOrgPath(name) {
|
||||||
|
const value = String(name ?? '').trim();
|
||||||
|
if (!value) return [];
|
||||||
|
const node = this.organizationTreeFlatOptions.find(item => item.rawLabel === value);
|
||||||
|
return node ? this.findOrgPath(node.id) || [] : [];
|
||||||
|
},
|
||||||
|
// 级联路径 → 组织名称(表单/搜索提交用,取末级节点名称)
|
||||||
|
resolveOrgName(path) {
|
||||||
|
const value = Array.isArray(path)
|
||||||
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: [];
|
||||||
|
return value.length ? this.findOrgById(value)?.rawLabel || '' : '';
|
||||||
|
},
|
||||||
|
// 搜索提交前把级联路径数组就地转成组织名称(后端按名称过滤)
|
||||||
|
normalizeOrganizationSearch(params, prop = 'organizationName') {
|
||||||
|
if (Array.isArray(params?.[prop])) {
|
||||||
|
params[prop] = this.resolveOrgName(params[prop]);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
},
|
||||||
|
renderOrganizationSearch(scope, prop = 'organizationName') {
|
||||||
|
return h(ElCascader, {
|
||||||
|
modelValue: Array.isArray(scope.row?.[prop]) ? scope.row[prop] : [],
|
||||||
|
'onUpdate:modelValue': value => {
|
||||||
|
// 级联单选:modelValue 必须是 id 路径数组,否则控件内部状态会错乱导致无法再次选中
|
||||||
|
if (scope.row) scope.row[prop] = Array.isArray(value) ? value : [];
|
||||||
|
},
|
||||||
|
options: this.organizationTreeOptions,
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'id',
|
||||||
|
children: 'children',
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
},
|
},
|
||||||
data: this.organizationTreeOptions,
|
|
||||||
'node-key': 'id',
|
|
||||||
'check-strictly': true,
|
|
||||||
filterable: true,
|
filterable: true,
|
||||||
clearable: true,
|
clearable: true,
|
||||||
'render-after-expand': false,
|
|
||||||
style: 'width: 100%',
|
style: 'width: 100%',
|
||||||
placeholder: '请选择 所属组织',
|
placeholder: '请选择 所属组织',
|
||||||
props: { label: 'label', value: 'id', children: 'children' },
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const formalSettlementSearchFields = [
|
|||||||
{ label: '结算单号', prop: 'formalSettlementNo', type: 'input' },
|
{ label: '结算单号', prop: 'formalSettlementNo', type: 'input' },
|
||||||
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
||||||
{ label: '项目', prop: 'projectName', type: 'input' },
|
{ label: '项目', prop: 'projectName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'input' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
||||||
{ label: '付款方', prop: 'payerName', type: 'input' },
|
{ label: '付款方', prop: 'payerName', type: 'input' },
|
||||||
{ label: '收款方', prop: 'payeeName', type: 'input' },
|
{ label: '收款方', prop: 'payeeName', type: 'input' },
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const preSettlementSearchFields = [
|
|||||||
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
{ label: '预结算单号', prop: 'preSettlementNo', type: 'input' },
|
||||||
{ label: '预付单号', prop: 'advanceNo', type: 'input' },
|
{ label: '预付单号', prop: 'advanceNo', type: 'input' },
|
||||||
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'input' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
{ label: '合同名称', prop: 'contractName', type: 'input' },
|
{ label: '合同名称', prop: 'contractName', type: 'input' },
|
||||||
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
{ label: '合同编号', prop: 'contractNo', type: 'input' },
|
||||||
{ label: '收款方', prop: 'payeeName', type: 'input' },
|
{ label: '收款方', prop: 'payeeName', type: 'input' },
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const searchFields = [
|
|||||||
{ label: '单据号', prop: 'documentNo', type: 'input' },
|
{ label: '单据号', prop: 'documentNo', type: 'input' },
|
||||||
{ label: '生成日期', prop: 'generateDateRange', type: 'daterange' },
|
{ label: '生成日期', prop: 'generateDateRange', type: 'daterange' },
|
||||||
{ label: '客户名称', prop: 'customerName', type: 'input' },
|
{ label: '客户名称', prop: 'customerName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'input' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
||||||
{ label: '货物类型', prop: 'cargoType', type: 'input' },
|
{ label: '货物类型', prop: 'cargoType', type: 'input' },
|
||||||
{ label: '货物名称', prop: 'cargoName', type: 'input' },
|
{ label: '货物名称', prop: 'cargoName', type: 'input' },
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const settlementAdjustmentSearchFields = [
|
|||||||
{ label: '日期', prop: 'createDateRange', type: 'daterange' },
|
{ label: '日期', prop: 'createDateRange', type: 'daterange' },
|
||||||
{ label: '客户名称', prop: 'customerName', type: 'input' },
|
{ label: '客户名称', prop: 'customerName', type: 'input' },
|
||||||
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
{ label: '项目名称', prop: 'projectName', type: 'input' },
|
||||||
{ label: '所属组织', prop: 'deptName', type: 'input' },
|
{ label: '所属组织', prop: 'deptName', type: 'cascader' },
|
||||||
{ label: '关联结算单', prop: 'formalSettlementNo', type: 'input' },
|
{ label: '关联结算单', prop: 'formalSettlementNo', type: 'input' },
|
||||||
{
|
{
|
||||||
label: '结算单类型',
|
label: '结算单类型',
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const transportReconciliationSearchFields = [
|
|||||||
{ prop: 'reconciliationNo', label: '对账单号', type: 'input' },
|
{ prop: 'reconciliationNo', label: '对账单号', type: 'input' },
|
||||||
{ prop: 'preSettlementNos', label: '预结算单号', type: 'input' },
|
{ prop: 'preSettlementNos', label: '预结算单号', type: 'input' },
|
||||||
{ prop: 'projectName', label: '项目', type: 'input' },
|
{ prop: 'projectName', label: '项目', type: 'input' },
|
||||||
{ prop: 'deptName', label: '所属组织', type: 'input' },
|
{ prop: 'deptName', label: '所属组织', type: 'cascader' },
|
||||||
{ prop: 'contractNo', label: '合同编号', type: 'input' },
|
{ prop: 'contractNo', label: '合同编号', type: 'input' },
|
||||||
{ prop: 'payerName', label: '付款方', type: 'input' },
|
{ prop: 'payerName', label: '付款方', type: 'input' },
|
||||||
{ prop: 'payeeName', label: '收款方', type: 'input' },
|
{ prop: 'payeeName', label: '收款方', type: 'input' },
|
||||||
|
|||||||
@@ -135,9 +135,10 @@
|
|||||||
//white-space: nowrap;
|
//white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全宽兜底:搜索表单内树形下拉占满(覆盖默认搜索项宽度)
|
// 全宽兜底:搜索表单内树形下拉 / 级联选择器占满(覆盖默认搜索项宽度)
|
||||||
// 注意:搜索 form 内的 el-tree-select 也走该规则;新增/编辑表单用 span=6 的栅格自然分开,不受影响。
|
// 注意:搜索 form 内的 el-tree-select、el-cascader 均走该规则;新增/编辑表单用 span=6 的栅格自然分开,不受影响。
|
||||||
.avue-crud__search .el-form-item__content > .el-tree-select {
|
.avue-crud__search .el-form-item__content > .el-tree-select,
|
||||||
|
.avue-crud__search .el-form-item__content > .el-cascader {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,18 +216,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="所属组织" prop="organizationName">
|
<el-form-item label="所属组织" prop="organizationName">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
v-model="selectedOrganizationId"
|
v-model="organizationCascaderValue"
|
||||||
:data="organizationOptions"
|
:options="organizationOptions"
|
||||||
:props="organizationTreeSelectProps"
|
:props="organizationCascaderProps"
|
||||||
node-key="id"
|
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
check-strictly
|
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
:render-after-expand="false"
|
|
||||||
@visible-change="visible => visible && loadOrganizationOptions()"
|
@visible-change="visible => visible && loadOrganizationOptions()"
|
||||||
@change="handleOrganizationChange"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="经办人">
|
<el-form-item label="经办人">
|
||||||
@@ -794,7 +790,7 @@ import { getToken } from '@/utils/auth';
|
|||||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||||
import { ElImageViewer, ElTreeSelect } from 'element-plus';
|
import { ElImageViewer, ElCascader } from 'element-plus';
|
||||||
import { OpenFileViewer } from '@open-file-viewer/vue';
|
import { OpenFileViewer } from '@open-file-viewer/vue';
|
||||||
import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-file-viewer/core';
|
import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-file-viewer/core';
|
||||||
import '@open-file-viewer/core/style.css';
|
import '@open-file-viewer/core/style.css';
|
||||||
@@ -1230,13 +1226,32 @@ export default {
|
|||||||
contractFormatOptions() {
|
contractFormatOptions() {
|
||||||
return this.columnOptions('contractFormat');
|
return this.columnOptions('contractFormat');
|
||||||
},
|
},
|
||||||
organizationTreeSelectProps() {
|
organizationCascaderProps() {
|
||||||
return {
|
return {
|
||||||
label: 'label',
|
label: 'label',
|
||||||
value: 'id',
|
value: 'id',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
|
emitPath: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
// 所属组织级联:selectedOrganizationId 存部门 id,级联控件用根到节点的 id 路径,
|
||||||
|
// 两者在此双向转换;依赖 organizationOptions,树加载完成后回显自动刷新
|
||||||
|
organizationCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const id = this.selectedOrganizationId || this.form.organizationId;
|
||||||
|
if (!id) return [];
|
||||||
|
return this.findOrganizationPath(id) || [String(id)];
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
const value = Array.isArray(path)
|
||||||
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: [];
|
||||||
|
this.selectedOrganizationId = value.length ? String(value.at(-1)) : '';
|
||||||
|
this.handleOrganizationChange(value);
|
||||||
|
},
|
||||||
|
},
|
||||||
settlementRuleEnabled() {
|
settlementRuleEnabled() {
|
||||||
return Number(this.settlementRuleForm.autoGenerate) === 1;
|
return Number(this.settlementRuleForm.autoGenerate) === 1;
|
||||||
},
|
},
|
||||||
@@ -1728,6 +1743,18 @@ export default {
|
|||||||
const value = Array.isArray(id) ? id.at(-1) : id;
|
const value = Array.isArray(id) ? id.at(-1) : id;
|
||||||
return this.organizationFlatOptions.find(item => String(item.id) === String(value));
|
return this.organizationFlatOptions.find(item => String(item.id) === String(value));
|
||||||
},
|
},
|
||||||
|
// 由部门 id 反查「根 → 该节点」的 id 路径,供级联回显(找不到返回 null)
|
||||||
|
findOrganizationPath(id, tree = this.organizationOptions, parents = []) {
|
||||||
|
const target = Array.isArray(id) ? id.at(-1) : id;
|
||||||
|
if (target === undefined || target === null || target === '') return null;
|
||||||
|
for (const node of tree || []) {
|
||||||
|
const path = [...parents, String(node.id)];
|
||||||
|
if (String(node.id) === String(target)) return path;
|
||||||
|
const matched = this.findOrganizationPath(target, node.children, path);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
handleOrganizationChange(id) {
|
handleOrganizationChange(id) {
|
||||||
const organization = this.findOrganization(id);
|
const organization = this.findOrganization(id);
|
||||||
Object.assign(
|
Object.assign(
|
||||||
@@ -1752,21 +1779,26 @@ export default {
|
|||||||
this.organizationFlatOptions.unshift(item);
|
this.organizationFlatOptions.unshift(item);
|
||||||
},
|
},
|
||||||
renderOrganizationSearch(scope) {
|
renderOrganizationSearch(scope) {
|
||||||
// 搜索区所属组织:树形下拉(与客户档案统一)
|
// 搜索区所属组织:单选级联(与新增/编辑表单一致)
|
||||||
return h(ElTreeSelect, {
|
// 级联返回 id 路径数组,提交时由 normalizeSearch 取末级 id 转组织名称
|
||||||
modelValue: scope.row?.organizationName || '',
|
return h(ElCascader, {
|
||||||
|
modelValue: Array.isArray(scope.row?.organizationName) ? scope.row.organizationName : [],
|
||||||
'onUpdate:modelValue': value => {
|
'onUpdate:modelValue': value => {
|
||||||
if (scope.row) scope.row.organizationName = value;
|
// 级联单选:modelValue 必须是 id 路径数组,否则控件内部状态会错乱导致无法再次选中
|
||||||
|
if (scope.row) scope.row.organizationName = Array.isArray(value) ? value : [];
|
||||||
|
},
|
||||||
|
options: this.organizationOptions,
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'id',
|
||||||
|
children: 'children',
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
},
|
},
|
||||||
data: this.organizationOptions,
|
|
||||||
'node-key': 'id',
|
|
||||||
'check-strictly': true,
|
|
||||||
filterable: true,
|
filterable: true,
|
||||||
clearable: true,
|
clearable: true,
|
||||||
'render-after-expand': false,
|
|
||||||
style: 'width: 100%',
|
style: 'width: 100%',
|
||||||
placeholder: '请选择 所属组织',
|
placeholder: '请选择 所属组织',
|
||||||
props: { label: 'label', value: 'id', children: 'children' },
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
integerInput(prop, value) {
|
integerInput(prop, value) {
|
||||||
|
|||||||
@@ -166,33 +166,25 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="业务部门" prop="businessDeptId">
|
<el-form-item label="业务部门" prop="businessDeptId">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
v-model="form.businessDeptId"
|
v-model="businessDeptCascaderValue"
|
||||||
:data="businessDeptTreeOptions"
|
:options="businessDeptTreeOptions"
|
||||||
:props="deptTreeSelectProps"
|
:props="deptCascaderProps"
|
||||||
node-key="value"
|
|
||||||
placeholder="请选择业务部门"
|
placeholder="请选择业务部门"
|
||||||
check-strictly
|
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
:render-after-expand="false"
|
|
||||||
:disabled="isBasicInfoReadonly"
|
:disabled="isBasicInfoReadonly"
|
||||||
@change="handleBusinessDeptChange"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="承办部门" prop="undertakeDeptId">
|
<el-form-item label="承办部门" prop="undertakeDeptId">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
v-model="form.undertakeDeptId"
|
v-model="undertakeDeptCascaderValue"
|
||||||
:data="deptTreeOptions"
|
:options="deptTreeOptions"
|
||||||
:props="deptTreeSelectProps"
|
:props="deptCascaderProps"
|
||||||
node-key="value"
|
|
||||||
placeholder="请选择承办部门"
|
placeholder="请选择承办部门"
|
||||||
check-strictly
|
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
:render-after-expand="false"
|
|
||||||
:disabled="isBasicInfoReadonly"
|
:disabled="isBasicInfoReadonly"
|
||||||
@change="handleUndertakeDeptChange"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="项目由来" prop="projectSource">
|
<el-form-item label="项目由来" prop="projectSource">
|
||||||
@@ -1047,11 +1039,6 @@ export default {
|
|||||||
deptOptions: [],
|
deptOptions: [],
|
||||||
businessDeptTreeOptions: [],
|
businessDeptTreeOptions: [],
|
||||||
deptTreeOptions: [],
|
deptTreeOptions: [],
|
||||||
deptTreeSelectProps: {
|
|
||||||
label: 'label',
|
|
||||||
value: 'value',
|
|
||||||
children: 'children',
|
|
||||||
},
|
|
||||||
cargoTypeOptions: [],
|
cargoTypeOptions: [],
|
||||||
selectedCustomerId: [],
|
selectedCustomerId: [],
|
||||||
selectedCarrierIds: [],
|
selectedCarrierIds: [],
|
||||||
@@ -1110,6 +1097,45 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
|
// 部门级联配置:checkStrictly 允许选中任意层级,不必选到末级
|
||||||
|
deptCascaderProps() {
|
||||||
|
return {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 业务部门:form 存部门 id,级联控件用根到节点的 id 路径,两者在此双向转换
|
||||||
|
businessDeptCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const id = this.form.businessDeptId;
|
||||||
|
return id ? this.findDeptPath(id, this.businessDeptTreeOptions) || [id] : [];
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
const value = Array.isArray(path)
|
||||||
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: [];
|
||||||
|
this.form.businessDeptId = value.length ? value.at(-1) : '';
|
||||||
|
this.handleBusinessDeptChange(this.form.businessDeptId);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 承办部门:同上
|
||||||
|
undertakeDeptCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const id = this.form.undertakeDeptId;
|
||||||
|
return id ? this.findDeptPath(id, this.deptTreeOptions) || [id] : [];
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
const value = Array.isArray(path)
|
||||||
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: [];
|
||||||
|
this.form.undertakeDeptId = value.length ? value.at(-1) : '';
|
||||||
|
this.handleUndertakeDeptChange(this.form.undertakeDeptId);
|
||||||
|
},
|
||||||
|
},
|
||||||
permissionList() {
|
permissionList() {
|
||||||
return {
|
return {
|
||||||
addBtn: this.canCreate,
|
addBtn: this.canCreate,
|
||||||
@@ -1843,15 +1869,30 @@ export default {
|
|||||||
return `${base}-BG${this.$dayjs().format('YYYYMMDD')}`;
|
return `${base}-BG${this.$dayjs().format('YYYYMMDD')}`;
|
||||||
},
|
},
|
||||||
handleBusinessDeptChange(value) {
|
handleBusinessDeptChange(value) {
|
||||||
const dept = this.deptOptions.find(item => item.value === value);
|
// 兼容级联路径数组(取末级)与单个部门 id
|
||||||
|
const id = Array.isArray(value) ? value.at(-1) : value;
|
||||||
|
const dept = this.deptOptions.find(item => String(item.value) === String(id));
|
||||||
this.form.businessDeptName = dept ? dept.rawLabel : '';
|
this.form.businessDeptName = dept ? dept.rawLabel : '';
|
||||||
this.$refs.projectForm?.validateField('businessDeptId');
|
this.$refs.projectForm?.validateField('businessDeptId');
|
||||||
},
|
},
|
||||||
handleUndertakeDeptChange(value) {
|
handleUndertakeDeptChange(value) {
|
||||||
const dept = this.deptOptions.find(item => item.value === value);
|
const id = Array.isArray(value) ? value.at(-1) : value;
|
||||||
|
const dept = this.deptOptions.find(item => String(item.value) === String(id));
|
||||||
this.form.undertakeDeptName = dept ? dept.rawLabel : '';
|
this.form.undertakeDeptName = dept ? dept.rawLabel : '';
|
||||||
this.$refs.projectForm?.validateField('undertakeDeptId');
|
this.$refs.projectForm?.validateField('undertakeDeptId');
|
||||||
},
|
},
|
||||||
|
// 由部门 id 反查「根 → 该节点」的 id 路径,供级联回显(找不到返回 null)
|
||||||
|
findDeptPath(id, tree = [], parents = []) {
|
||||||
|
const target = Array.isArray(id) ? id.at(-1) : id;
|
||||||
|
if (target === undefined || target === null || target === '') return null;
|
||||||
|
for (const node of tree || []) {
|
||||||
|
const path = [...parents, node.value];
|
||||||
|
if (String(node.value) === String(target)) return path;
|
||||||
|
const matched = this.findDeptPath(target, node.children, path);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
handleProjectTypeChange() {
|
handleProjectTypeChange() {
|
||||||
this.normalizeAttachmentFileTypes();
|
this.normalizeAttachmentFileTypes();
|
||||||
this.$refs.projectForm?.validateField('projectType');
|
this.$refs.projectForm?.validateField('projectType');
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import BillPaymentTable from './components/bill-payment-table.vue';
|
|||||||
const emptyQuery = () => ({
|
const emptyQuery = () => ({
|
||||||
paymentNo: '',
|
paymentNo: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
|
deptPath: [],
|
||||||
paymentDateRange: [],
|
paymentDateRange: [],
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,18 +6,15 @@
|
|||||||
<el-input v-model="query.paymentNo" clearable placeholder="请输入" />
|
<el-input v-model="query.paymentNo" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="使用部门">
|
<el-form-item label="使用部门">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
:model-value="query.deptName"
|
v-model="query.deptPath"
|
||||||
:data="organizationTreeOptions"
|
:options="organizationTreeOptions"
|
||||||
node-key="id"
|
:props="organizationCascaderProps"
|
||||||
check-strictly
|
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
render-after-expand
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择 所属组织"
|
placeholder="请选择 所属组织"
|
||||||
:props="{ label: 'label', value: 'id', children: 'children' }"
|
@change="val => { query.deptName = findOrgById(val)?.rawLabel || '' }"
|
||||||
@update:model-value="val => { query.deptName = findOrgById(val)?.rawLabel || val }"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="付款日期">
|
<el-form-item label="付款日期">
|
||||||
|
|||||||
@@ -10,18 +10,15 @@
|
|||||||
<el-input v-model="query.projectName" clearable placeholder="请输入" />
|
<el-input v-model="query.projectName" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="所属组织">
|
<el-form-item label="所属组织">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
:model-value="query.deptName"
|
v-model="query.deptPath"
|
||||||
:data="organizationTreeOptions"
|
:options="organizationTreeOptions"
|
||||||
node-key="id"
|
:props="organizationCascaderProps"
|
||||||
check-strictly
|
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
render-after-expand
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择 所属组织"
|
placeholder="请选择 所属组织"
|
||||||
:props="{ label: 'label', value: 'id', children: 'children' }"
|
@change="val => { query.deptName = findOrgById(val)?.rawLabel || '' }"
|
||||||
@update:model-value="val => { query.deptName = findOrgById(val)?.rawLabel || val }"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="invoice-kingdee-item" label="金蝶单据状态">
|
<el-form-item class="invoice-kingdee-item" label="金蝶单据状态">
|
||||||
@@ -252,6 +249,7 @@ const emptyQuery = () => ({
|
|||||||
applicationNo: '',
|
applicationNo: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
|
deptPath: [],
|
||||||
kingdeeStatus: '',
|
kingdeeStatus: '',
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,18 +19,15 @@
|
|||||||
<el-input v-model="query.projectName" clearable placeholder="请输入" />
|
<el-input v-model="query.projectName" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="所属组织">
|
<el-form-item label="所属组织">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
:model-value="query.deptName"
|
v-model="query.deptPath"
|
||||||
:data="organizationTreeOptions"
|
:options="organizationTreeOptions"
|
||||||
node-key="id"
|
:props="organizationCascaderProps"
|
||||||
check-strictly
|
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
render-after-expand
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择 所属组织"
|
placeholder="请选择 所属组织"
|
||||||
:props="{ label: 'label', value: 'id', children: 'children' }"
|
@change="val => { query.deptName = findOrgById(val)?.rawLabel || '' }"
|
||||||
@update:model-value="val => { query.deptName = findOrgById(val)?.rawLabel || val }"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="searchExpanded" label="审核状态">
|
<el-form-item v-if="searchExpanded" label="审核状态">
|
||||||
@@ -245,6 +242,7 @@ const emptyQuery = () => ({
|
|||||||
invoiceDate: '',
|
invoiceDate: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
|
deptPath: [],
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
kingdeeStatus: '',
|
kingdeeStatus: '',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,18 +23,15 @@
|
|||||||
/></el-form-item>
|
/></el-form-item>
|
||||||
<template v-if="searchExpanded">
|
<template v-if="searchExpanded">
|
||||||
<el-form-item label="所属组织"
|
<el-form-item label="所属组织"
|
||||||
><el-tree-select
|
><el-cascader
|
||||||
:model-value="query.deptName"
|
v-model="query.deptPath"
|
||||||
:data="organizationTreeOptions"
|
:options="organizationTreeOptions"
|
||||||
node-key="id"
|
:props="organizationCascaderProps"
|
||||||
check-strictly
|
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
render-after-expand
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请选择 所属组织"
|
placeholder="请选择 所属组织"
|
||||||
:props="{ label: 'label', value: 'id', children: 'children' }"
|
@change="val => { query.deptName = findOrgById(val)?.rawLabel || '' }"
|
||||||
@update:model-value="val => { query.deptName = findOrgById(val)?.rawLabel || val }"
|
|
||||||
/></el-form-item>
|
/></el-form-item>
|
||||||
<el-form-item label="关联结算单"
|
<el-form-item label="关联结算单"
|
||||||
><el-input v-model="query.settlementNo" clearable
|
><el-input v-model="query.settlementNo" clearable
|
||||||
@@ -243,6 +240,7 @@ const emptyQuery = () => ({
|
|||||||
payeeName: '',
|
payeeName: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
|
deptPath: [],
|
||||||
settlementNo: '',
|
settlementNo: '',
|
||||||
paymentType: '',
|
paymentType: '',
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
|
|||||||
@@ -27,6 +27,16 @@
|
|||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-cascader
|
||||||
|
v-else-if="field.type === 'cascader'"
|
||||||
|
v-model="query[field.prop]"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="formal-page__search-actions">
|
<div class="formal-page__search-actions">
|
||||||
@@ -168,6 +178,7 @@ import {
|
|||||||
formalSettlementSearchFields,
|
formalSettlementSearchFields,
|
||||||
paymentStatusOptions,
|
paymentStatusOptions,
|
||||||
} from '@/option/settlement/formalSettlementSearch';
|
} from '@/option/settlement/formalSettlementSearch';
|
||||||
|
import organizationSearch from '@/mixins/organization-search';
|
||||||
import { formalSettlementTableColumns } from '@/option/settlement/formalSettlementTable';
|
import { formalSettlementTableColumns } from '@/option/settlement/formalSettlementTable';
|
||||||
import FormalSettlementEditor from './components/formal-settlement-editor.vue';
|
import FormalSettlementEditor from './components/formal-settlement-editor.vue';
|
||||||
import FormalSettlementTablePanel from './components/formal-settlement-table-panel.vue';
|
import FormalSettlementTablePanel from './components/formal-settlement-table-panel.vue';
|
||||||
@@ -176,7 +187,7 @@ const emptyQuery = () => ({
|
|||||||
formalSettlementNo: '',
|
formalSettlementNo: '',
|
||||||
preSettlementNo: '',
|
preSettlementNo: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: [],
|
||||||
contractNo: '',
|
contractNo: '',
|
||||||
payerName: '',
|
payerName: '',
|
||||||
payeeName: '',
|
payeeName: '',
|
||||||
@@ -190,6 +201,7 @@ const emptyQuery = () => ({
|
|||||||
export default {
|
export default {
|
||||||
name: 'FormalSettlement',
|
name: 'FormalSettlement',
|
||||||
components: { FormalSettlementEditor, FormalSettlementTablePanel },
|
components: { FormalSettlementEditor, FormalSettlementTablePanel },
|
||||||
|
mixins: [organizationSearch],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
@@ -231,6 +243,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.loadOrganizationOptions();
|
||||||
this.loadTable();
|
this.loadTable();
|
||||||
this.openRouteDetail();
|
this.openRouteDetail();
|
||||||
},
|
},
|
||||||
@@ -517,7 +530,8 @@ export default {
|
|||||||
XLSX.writeFile(workbook, `正式结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`);
|
XLSX.writeFile(workbook, `正式结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`);
|
||||||
},
|
},
|
||||||
buildQueryParams() {
|
buildQueryParams() {
|
||||||
const params = { ...this.query };
|
// 所属组织级联返回 id 路径,转成组织名称传给后端(用副本,避免污染搜索框回显)
|
||||||
|
const params = this.normalizeOrganizationSearch({ ...this.query }, 'deptName');
|
||||||
params.settlementType = this.activeSettlementType;
|
params.settlementType = this.activeSettlementType;
|
||||||
const range = params.createDateRange || [];
|
const range = params.createDateRange || [];
|
||||||
delete params.createDateRange;
|
delete params.createDateRange;
|
||||||
|
|||||||
@@ -29,6 +29,16 @@
|
|||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-cascader
|
||||||
|
v-else-if="field.type === 'cascader'"
|
||||||
|
v-model="query[field.prop]"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
@@ -283,6 +293,7 @@ import {
|
|||||||
voidBill,
|
voidBill,
|
||||||
} from '@/api/settlement/preSettlement';
|
} from '@/api/settlement/preSettlement';
|
||||||
import { preSettlementSearchFields } from '@/option/settlement/preSettlementSearch';
|
import { preSettlementSearchFields } from '@/option/settlement/preSettlementSearch';
|
||||||
|
import organizationSearch from '@/mixins/organization-search';
|
||||||
import { preSettlementTableColumns } from '@/option/settlement/preSettlementTable';
|
import { preSettlementTableColumns } from '@/option/settlement/preSettlementTable';
|
||||||
import { createSettlementTransfer } from '@/utils/settlement-transfer';
|
import { createSettlementTransfer } from '@/utils/settlement-transfer';
|
||||||
import { downloadFile } from '@/utils/util';
|
import { downloadFile } from '@/utils/util';
|
||||||
@@ -292,7 +303,7 @@ const emptyQuery = () => ({
|
|||||||
preSettlementNo: '',
|
preSettlementNo: '',
|
||||||
advanceNo: '',
|
advanceNo: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: [],
|
||||||
contractName: '',
|
contractName: '',
|
||||||
contractNo: '',
|
contractNo: '',
|
||||||
payeeName: '',
|
payeeName: '',
|
||||||
@@ -304,6 +315,7 @@ const emptyQuery = () => ({
|
|||||||
export default {
|
export default {
|
||||||
name: 'PreSettlement',
|
name: 'PreSettlement',
|
||||||
components: { PreSettlementEditor },
|
components: { PreSettlementEditor },
|
||||||
|
mixins: [organizationSearch],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
@@ -357,6 +369,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.loadOrganizationOptions();
|
||||||
this.loadTable();
|
this.loadTable();
|
||||||
this.openRouteDetail();
|
this.openRouteDetail();
|
||||||
},
|
},
|
||||||
@@ -377,8 +390,10 @@ export default {
|
|||||||
},
|
},
|
||||||
buildQuery() {
|
buildQuery() {
|
||||||
const range = this.query.createDateRange || [];
|
const range = this.query.createDateRange || [];
|
||||||
|
// 所属组织级联返回 id 路径,转成组织名称传给后端(用副本,避免污染搜索框回显)
|
||||||
|
const query = this.normalizeOrganizationSearch({ ...this.query }, 'deptName');
|
||||||
return {
|
return {
|
||||||
...this.query,
|
...query,
|
||||||
createDateRange: undefined,
|
createDateRange: undefined,
|
||||||
createStartDate: range[0],
|
createStartDate: range[0],
|
||||||
createEndDate: range[1],
|
createEndDate: range[1],
|
||||||
|
|||||||
@@ -25,6 +25,16 @@
|
|||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/></el-select>
|
/></el-select>
|
||||||
|
<el-cascader
|
||||||
|
v-else-if="field.type === 'cascader'"
|
||||||
|
v-model="query[field.prop]"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="settlement-adjustment-page__search-actions">
|
<div class="settlement-adjustment-page__search-actions">
|
||||||
@@ -159,6 +169,7 @@ import { ArrowDown, ArrowUp, Refresh } from '@element-plus/icons-vue';
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import * as api from '@/api/settlement/settlementAdjustment';
|
import * as api from '@/api/settlement/settlementAdjustment';
|
||||||
import { settlementAdjustmentSearchFields } from '@/option/settlement/settlementAdjustmentSearch';
|
import { settlementAdjustmentSearchFields } from '@/option/settlement/settlementAdjustmentSearch';
|
||||||
|
import organizationSearch from '@/mixins/organization-search';
|
||||||
import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable';
|
import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable';
|
||||||
import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue';
|
import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue';
|
||||||
|
|
||||||
@@ -167,7 +178,7 @@ const emptyQuery = () => ({
|
|||||||
createDateRange: [],
|
createDateRange: [],
|
||||||
customerName: '',
|
customerName: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: [],
|
||||||
formalSettlementNo: '',
|
formalSettlementNo: '',
|
||||||
settlementType: '',
|
settlementType: '',
|
||||||
approvalStatus: '',
|
approvalStatus: '',
|
||||||
@@ -175,6 +186,7 @@ const emptyQuery = () => ({
|
|||||||
export default {
|
export default {
|
||||||
name: 'SettlementAdjustment',
|
name: 'SettlementAdjustment',
|
||||||
components: { SettlementAdjustmentEditor },
|
components: { SettlementAdjustmentEditor },
|
||||||
|
mixins: [organizationSearch],
|
||||||
data: () => ({
|
data: () => ({
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
ArrowUp,
|
ArrowUp,
|
||||||
@@ -199,6 +211,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.loadOrganizationOptions();
|
||||||
this.loadTable();
|
this.loadTable();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -210,7 +223,8 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const range = this.query.createDateRange || [];
|
const range = this.query.createDateRange || [];
|
||||||
const { data } = await api.getList(this.page.current, this.page.size, {
|
const { data } = await api.getList(this.page.current, this.page.size, {
|
||||||
...this.query,
|
// 所属组织级联返回 id 路径,转成组织名称传给后端(用副本,避免污染搜索框回显)
|
||||||
|
...this.normalizeOrganizationSearch({ ...this.query }, 'deptName'),
|
||||||
createDateRange: undefined,
|
createDateRange: undefined,
|
||||||
createStartDate: range[0],
|
createStartDate: range[0],
|
||||||
createEndDate: range[1],
|
createEndDate: range[1],
|
||||||
|
|||||||
@@ -17,6 +17,16 @@
|
|||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-cascader
|
||||||
|
v-else-if="field.type === 'cascader'"
|
||||||
|
v-model="query[field.prop]"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请选择"
|
||||||
|
/>
|
||||||
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
<el-input v-else v-model="query[field.prop]" clearable placeholder="请输入" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,6 +97,7 @@ import * as XLSX from 'xlsx';
|
|||||||
import * as api from '@/api/settlement/transportReconciliation';
|
import * as api from '@/api/settlement/transportReconciliation';
|
||||||
import { transportReconciliationSearchFields } from '@/option/settlement/transportReconciliationSearch';
|
import { transportReconciliationSearchFields } from '@/option/settlement/transportReconciliationSearch';
|
||||||
import { transportReconciliationTableColumns } from '@/option/settlement/transportReconciliationTable';
|
import { transportReconciliationTableColumns } from '@/option/settlement/transportReconciliationTable';
|
||||||
|
import organizationSearch from '@/mixins/organization-search';
|
||||||
import TransportReconciliationEditor from './components/transport-reconciliation-editor.vue';
|
import TransportReconciliationEditor from './components/transport-reconciliation-editor.vue';
|
||||||
import TransportReconciliationTablePanel from './components/transport-reconciliation-table-panel.vue';
|
import TransportReconciliationTablePanel from './components/transport-reconciliation-table-panel.vue';
|
||||||
|
|
||||||
@@ -94,7 +105,7 @@ const emptyQuery = () => ({
|
|||||||
reconciliationNo: '',
|
reconciliationNo: '',
|
||||||
preSettlementNos: '',
|
preSettlementNos: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: [],
|
||||||
contractNo: '',
|
contractNo: '',
|
||||||
payerName: '',
|
payerName: '',
|
||||||
payeeName: '',
|
payeeName: '',
|
||||||
@@ -105,6 +116,7 @@ const emptyQuery = () => ({
|
|||||||
export default {
|
export default {
|
||||||
name: 'TransportReconciliation',
|
name: 'TransportReconciliation',
|
||||||
components: { TransportReconciliationEditor, TransportReconciliationTablePanel },
|
components: { TransportReconciliationEditor, TransportReconciliationTablePanel },
|
||||||
|
mixins: [organizationSearch],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ArrowDown,
|
ArrowDown,
|
||||||
@@ -129,6 +141,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.loadOrganizationOptions();
|
||||||
this.loadTable();
|
this.loadTable();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -139,7 +152,8 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const response = await api.getList(this.page.current, this.page.size, {
|
const response = await api.getList(this.page.current, this.page.size, {
|
||||||
...this.query,
|
// 所属组织级联返回 id 路径,转成组织名称传给后端(用副本,避免污染搜索框回显)
|
||||||
|
...this.normalizeOrganizationSearch({ ...this.query }, 'deptName'),
|
||||||
settlementType: this.settlementType,
|
settlementType: this.settlementType,
|
||||||
});
|
});
|
||||||
const data = response?.data?.data || response?.data || response || {};
|
const data = response?.data?.data || response?.data || response || {};
|
||||||
|
|||||||
@@ -195,7 +195,7 @@
|
|||||||
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="所属组织" prop="deptId"><el-tree-select v-model="form.deptId" :data="permissionDeptTree" :props="{ label: 'title', value: 'id' }" multiple check-strictly show-checkbox /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="所属组织" prop="deptId"><el-cascader v-model="deptCascaderValue" :options="permissionDeptTree" :props="deptCascaderProps" clearable filterable placeholder="请选择 所属组织" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
|
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
|
||||||
@@ -443,6 +443,36 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['userInfo', 'permission']),
|
...mapGetters(['userInfo', 'permission']),
|
||||||
|
// 所属组织级联配置:checkStrictly 允许选中任意层级,不必选到末级
|
||||||
|
deptCascaderProps() {
|
||||||
|
return {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 所属组织为单选级联:form.deptId 仍为数组(提交时 join),此处与 id 路径双向转换
|
||||||
|
deptCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const ids = Array.isArray(this.form.deptId)
|
||||||
|
? this.form.deptId
|
||||||
|
: this.form.deptId
|
||||||
|
? [this.form.deptId]
|
||||||
|
: [];
|
||||||
|
const id = ids.find(item => item !== undefined && item !== null && item !== '');
|
||||||
|
return id === undefined ? [] : this.findDeptPath(id) || [id];
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
const value = Array.isArray(path)
|
||||||
|
? path.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
|
: [];
|
||||||
|
this.form.deptId = value.length ? [value.at(-1)] : [];
|
||||||
|
this.$refs.userFormRef?.validateField('deptId');
|
||||||
|
},
|
||||||
|
},
|
||||||
permissionList() {
|
permissionList() {
|
||||||
return {
|
return {
|
||||||
addBtn: this.validData(this.permission.user_add, false),
|
addBtn: this.validData(this.permission.user_add, false),
|
||||||
@@ -565,6 +595,18 @@ export default {
|
|||||||
this.customerList = res.data.data || [];
|
this.customerList = res.data.data || [];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 由部门 id 反查「根 → 该节点」的 id 路径,供级联回显(找不到返回 null)
|
||||||
|
findDeptPath(id, tree = this.permissionDeptTree, parents = []) {
|
||||||
|
const target = Array.isArray(id) ? id.at(-1) : id;
|
||||||
|
if (target === undefined || target === null || target === '') return null;
|
||||||
|
for (const node of tree || []) {
|
||||||
|
const path = [...parents, node.id];
|
||||||
|
if (String(node.id) === String(target)) return path;
|
||||||
|
const matched = this.findDeptPath(target, node.children, path);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
submitRole() {
|
submitRole() {
|
||||||
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
|
const roleList = this.$refs.treeRole.getCheckedKeys().join(',');
|
||||||
if (this.roleFormMode) {
|
if (this.roleFormMode) {
|
||||||
|
|||||||
@@ -490,14 +490,14 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="所属组织" prop="organizationName">
|
<el-form-item label="所属组织" prop="organizationName">
|
||||||
<el-select v-model="driverForm.organizationName" clearable filterable>
|
<el-cascader
|
||||||
<el-option
|
v-model="organizationCascaderValue"
|
||||||
v-for="item in organizationOptions"
|
:options="organizationTreeOptions"
|
||||||
:key="item.value"
|
:props="organizationCascaderProps"
|
||||||
:label="item.label"
|
filterable
|
||||||
:value="item.value"
|
clearable
|
||||||
|
placeholder="请选择 所属组织"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -815,6 +815,15 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
|
// 所属组织级联:表单存组织名称,级联控件用 id 路径,两者在此双向转换
|
||||||
|
organizationCascaderValue: {
|
||||||
|
get() {
|
||||||
|
return this.resolveOrgPath(this.driverForm.organizationName);
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
this.driverForm.organizationName = this.resolveOrgName(path);
|
||||||
|
},
|
||||||
|
},
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
const authority = this.userInfo.authority || '';
|
const authority = this.userInfo.authority || '';
|
||||||
return authority.includes('admin');
|
return authority.includes('admin');
|
||||||
@@ -1613,6 +1622,8 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
searchChange(params, done) {
|
searchChange(params, done) {
|
||||||
|
// 所属组织级联返回的是 id 路径,转成组织名称传给后端
|
||||||
|
this.normalizeOrganizationSearch(params);
|
||||||
this.searchForm = params;
|
this.searchForm = params;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page, params);
|
this.onLoad(this.page, params);
|
||||||
|
|||||||
@@ -145,19 +145,14 @@
|
|||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="船舶所属组织" prop="organizationName">
|
<el-form-item label="船舶所属组织" prop="organizationName">
|
||||||
<el-select
|
<el-cascader
|
||||||
v-model="shipForm.organizationName"
|
v-model="organizationCascaderValue"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
placeholder="请选择"
|
placeholder="请选择 船舶所属组织"
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in organizationOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
/>
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
@@ -707,6 +702,15 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
|
// 船舶所属组织级联:表单存组织名称,级联控件用 id 路径,两者在此双向转换
|
||||||
|
organizationCascaderValue: {
|
||||||
|
get() {
|
||||||
|
return this.resolveOrgPath(this.shipForm.organizationName);
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
this.shipForm.organizationName = this.resolveOrgName(path);
|
||||||
|
},
|
||||||
|
},
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
const authority = this.userInfo.authority || '';
|
const authority = this.userInfo.authority || '';
|
||||||
return authority.includes('admin');
|
return authority.includes('admin');
|
||||||
@@ -1100,6 +1104,8 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
searchChange(params, done) {
|
searchChange(params, done) {
|
||||||
|
// 所属组织级联返回的是 id 路径,转成组织名称传给后端
|
||||||
|
this.normalizeOrganizationSearch(params);
|
||||||
this.searchForm = params;
|
this.searchForm = params;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page, params);
|
this.onLoad(this.page, params);
|
||||||
|
|||||||
@@ -159,19 +159,14 @@
|
|||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="所有组织" prop="organizationName">
|
<el-form-item label="所有组织" prop="organizationName">
|
||||||
<el-select
|
<el-cascader
|
||||||
v-model="vehicleForm.organizationName"
|
v-model="organizationCascaderValue"
|
||||||
|
:options="organizationTreeOptions"
|
||||||
|
:props="organizationCascaderProps"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
placeholder="请选择"
|
placeholder="请选择 所属组织"
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in organizationOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
/>
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -709,6 +704,15 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['permission', 'userInfo']),
|
...mapGetters(['permission', 'userInfo']),
|
||||||
|
// 所属组织级联:表单存组织名称,级联控件用 id 路径,两者在此双向转换
|
||||||
|
organizationCascaderValue: {
|
||||||
|
get() {
|
||||||
|
return this.resolveOrgPath(this.vehicleForm.organizationName);
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
this.vehicleForm.organizationName = this.resolveOrgName(path);
|
||||||
|
},
|
||||||
|
},
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
const authority = this.userInfo.authority || '';
|
const authority = this.userInfo.authority || '';
|
||||||
return authority.includes('admin');
|
return authority.includes('admin');
|
||||||
@@ -1275,6 +1279,8 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
searchChange(params, done) {
|
searchChange(params, done) {
|
||||||
|
// 所属组织级联返回的是 id 路径,转成组织名称传给后端
|
||||||
|
this.normalizeOrganizationSearch(params);
|
||||||
this.searchForm = params;
|
this.searchForm = params;
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
this.onLoad(this.page, params);
|
this.onLoad(this.page, params);
|
||||||
|
|||||||
@@ -335,17 +335,13 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="所属组织" prop="deptName">
|
<el-form-item label="所属组织" prop="deptName">
|
||||||
<el-tree-select
|
<el-cascader
|
||||||
v-model="archiveForm.deptId"
|
v-model="deptCascaderValue"
|
||||||
:data="deptTree"
|
:options="deptTree"
|
||||||
:props="{ label: 'label', value: 'value', children: 'children' }"
|
:props="deptCascaderProps"
|
||||||
multiple
|
|
||||||
node-key="value"
|
|
||||||
check-strictly
|
|
||||||
filterable
|
|
||||||
clearable
|
clearable
|
||||||
:render-after-expand="false"
|
filterable
|
||||||
@change="onDeptChange"
|
placeholder="请选择 所属组织"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -1367,7 +1363,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { h } from 'vue';
|
import { h } from 'vue';
|
||||||
import { ElTreeSelect } from 'element-plus';
|
import { ElCascader } from 'element-plus';
|
||||||
import {
|
import {
|
||||||
getList,
|
getList,
|
||||||
getDetail,
|
getDetail,
|
||||||
@@ -1875,6 +1871,34 @@ export default {
|
|||||||
emitPath: true,
|
emitPath: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
deptCascaderProps() {
|
||||||
|
return {
|
||||||
|
value: 'value',
|
||||||
|
label: 'label',
|
||||||
|
children: 'children',
|
||||||
|
emitPath: true,
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 所属组织级联值:archiveForm.deptId 只存选中的部门 ID(单选),
|
||||||
|
// 级联控件需要根到选中节点的完整路径,两者在此做双向转换——
|
||||||
|
// 部门树是异步加载的,依赖 deptTree 可保证树加载完成后回显自动刷新。
|
||||||
|
deptCascaderValue: {
|
||||||
|
get() {
|
||||||
|
const ids = Array.isArray(this.archiveForm.deptId)
|
||||||
|
? this.archiveForm.deptId
|
||||||
|
: this.archiveForm.deptId
|
||||||
|
? [this.archiveForm.deptId]
|
||||||
|
: [];
|
||||||
|
const currentId = ids.length ? String(ids[ids.length - 1]) : '';
|
||||||
|
if (!currentId) return [];
|
||||||
|
return this.findDeptPath(currentId) || [currentId];
|
||||||
|
},
|
||||||
|
set(path) {
|
||||||
|
this.onDeptChange(path);
|
||||||
|
},
|
||||||
|
},
|
||||||
ids() {
|
ids() {
|
||||||
let ids = [];
|
let ids = [];
|
||||||
this.selectionList.forEach(ele => {
|
this.selectionList.forEach(ele => {
|
||||||
@@ -2645,38 +2669,57 @@ export default {
|
|||||||
this.onDeptChange([firstTopLevelDept.value]);
|
this.onDeptChange([firstTopLevelDept.value]);
|
||||||
},
|
},
|
||||||
onDeptChange(value) {
|
onDeptChange(value) {
|
||||||
const deptIds = Array.isArray(value) ? value : value ? [value] : [];
|
// 级联单选:value 为根到选中节点的 ID 路径,取末级作为客商所属组织
|
||||||
const deptNames = deptIds
|
const path = Array.isArray(value)
|
||||||
.map(id => this.deptOptions.find(item => String(item.value) === String(id))?.rawLabel)
|
? value.filter(item => item !== undefined && item !== null && item !== '')
|
||||||
.filter(Boolean);
|
: [];
|
||||||
this.archiveForm.deptId = deptIds;
|
const deptId = path.length ? String(path[path.length - 1]) : '';
|
||||||
this.archiveForm.deptIds = deptIds.join(',');
|
this.archiveForm.deptId = deptId ? [deptId] : [];
|
||||||
this.archiveForm.deptName = deptNames.join(',');
|
this.archiveForm.deptIds = deptId;
|
||||||
|
this.archiveForm.deptName = deptId ? this.findDeptLabel(deptId) : '';
|
||||||
this.$refs.archiveForm?.validateField('deptName');
|
this.$refs.archiveForm?.validateField('deptName');
|
||||||
},
|
},
|
||||||
|
findDeptPath(id, tree = this.deptTree, parents = []) {
|
||||||
|
for (const node of tree || []) {
|
||||||
|
const path = [...parents, String(node.value)];
|
||||||
|
if (String(node.value) === String(id)) return path;
|
||||||
|
const children = node.children || [];
|
||||||
|
if (children.length) {
|
||||||
|
const matched = this.findDeptPath(id, children, path);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
findDeptLabel(id, tree = this.deptTree) {
|
||||||
|
for (const node of tree || []) {
|
||||||
|
if (String(node.value) === String(id)) return node.label;
|
||||||
|
const matched = this.findDeptLabel(id, node.children || []);
|
||||||
|
if (matched) return matched;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
renderDeptSearch(scope) {
|
renderDeptSearch(scope) {
|
||||||
// 搜索区所属组织:多选树形下拉(与新增/编辑表单一致)
|
// 搜索区所属组织:单选级联(与新增/编辑表单一致)
|
||||||
// 多选返回 ID 数组,转换为部门名称按逗号拼接写入 searchForm.deptName
|
// 级联返回的是根到选中节点的 ID 路径数组,提交时取末级 ID 转部门名称
|
||||||
return h(ElTreeSelect, {
|
return h(ElCascader, {
|
||||||
modelValue: Array.isArray(scope.row?.deptName) ? scope.row.deptName : [],
|
modelValue: Array.isArray(scope.row?.deptName) ? scope.row.deptName : [],
|
||||||
'onUpdate:modelValue': value => {
|
'onUpdate:modelValue': value => {
|
||||||
// 多选模式:modelValue 必须是 ID 数组,否则 el-tree-select 内部状态会错乱导致无法再次选中
|
// 级联单选:modelValue 必须是 ID 路径数组,否则控件内部状态会错乱导致无法再次选中
|
||||||
const ids = Array.isArray(value) ? value : value ? [value] : [];
|
if (scope.row) scope.row.deptName = Array.isArray(value) ? value : [];
|
||||||
if (scope.row) scope.row.deptName = ids;
|
},
|
||||||
|
options: this.deptTree,
|
||||||
|
props: {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
checkStrictly: true,
|
||||||
|
expandTrigger: 'click',
|
||||||
},
|
},
|
||||||
data: this.deptTree,
|
|
||||||
'node-key': 'value',
|
|
||||||
'check-strictly': true,
|
|
||||||
multiple: true,
|
|
||||||
filterable: true,
|
filterable: true,
|
||||||
clearable: true,
|
clearable: true,
|
||||||
'render-after-expand': false,
|
|
||||||
collapseTags: true,
|
|
||||||
'collapse-tags-tooltip': true,
|
|
||||||
'default-expand-all': false,
|
|
||||||
style: 'width: 100%',
|
style: 'width: 100%',
|
||||||
placeholder: '请选择 所属组织',
|
placeholder: '请选择 所属组织',
|
||||||
props: { label: 'label', value: 'value', children: 'children' },
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleNoFixedTermChange(checked) {
|
handleNoFixedTermChange(checked) {
|
||||||
@@ -2717,13 +2760,15 @@ export default {
|
|||||||
: [];
|
: [];
|
||||||
},
|
},
|
||||||
normalizeDeptIds(detail) {
|
normalizeDeptIds(detail) {
|
||||||
|
// 所属组织为单选级联,只保留第一个部门 ID(历史多选数据自动收敛)
|
||||||
const value = detail.deptIds || detail.deptId;
|
const value = detail.deptIds || detail.deptId;
|
||||||
return value
|
const ids = value
|
||||||
? String(value)
|
? String(value)
|
||||||
.split(',')
|
.split(',')
|
||||||
.map(item => item.trim())
|
.map(item => item.trim())
|
||||||
.filter(item => item !== '')
|
.filter(item => item !== '')
|
||||||
: [];
|
: [];
|
||||||
|
return ids.length ? [ids[0]] : [];
|
||||||
},
|
},
|
||||||
formatArchiveAddress(archive = {}) {
|
formatArchiveAddress(archive = {}) {
|
||||||
return [archive.registeredRegionName, archive.registeredDetailAddress]
|
return [archive.registeredRegionName, archive.registeredDetailAddress]
|
||||||
@@ -4539,12 +4584,15 @@ export default {
|
|||||||
this.onLoad(this.page);
|
this.onLoad(this.page);
|
||||||
},
|
},
|
||||||
searchChange(params, done) {
|
searchChange(params, done) {
|
||||||
// 搜索区所属组织多选返回的是部门 ID 数组,需转成部门名称逗号串传给后端(与列表接口 deptName 字段一致)
|
// 搜索区所属组织级联返回的是 ID 路径数组,取末级 ID 转成部门名称传给后端(与列表接口 deptName 字段一致)
|
||||||
if (Array.isArray(params.deptName)) {
|
if (Array.isArray(params.deptName)) {
|
||||||
params.deptName = params.deptName
|
const path = params.deptName.filter(
|
||||||
.map(id => this.deptOptions.find(item => String(item.value) === String(id))?.rawLabel)
|
item => item !== undefined && item !== null && item !== ''
|
||||||
.filter(Boolean)
|
);
|
||||||
.join(',');
|
const deptId = path.length ? path[path.length - 1] : '';
|
||||||
|
params.deptName = deptId
|
||||||
|
? this.deptOptions.find(item => String(item.value) === String(deptId))?.rawLabel || ''
|
||||||
|
: '';
|
||||||
}
|
}
|
||||||
this.query = this.buildQuery(params);
|
this.query = this.buildQuery(params);
|
||||||
this.page.currentPage = 1;
|
this.page.currentPage = 1;
|
||||||
|
|||||||
+13
-13
@@ -47,26 +47,26 @@ export default ({ mode, command }) => {
|
|||||||
__VUE_I18N_LEGACY_API__: true,
|
__VUE_I18N_LEGACY_API__: true,
|
||||||
__INTLIFY_PROD_DEVTOOLS__: false,
|
__INTLIFY_PROD_DEVTOOLS__: false,
|
||||||
},
|
},
|
||||||
server: {
|
|
||||||
port: 2888,
|
|
||||||
proxy: {
|
|
||||||
'/api': {
|
|
||||||
target: 'http://localhost',
|
|
||||||
//target: 'https://saber3.bladex.cn/api',
|
|
||||||
changeOrigin: true,
|
|
||||||
rewrite: path => path.replace(/^\/api/, ''),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// server: {
|
// server: {
|
||||||
// port: 2889,
|
// port: 2888,
|
||||||
// proxy: {
|
// proxy: {
|
||||||
// '/api': {
|
// '/api': {
|
||||||
// target: 'http://172.16.203.228:8000',
|
// target: 'http://localhost',
|
||||||
|
// //target: 'https://saber3.bladex.cn/api',
|
||||||
// changeOrigin: true,
|
// changeOrigin: true,
|
||||||
|
// rewrite: path => path.replace(/^\/api/, ''),
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
server: {
|
||||||
|
port: 2889,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://172.16.203.228:8000',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~': resolve(__dirname, './'),
|
'~': resolve(__dirname, './'),
|
||||||
|
|||||||
Reference in New Issue
Block a user