将开源版本的修改打补丁应用到商业版

This commit is contained in:
wsm
2026-04-09 19:36:52 +08:00
parent d8e3a63df1
commit 7cf7a03983
105 changed files with 18321 additions and 2386 deletions
@@ -0,0 +1,158 @@
<template>
<div class="JSelectDept">
<JSelectBiz @change="handleSelectChange" @handleOpen="handleOpen" :loading="loadingEcho" v-bind="attrs" />
<a-form-item v-show="false">
<SzDeptSelectModal
@register="regModal"
@getSelectResult="setValue"
v-bind="getBindValue"
:rowKey="rowKey"
:labelKey="labelKey"
@close="handleClose"
/>
</a-form-item>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, watchEffect, watch, provide, unref, toRaw } from 'vue';
import SzDeptSelectModal from './modal/SzDeptSelectModal.vue';
import JSelectBiz from '@/components/Form/src/jeecg/components/base/JSelectBiz.vue';
import { useModal } from '/@/components/Modal';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { SelectValue } from 'ant-design-vue/es/select';
import { cloneDeep } from 'lodash-es';
export default defineComponent({
name: 'SzSelectDept',
components: {
SzDeptSelectModal,
JSelectBiz,
},
inheritAttrs: false,
props: {
// 外部 v-model 绑定的值(ID字符串或数组)
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
// 显示文本的字段名
labelKey: {
type: String,
default: 'departName',
},
// 存储值的字段名
rowKey: {
type: String,
default: 'id',
},
// 是否允许多选
multiple: propTypes.bool.def(true),
},
emits: ['options-change', 'change', 'update:value', 'select'],
setup(props, { emit }) {
const [regModal, { openModal }] = useModal();
const attrs = useAttrs();
const selectOptions = ref<SelectValue>([]); // 存储 [{id, departName}]
const selectValues = reactive<Recordable>({ value: [] }); // 存储 [id]
const loadingEcho = ref<boolean>(false);
let tempSave: any = [];
// 依赖注入给 JSelectBiz 组件使用,用于显示标签和加载状态
provide('selectOptions', selectOptions);
provide('selectValues', selectValues);
provide('loadingEcho', loadingEcho);
/**
* 监听外部 value 变化进行初始化
*/
watchEffect(() => {
tempSave = [];
if (props.value) {
initValue();
} else {
selectValues.value = [];
}
});
/**
* 初始化值:将字符串转为数组
*/
function initValue() {
let val = props.value ? props.value : [];
if (typeof val === 'string' && val !== 'null' && val !== 'undefined') {
selectValues.value = val.split(',');
tempSave = val.split(',');
} else {
selectValues.value = Array.isArray(val) ? val : [];
tempSave = cloneDeep(selectValues.value);
}
}
/**
* 【关键】接收弹窗传回的精简数据
* @param options 格式:[{id: 'xxx', departName: 'xxx'}]
* @param values 格式:['xxx']
*/
function setValue(options, values) {
// 将后端字段 [id, departName] 转换为 a-select 认识的 [value, label]
selectOptions.value = options.map((item) => ({
label: item.departName, // 这一步让框里显示出名字
value: item.id, // 这一步让值对应上
}));
selectValues.value = values;
send(values);
}
/**
* 发送数据给父组件
*/
const send = (values) => {
let result = typeof props.value === 'string' ? values.join(',') : values;
emit('update:value', result);
emit('change', result);
};
function handleOpen() {
openModal(true, { isUpdate: false });
}
function handleClose() {
if (tempSave.length) {
selectValues.value = cloneDeep(tempSave);
} else {
send(tempSave);
}
}
function handleSelectChange(values) {
tempSave = cloneDeep(values);
send(tempSave);
}
const getBindValue = Object.assign({}, unref(props), unref(attrs));
return {
attrs,
selectOptions,
selectValues,
loadingEcho,
getBindValue,
regModal,
setValue,
handleOpen,
handleClose,
handleSelectChange,
};
},
});
</script>
<style lang="less" scoped>
.JSelectDept {
> .ant-form-item {
display: none;
}
}
</style>
@@ -0,0 +1,12 @@
// 1. 修改引入路径,Jeecg 使用的是 defHttp
import { defHttp } from '@/utils/http/axios';
// 根据部门+角色+密级筛选用户
export function queryDept(params) {
return defHttp.get({
// 2. 注意:Jeecg 默认配置了 baseUrl,通常不需要写 /jeecg-boot 前缀
url: '/sys/sysDepart/querySecondLevelDepts',
// 3. GET 请求的参数 key 是 params,而不是 data
params,
});
}
@@ -0,0 +1,245 @@
<template>
<div>
<BasicModal
v-bind="$attrs"
@register="register"
:title="modalTitle"
:width="showSelected ? '1200px' : '900px'"
wrapClassName="j-user-select-modal"
@ok="handleOk"
@cancel="handleCancel"
:maxHeight="maxHeight"
:centered="true"
destroyOnClose
@visible-change="visibleChange"
>
<a-row>
<a-col :span="showSelected ? 18 : 24">
<BasicTable
ref="tableRef"
:columns="columns"
:scroll="tableScroll"
v-bind="getBindValue"
:useSearchForm="true"
:formConfig="formConfig"
:api="queryDept"
:searchInfo="searchInfo"
:rowSelection="rowSelection"
:indexColumnProps="indexColumnProps"
:afterFetch="afterFetch"
:beforeFetch="beforeFetch"
>
<template #tableTitle></template>
</BasicTable>
</a-col>
<a-col :span="showSelected ? 6 : 0" v-if="showSelected" style="padding-left: 10px">
<BasicTable v-bind="selectedTable" :dataSource="selectRows">
<template #action="{ record }">
<a href="javascript:void(0)" @click="handleDeleteSelected(record)">
<Icon icon="ant-design:delete-outlined" style="color: #ff4d4f"></Icon>
</a>
</template>
</BasicTable>
</a-col>
</a-row>
</BasicModal>
</div>
</template>
<script lang="ts">
import { defineComponent, unref, ref, watch, h } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { queryDept } from '../dept';
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { useSelectBiz } from '@/components/Form/src/jeecg/hooks/useSelectBiz';
import { useAttrs } from '@/hooks/core/useAttrs';
import { selectProps } from '@/components/Form/src/jeecg/props/props';
import { Icon } from '@/components/Icon';
import { JDictSelectTag } from "@/components/Form";
import { render } from "@/utils/common/renderUtils";
export default defineComponent({
name: 'SzDeptSelectModal',
components: {
BasicModal,
Icon,
BasicTable: createAsyncComponent(() => import('/src/components/Table/src/BasicTable.vue'), {
loading: true,
}),
},
props: {
...selectProps,
modalTitle: {
type: String,
default: '选择部门',
},
},
emits: ['register', 'getSelectResult', 'close'],
setup(props, { emit }) {
const tableScroll = ref<any>({ x: false });
const tableRef = ref();
const maxHeight = ref(600);
// 内部状态注册
const [register, { closeModal }] = useModalInner(() => {
if (window.innerWidth < 900) {
tableScroll.value = { x: 900 };
} else {
tableScroll.value = { x: false };
}
// 延迟设置选中行,确保 table 渲染完成
setTimeout(() => {
if (tableRef.value) {
tableRef.value.setSelectedRowKeys(selectValues['value'] || []);
}
}, 300);
});
const attrs = useAttrs();
// 基础配置
const config = {
canResize: false,
bordered: true,
size: 'small',
rowKey: 'id', // 必须确保后端返回 id 字段
labelKey: 'departName',
};
const getBindValue = Object.assign({}, unref(props), unref(attrs), config);
// 使用 Jeecg 核心 Hook
const [{ rowSelection, visibleChange, selectValues, indexColumnProps, getSelectResult, handleDeleteSelected, selectRows, showSelected }] =
useSelectBiz(queryDept, getBindValue, emit);
const searchInfo = ref(props.params);
// 监听外部 keys 变化同步给 table
watch(rowSelection.selectedRowKeys, (newVal) => {
if (tableRef.value) {
tableRef.value.setSelectedRowKeys(newVal);
}
});
// 搜索表单配置
const formConfig = {
// 在这里增加 labelWidth
labelWidth: 65,
baseColProps: { xs: 24, sm: 12, md: 8, lg: 8, xl: 8, xxl: 8 },
schemas: [
{
label: '部门类别',
field: 'departType',
// 也可以在具体的 schema 里单独控制
// labelWidth: 100,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'depart_type',
placeholder: '请选择部门类别',
stringToNumber: true,
'onUpdate:value': (val) => {
// 这里的 val 就是选中的值
console.log('监听到值改变:', val);
// 触发 Table 刷新
tableRef.value?.reload();
},
},
},
],
};
// 主表列定义
const columns = [
{ title: '部门名称', dataIndex: 'departName', width: 180, align: 'left' },
{ title: '机构编码', dataIndex: 'orgCode', width: 120 },
{
title: '机构类型',
dataIndex: 'departType',
width: 100,
customRender: ({ text }) => {
return render.renderDict(text, 'depart_type');
},
},
{ title: '排序', dataIndex: 'departOrder', width: 80 },
];
// 右侧已选表配置
const selectedTable = {
pagination: false,
showIndexColumn: false,
scroll: { y: 390 },
size: 'small',
canResize: false,
bordered: true,
rowKey: 'id',
columns: [
{ title: '部门名称', dataIndex: 'departName', width: 100 },
{ title: '操作', dataIndex: 'action', align: 'center', width: 40, slots: { customRender: 'action' } },
],
};
/**
* 【修改后的 handleOk】
* 只提取 id 和 departName
*/
function handleOk() {
// 直接从 tableRef 获取选中的原始行数据,避免 label 为 undefined 的问题
const rows = tableRef.value.getSelectRows();
// 1. 提取精简的对象列表
const options = rows.map((item) => ({
id: item.id,
departName: item.departName,
}));
// 2. 提取 ID 列表
const values = rows.map((item) => item.id);
console.log('确定选择内容:', options);
// 3. 向上抛出事件
emit('getSelectResult', options, values);
closeModal();
}
function afterFetch(record) {
return record;
}
function beforeFetch(params) {
return Object.assign({ column: 'createTime', order: 'desc' }, params);
}
const handleCancel = () => {
emit('close');
};
return {
handleOk,
searchInfo,
register,
indexColumnProps,
visibleChange,
getBindValue,
queryDept, // 必须暴露给 template 中的 :api
formConfig,
columns,
rowSelection,
selectRows,
showSelected,
selectedTable,
handleDeleteSelected,
tableScroll,
tableRef,
afterFetch,
handleCancel,
maxHeight,
beforeFetch,
};
},
});
</script>