v3.8.1发布,上传前端代码

This commit is contained in:
JEECG
2025-06-25 16:04:02 +08:00
parent 3d414aaec8
commit 0148f45979
120 changed files with 4783 additions and 486 deletions

View File

@ -367,6 +367,13 @@
margin-bottom: 24px;
}
// update-end--author:liaozhiyang---date:20240620---for【TV360X-1420】校验时闪动
// 表单组件中间件样式
.j-form-item-middleware {
flex: 1;
width: 100%
}
&.suffix-item {
.ant-form-item-children {
display: flex;
@ -376,6 +383,12 @@
margin-top: 4px;
}
// 【QQYUN-12876】当紧凑型 suffix 时,表单组件中间件的宽度不占满
&.suffix-compact .j-form-item-middleware {
flex: unset;
width: auto;
}
.suffix {
display: inline-flex;
padding-left: 6px;

View File

@ -65,6 +65,7 @@ import JTreeSelect from './jeecg/components/JTreeSelect.vue';
import JEllipsis from './jeecg/components/JEllipsis.vue';
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
import JSelectUserByDepartment from './jeecg/components/JSelectUserByDepartment.vue';
import JLinkTableCard from './jeecg/components/JLinkTableCard/JLinkTableCard.vue';
import JUpload from './jeecg/components/JUpload/JUpload.vue';
import JSearchSelect from './jeecg/components/JSearchSelect.vue';
import JAddInput from './jeecg/components/JAddInput.vue';
@ -128,6 +129,7 @@ componentMap.set('JImageUpload', JImageUpload);
componentMap.set('JDictSelectTag', JDictSelectTag);
componentMap.set('JSelectDept', JSelectDept);
componentMap.set('JAreaSelect', JAreaSelect);
componentMap.set('JLinkTableCard', JLinkTableCard);
// componentMap.set(
// 'JEditor',
// createAsyncComponent(() => import('./jeecg/components/JEditor.vue'))

View File

@ -464,10 +464,17 @@
}
function renderItem() {
const { itemProps, slot, render, field, suffix, component } = props.schema;
const { itemProps, slot, render, field, suffix, suffixCompact, component } = props.schema;
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
const { colon } = props.formProps;
// update-begin--author:sunjianlei---date:20250613---foritemProps 属性支持函数形式
let getItemProps = itemProps;
if (typeof getItemProps === 'function') {
getItemProps = getItemProps(unref(getValues));
}
// update-end--author:sunjianlei---date:20250613---foritemProps 属性支持函数形式
if (component === 'Divider') {
return (
<Col span={24}>
@ -486,8 +493,8 @@
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
{...(itemProps as Recordable)}
class={{ 'suffix-item': showSuffix, 'suffix-compact': showSuffix && suffixCompact }}
{...(getItemProps as Recordable)}
label={renderLabelHelpMessage()}
rules={handleRules()}
// update-begin--author:liaozhiyang---date:20240514---forissues/1244标识了必填但是必填标识没显示

View File

@ -1,5 +1,5 @@
<template>
<div :id="formItemId" style="flex: 1; width: 100%">
<div :id="formItemId" class="j-form-item-middleware">
<slot></slot>
</div>
</template>

View File

@ -89,6 +89,8 @@
required: false,
},
style: propTypes.any,
// 搜索时是否只搜索label
onlySearchByLabel: propTypes.bool.def(false),
},
emits: ['options-change', 'change','update:value'],
setup(props, { emit, refs }) {
@ -202,6 +204,10 @@
}
}
// update-end--author:liaozhiyang---date:20230914---for【QQYUN-6514】 配置的时候Y轴不能输入多个字段了控制台报错
if (props.onlySearchByLabel) {
// 如果开启了只在 label 中搜索就不继续往下搜索value了
return false;
}
// 在 value 中搜索
return (option.value || '').toString().toLowerCase().indexOf(input.toLowerCase()) >= 0;
}

View File

@ -25,7 +25,7 @@
</a-button>
</div>
</a-upload>
<a-modal :open="previewVisible" :footer="null" @cancel="handleCancel()">
<a-modal :width="previewWidth" :open="previewVisible" :footer="null" @cancel="handleCancel()">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
@ -38,7 +38,7 @@
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useMessage } from '/@/hooks/web/useMessage';
import { getFileAccessHttpUrl, getHeaders, getRandom } from '/@/utils/common/compUtils';
import { uploadUrl } from '/@/api/common/api';
import { uploadUrl as systemUploadUrl } from '/@/api/common/api';
import { getToken } from '/@/utils/auth';
const { createMessage, createErrorModal } = useMessage();
@ -79,6 +79,15 @@
required: false,
default: 1,
},
uploadUrl: {
type: String,
default: systemUploadUrl,
},
previewWidth: {
type: Number,
required: false,
default: 520,
},
},
emits: ['options-change', 'change', 'update:value'],
setup(props, { emit, refs }) {
@ -256,7 +265,6 @@
multiple,
headers,
loading,
uploadUrl,
beforeUpload,
uploadVisible,
handlePreview,

View File

@ -0,0 +1,379 @@
<template>
<div ref="tableLinkCardRef">
<div class="table-link-card">
<div style="width: 100%; height: 100%">
<div class="card-button" v-if="showButton">
<a-button @click="handleAddRecord"><PlusOutlined /> </a-button>
</div>
<a-row>
<a-col :span="fixedSpan ? fixedSpan : itemSpan" v-for="(record, index) in selectRecords" :key="index">
<div class="card-item" :class="{ 'disabled-chunk': detail == true }">
<!-- -->
<div class="card-item-left" :class="{ 'show-right-image': getImageSrc(record) }">
<span class="card-delete" v-if="disabled == false">
<minus-circle-filled @click="(e) => handleDeleteRecord(e, index)" />
</span>
<div class="card-inner">
<div class="card-main-content">{{ getMainContent(record) }}</div>
<div class="other-content">
<a-row>
<a-col :span="columnSpan" v-for="(col, cIndex) in realShowColumns" :key="cIndex">
<span class="label ellipsis">{{ col.title }}</span>
<span class="text ellipsis">{{ record[col.dataIndex] }}</span>
</a-col>
</a-row>
</div>
</div>
</div>
<div class="card-item-image" v-if="getImageSrc(record)">
<img v-if="getImageSrc(record)" :src="getImageSrc(record)" @error="handleImageError" />
</div>
</div>
</a-col>
</a-row>
</div>
</div>
<LinkTableListModal @register="registerListModal" :multi="multi" :id="popTableName" @success="addCard" />
</div>
</template>
<script>
import { propTypes } from '/@/utils/propTypes';
import { PlusOutlined, MinusCircleFilled } from '@ant-design/icons-vue';
import { computed, ref, watch, onMounted } from 'vue';
import { useLinkTable } from './hooks/useLinkTable';
import { useModal } from '/@/components/Modal';
import placeholderImage from '/@/assets/images/placeholderImage.png';
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
export default {
name: 'JLinkTableCard',
inheritAttrs: false,
props: {
// value字段
valueField: propTypes.string.def(''),
// 文本字段
textField: propTypes.string.def(''),
// 关联表名
tableName: propTypes.string.def(''),
// 是否多选
multi: propTypes.bool.def(false),
value: propTypes.oneOfType([propTypes.string, propTypes.number]),
// ["表单字段,表字典字段","表单字段,表字典字段"]
linkFields: propTypes.array.def([]),
//是否是禁用页面
disabled: propTypes.bool.def(false),
// 是否是detail页面
detail: propTypes.bool.def(false),
// 图片字段
imageField: propTypes.string.def(''),
},
components: {
PlusOutlined,
MinusCircleFilled,
LinkTableListModal: createAsyncComponent(() => import('./components/LinkTableListModal.vue'), { loading: true }),
},
emits: ['change', 'update:value'],
setup(props, { emit }) {
const popTableName = computed(() => {
return props.tableName;
});
//注册model
const [registerListModal, { openModal: openListModal }] = useModal();
const selectValue = ref([]);
const selectRecords = ref([]);
const tableLinkCardRef = ref(null);
const fixedSpan = ref(0);
const showButton = computed(() => {
if (props.disabled == true) {
return false;
}
if (props.multi === false) {
//单选且有值
if (selectRecords.value.length > 0) {
return false;
}
}
return true;
});
const {
auths,
otherColumns,
realShowColumns,
tableColumns,
textFieldArray,
transData,
loadOne,
compareData,
formatData,
initFormData,
getImageSrc,
showImage,
} = useLinkTable(props);
const itemSpan = computed(() => {
if (props.multi === true) {
return 12;
}
return 24;
});
const columnSpan = computed(() => {
if (props.multi === true) {
return 24;
}
return 12;
});
function getMainContent(record) {
if (record) {
if (textFieldArray.value.length > 0) {
let field = textFieldArray.value[0];
return record[field];
}
}
}
function prevent(e) {
e?.stopPropagation();
e?.preventDefault();
}
function handleAddRecord(e) {
prevent(e);
openListModal(true, {
// update-begin--author:liaozhiyang---date:20240517---for【TV360X-43】修复关联记录可以添加重复数据
selectedRowKeys: selectRecords.value.map((item) => item.id),
selectedRows: [...selectRecords.value],
// update-end--author:liaozhiyang---date:20240517---for【TV360X-43】修复关联记录可以添加重复数据
});
}
function addCard(data) {
// update-begin--author:liaozhiyang---date:20240517---for【TV360X-43】修复关联记录可以添加重复数据
let arr = [];
// update-end--author:liaozhiyang---date:20240517---for【TV360X-43】修复关联记录可以添加重复数据
for (let item of data) {
let temp = { ...item };
transData(temp);
arr.push(temp);
}
selectRecords.value = arr;
emitValue();
}
function updateCardData(formData) {
let arr = selectRecords.value;
for (let i = 0; i < arr.length; i++) {
if (arr[i].id === formData.id) {
let temp = { ...formData };
transData(temp);
arr.splice(i, 1, temp);
}
}
selectRecords.value = arr;
emitValue();
}
function handleDeleteRecord(e, index) {
prevent(e);
let temp = selectRecords.value;
if (temp && temp.length > index) {
temp.splice(index, 1);
selectRecords.value = temp;
}
emitValue();
}
function emitValue() {
let arr = selectRecords.value;
let values = [];
let formData = {};
let linkFieldArray = props.linkFields;
if (arr.length > 0) {
for (let i = 0; i < arr.length; i++) {
values.push(arr[i][props.valueField]);
initFormData(formData, linkFieldArray, arr[i]);
}
} else {
initFormData(formData, linkFieldArray);
}
let text = values.join(',');
formatData(formData);
emit('change', text, formData);
emit('update:value', text);
}
watch(
() => props.value,
async (val) => {
if (val) {
let flag = compareData(selectRecords.value, val);
if (flag === false) {
let arr = await loadOne(val);
selectRecords.value = arr;
}
//保证表单其他值回显成功
if (props.linkFields && props.linkFields.length > 0) {
emitValue();
}
} else {
selectRecords.value = [];
}
},
{ immediate: true }
);
onMounted(() => {
// update-begin--author:liaozhiyang---date:20240522---for【TV360X-281】分辨率小时关联记录文字被图片挤没了
if (tableLinkCardRef.value.offsetWidth < 250) {
fixedSpan.value = 24;
}
// update-end--author:liaozhiyang---date:20240522---for【TV360X-281】分辨率小时关联记录文字被图片挤没了
});
// update-begin--author:liaozhiyang---date:20240529---for【TV360X-389】下拉和卡片关联记录图裂开给个默认图片
const handleImageError = (event) => {
event.target.src = placeholderImage;
};
// update-end--author:liaozhiyang---date:20240529---for【TV360X-389】下拉和卡片关联记录图裂开给个默认图片
return {
popTableName,
selectRecords,
otherColumns,
realShowColumns,
showButton,
selectValue,
handleAddRecord,
handleDeleteRecord,
getMainContent,
itemSpan,
columnSpan,
tableColumns,
addCard,
registerListModal,
updateCardData,
getImageSrc,
showImage,
auths,
tableLinkCardRef,
fixedSpan,
placeholderImage,
handleImageError,
};
},
};
</script>
<style scoped lang="less">
.table-link-card {
box-sizing: border-box;
position: relative;
width: 100%;
.card-button {
margin-bottom: 10px !important;
}
.card-item {
width: calc(100% - 10px);
display: inline-flex;
flex-direction: row;
margin: 0px 10px 10px 0px;
position: relative;
border-radius: 3px;
background-color: rgb(255, 255, 255);
box-shadow:
rgb(0 0 0 / 12%) 0px 1px 4px 0px,
rgb(0 0 0 / 12%) 0px 0px 2px 0px;
cursor: pointer;
&:hover {
/* box-shadow: rgb(0 0 0 / 12%) 0px 4px 12px 0px, rgb(0 0 0 / 12%) 0px 0px 2px 0px;*/
.card-item-left {
.card-delete {
display: inline-block;
}
}
}
&.disabled-chunk {
background: none;
box-shadow: none;
}
.card-item-image {
width: 100px;
padding-right: 8px;
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
img {
width: 100%;
}
}
.card-item-left {
width: 100%;
display: inline-block;
&.show-right-image {
width: calc(100% - 100px);
}
.card-delete {
position: absolute;
top: -8px;
right: -8px;
font-size: 16px;
color: #757575;
line-height: 1em;
overflow: hidden;
display: none;
}
.card-inner {
flex: 1 1 0%;
padding: 12px 16px;
overflow: hidden;
padding-bottom: 10px;
.card-main-content {
overflow: hidden;
text-overflow: ellipsis;
vertical-align: top;
white-space: nowrap;
margin-bottom: 8px;
font-weight: 500;
font-size: 14px;
line-height: 20px;
color: rgb(51, 51, 51);
}
.other-content {
.text {
font-size: 12px !important;
display: inline-block;
width: 80%;
}
.label {
max-width: 160px;
color: rgb(158, 158, 158);
padding-right: 0.7em;
display: inline-block;
}
.ellipsis {
overflow: hidden;
height: 22px;
line-height: 22px;
text-overflow: ellipsis;
/* vertical-align: top;*/
white-space: nowrap;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,320 @@
<template>
<BasicModal
@register="registerModal"
:width="popModalFixedWidth"
:dialogStyle="{ top: '70px' }"
:bodyStyle="popBodyStyle"
:title="modalTitle"
wrapClassName="jeecg-online-pop-list-modal"
>
<template #footer>
<a-button key="back" @click="handleCancel">关闭</a-button>
<a-button :disabled="submitDisabled" key="submit" type="primary" @click="handleSubmit" :loading="submitLoading">确定</a-button>
</template>
<BasicTable ref="tableRef" @register="registerTable" :rowSelection="rowSelection">
<!-- update-begin-author:taoyan date:2023-7-11 for: issues/4992 online表单开发 字段控件类型是关联记录 新增的时候选择列表可以添加查询么 -->
<template #tableTitle>
<a-input-search v-model:value="searchText" @search="onSearch" placeholder="请输入关键词,按回车搜索" style="width: 240px" />
</template>
<!-- update-end-author:taoyan date:2023-7-11 for: issues/4992 online表单开发 字段控件类型是关联记录 新增的时候选择列表可以添加查询么 -->
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)"> </TableAction>
</template>
<template #fileSlot="{ text }">
<span v-if="!text" style="font-size: 12px; font-style: italic">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download" size="small" @click="downloadRowFile(text)"> 下载 </a-button>
</template>
<template #imgSlot="{ text }">
<span v-if="!text" style="font-size: 12px; font-style: italic">无图片</span>
<img v-else :src="getImgView(text)" alt="图片不存在" class="online-cell-image" @click="viewOnlineCellImage(text)" />
</template>
<template #htmlSlot="{ text }">
<div v-html="text"></div>
</template>
<template #pcaSlot="{ text }">
<div :title="getPcaText(text)">{{ getPcaText(text) }}</div>
</template>
<template #dateSlot="{ text, column }">
<span>{{ getFormatDate(text, column) }}</span>
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, watch, ref, toRaw, computed, nextTick } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import { useMessage } from '/@/hooks/web/useMessage';
import { defHttp } from '/@/utils/http/axios';
import { useTableColumns } from '@/views/super/online/cgform/hooks/auto/useTableColumns';
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { useFixedHeightModal } from '../hooks/useLinkTable';
export default defineComponent({
name: 'LinkTableListModal',
props: {
/**可以是表名 可以是ID*/
id: {
type: String,
default: '',
},
multi: {
type: Boolean,
default: false,
},
addAuth: {
type: Boolean,
default: true,
},
},
components: {
BasicModal,
BasicTable: createAsyncComponent(() => import('/@/components/Table/src/BasicTable.vue'), { loading: true, delay: 1000 }),
TableAction: createAsyncComponent(() => import('/@/components/Table/src/components/TableAction.vue'), { loading: true, delay: 1000 }),
},
emits: ['success', 'register'],
setup(props, { emit }) {
const { createMessage: $message } = useMessage();
const tableRef = ref(null);
// 弹窗高度控制
const { popModalFixedWidth, resetBodyStyle, popBodyStyle } = useFixedHeightModal();
const searchText = ref('');
const modalWidth = ref(800);
//useModalInner
const [registerModal, { closeModal }] = useModalInner((data) => {
searchText.value = '';
selectedRowKeys.value = data.selectedRowKeys;
selectedRows.value = data.selectedRows;
setTimeout(async () => {
await setPagination({ current: 1 });
await reload(); // 等待表格加载
resetBodyStyle();
}, 100);
});
function handleCancel() {
closeModal();
}
const submitDisabled = computed(() => {
const arr = selectedRowKeys.value;
if (arr && arr.length > 0) {
return false;
}
return true;
});
const submitLoading = ref(false);
function handleSubmit() {
submitLoading.value = true;
let arr = toRaw(selectedRows.value);
if (arr && arr.length > 0) {
emit('success', arr);
closeModal();
}
setTimeout(() => {
submitLoading.value = false;
}, 200);
}
//---------------------列表------------------------
function queryTableData(params) {
const url = '/online/cgform/api/getData/' + props.id;
return defHttp.get({ url, params });
}
function list(params) {
params['column'] = 'id';
return new Promise(async (resolve, _reject) => {
const aa = await queryTableData(params);
resolve(aa);
});
}
const onlineTableContext = {
isPopList: true,
reloadTable() {
console.log('reloadTable');
},
isTree() {
return false;
},
};
const extConfigJson = ref<any>({});
// 处理 BasicTable 的配置
const { columns, downloadRowFile, getImgView, getPcaText, getFormatDate, handleColumnResult, hrefComponent, viewOnlineCellImage } =
useTableColumns(onlineTableContext, extConfigJson);
/**
* 查询table列信息 及其他配置
*/
function getColumnList() {
const url = '/online/cgform/api/getColumns/' + props.id;
return new Promise((resolve, reject) => {
defHttp.get({ url }, { isTransformResponse: false }).then((res) => {
if (res.success) {
resolve(res.result);
} else {
$message.warning(res.message);
reject();
}
});
});
}
const modalTitle = ref('');
watch(
() => props.id,
async () => {
let columnResult: any = await getColumnList();
handleColumnResult(columnResult);
modalTitle.value = columnResult.description;
},
{ immediate: true }
);
const { tableContext } = useListPage({
designScope: 'process-design',
pagination: true,
tableProps: {
title: '',
api: list,
clickToRowSelect: true,
columns: columns,
showTableSetting: false,
immediate: false,
//showIndexColumn: true,
canResize: false,
showActionColumn: false,
actionColumn: {
dataIndex: 'action',
slots: { customRender: 'action' },
},
useSearchForm: false,
beforeFetch: (params) => {
return addQueryParams(params);
},
},
});
const [registerTable, { reload, setPagination }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
watch(
() => props.multi,
(val) => {
if (val == true) {
rowSelection.type = 'checkbox';
} else {
rowSelection.type = 'radio';
}
},
{ immediate: true }
);
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleUpdate.bind(null, record),
},
];
}
function handleUpdate(record) {
console.log('handleUpdate', record);
}
function onSearch() {
reload();
}
const eqConditonTypes = ['int', 'double', 'Date', 'Datetime', 'BigDecimal'];
function addQueryParams(params) {
let text = searchText.value;
if (!text) {
params['superQueryMatchType'] = 'or';
params['superQueryParams'] = '';
return params;
}
let arr = columns.value;
let conditions: any[] = [];
if (arr && arr.length > 0) {
for (let item of arr) {
if (item.dbType) {
if (item.dbType == 'string') {
conditions.push({ field: item.dataIndex, type: item.dbType.toLowerCase(), rule: 'like', val: text });
} else if (item.dbType == 'Date') {
if (text.length == '2020-10-10'.length) {
conditions.push({ field: item.dataIndex, type: item.dbType.toLowerCase(), rule: 'eq', val: text });
}
} else if (item.dbType == 'Datetime') {
if (text.length == '2020-10-10 10:10:10'.length) {
conditions.push({ field: item.dataIndex, type: item.dbType.toLowerCase(), rule: 'eq', val: text });
}
} else if (eqConditonTypes.indexOf(item.dbType)) {
conditions.push({ field: item.dataIndex, type: item.dbType.toLowerCase(), rule: 'eq', val: text });
} else {
//text blob不做处理
}
}
}
}
params['superQueryMatchType'] = 'or';
params['superQueryParams'] = encodeURI(JSON.stringify(conditions));
return params;
}
// modal数据新增完成 直接关闭list将新增的数据带回表单
function handleDataSave(data) {
console.log('handleDateSave', data);
// update-begin--author:liaozhiyang---date:20250429---for【issues/8163】关联记录新增丢失
let arr = [data, ...selectedRows.value];
// update-end--author:liaozhiyang---date:20250429---for【issues/8163】关联记录新增丢失
emit('success', arr);
closeModal();
//reload();
}
return {
registerModal,
modalWidth,
handleCancel,
submitDisabled,
submitLoading,
handleSubmit,
registerTable,
getTableAction,
searchText,
onSearch,
downloadRowFile,
getImgView,
getPcaText,
getFormatDate,
hrefComponent,
viewOnlineCellImage,
rowSelection,
modalTitle,
reload,
popModalFixedWidth,
popBodyStyle,
handleDataSave,
tableRef,
};
},
});
</script>
<style scoped></style>

View File

@ -0,0 +1,358 @@
import { defHttp } from '/@/utils/http/axios';
import { ref, watchEffect, computed, reactive } from 'vue';
import { pick } from 'lodash-es';
import { filterMultiDictText } from '/@/utils/dict/JDictSelectUtil';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
function queryTableData(tableName, params) {
const url = '/online/cgform/api/getData/' + tableName;
return defHttp.get({ url, params });
}
function queryTableColumns(tableName, params) {
const url = '/online/cgform/api/getColumns/' + tableName;
return defHttp.get({ url, params });
}
export function useLinkTable(props) {
//TODO 目前只支持查询第一页的数据,可以输入关键字搜索
const pageNo = ref('1');
// 查询列
const baseParam = ref<any>({});
// 搜素条件
const searchParam = ref<any>({});
// 第一个文本列
const mainContentField = ref('');
//权限数据
const auths = reactive({
add: true,
update: true,
});
//显示列
const textFieldArray = computed(() => {
if (props.textField) {
return props.textField.split(',');
}
return [];
});
const otherColumns = ref<any[]>([]);
// 展示的列 配置的很多列,但是只展示三行
const realShowColumns = computed(() => {
const columns = otherColumns.value;
if (props.multi == true) {
return columns.slice(0, 3);
} else {
return columns.slice(0, 6);
}
});
watchEffect(async () => {
const table = props.tableName;
if (table) {
const valueField = props.valueField || '';
const textField = props.textField || '';
const arr: any[] = [];
if (valueField) {
arr.push(valueField);
}
if (textField) {
const temp = textField.split(',');
mainContentField.value = temp[0];
for (const field of temp) {
arr.push(field);
}
}
const imageField = props.imageField || '';
if (imageField) {
arr.push(imageField);
}
baseParam.value = {
linkTableSelectFields: arr.join(','),
};
await resetTableColumns();
await reloadTableLinkOptions();
}
});
const otherFields = computed(() => {
const textField = props.textField || '';
const others: any[] = [];
let labelField = '';
if (textField) {
const temp = textField.split(',');
labelField = temp[0];
for (let i = 0; i < temp.length; i++) {
if (i > 0) {
others.push(temp[i]);
}
}
}
return {
others,
labelField,
};
});
// 选项
const selectOptions = ref<any[]>([]);
const tableColumns = ref<any[]>([]);
const dictOptions = ref<any>({});
async function resetTableColumns() {
const params = baseParam.value;
const data = await queryTableColumns(props.tableName, params);
tableColumns.value = data.columns;
if (data.columns) {
const imageField = props.imageField;
const arr = data.columns.filter((c) => c.dataIndex != mainContentField.value && c.dataIndex != imageField);
otherColumns.value = arr;
}
dictOptions.value = data.dictOptions;
// 权限数据
console.log('隐藏的按钮', data.hideColumns);
if (data.hideColumns) {
const hideCols = data.hideColumns;
if (hideCols.indexOf('add') >= 0) {
auths.add = false;
} else {
auths.add = true;
}
if (hideCols.indexOf('update') >= 0) {
auths.update = false;
} else {
auths.update = true;
}
}
}
async function reloadTableLinkOptions() {
const params = getLoadDataParams();
const data = await queryTableData(props.tableName, params);
const records = data.records;
//tableTitle.value = data.head.tableTxt;
const dataList: any[] = [];
const { others, labelField } = otherFields.value;
const imageField = props.imageField;
if (records && records.length > 0) {
for (const rd of records) {
const temp = { ...rd };
transData(temp);
const result = Object.assign({}, pick(temp, others), { id: temp.id, label: temp[labelField], value: temp[props.valueField] });
if (imageField) {
result[imageField] = temp[imageField];
}
dataList.push(result);
}
}
//添加一个空对象 为add操作占位
// update-begin--author:liaozhiyang---date:20240607---for【TV360X-1095】高级查询关联记录去掉编辑按钮及去掉记录按钮
props.editBtnShow && dataList.push({});
// update-end--author:liaozhiyang---date:20240607---for【TV360X-1095】高级查询关联记录去掉编辑按钮及去掉记录按钮
selectOptions.value = dataList;
}
/**
* 数据简单翻译-字典
* @param data
*/
function transData(data) {
const columns = tableColumns.value;
const dictInfo = dictOptions.value;
for (const c of columns) {
const { dataIndex, customRender } = c;
if (data[dataIndex] || data[dataIndex] === 0) {
if (customRender && customRender == dataIndex) {
//这样的就是 字典数据了 可以直接翻译
if (dictInfo[customRender]) {
data[dataIndex] = filterMultiDictText(dictInfo[customRender], data[dataIndex]);
continue;
}
}
}
// 兼容后台翻译字段
const dictText = data[dataIndex + '_dictText'];
if (dictText) {
data[dataIndex] = dictText;
}
}
}
//获取加载数据的查询条件
function getLoadDataParams() {
const params = Object.assign({ pageSize: 100, pageNo: pageNo.value }, baseParam.value, searchParam.value);
return params;
}
//设置查询条件
function addQueryParams(text) {
if (!text) {
searchParam.value = {};
} else {
const arr = textFieldArray.value;
const params: any[] = [];
const fields: any[] = [];
for (let i = 0; i < arr.length; i++) {
if (i <= 1) {
fields.push(arr[i]);
params.push({ field: arr[i], rule: 'like', val: text });
}
}
// params[arr[i]] = `*${text}*`
// params['selectConditionFields'] = fields.join(',')
// searchParam.value = params;
params['superQueryMatchType'] = 'or';
params['superQueryParams'] = encodeURI(JSON.stringify(params));
searchParam.value = params;
}
}
async function loadOne(value) {
if (!value) {
return [];
}
let valueFieldName = props.valueField;
let params = {
...baseParam.value,
pageSize: 100,
pageNo: pageNo.value,
};
params['superQueryMatchType'] = 'and';
let valueCondition = [{ field: valueFieldName, rule: 'in', val: value }];
params['superQueryParams'] = encodeURI(JSON.stringify(valueCondition));
const data = await queryTableData(props.tableName, params);
let records = data.records;
//tableTitle.value = data.head.tableTxt;
let dataList: any[] = [];
if (records && records.length > 0) {
for (let item of records) {
let temp = { ...item };
transData(temp);
dataList.push(temp);
}
}
return dataList;
}
/**
* true:数据一致false:数据不一致
* @param arr
* @param value
*/
function compareData(arr, value) {
if (!arr || arr.length == 0) {
return false;
}
const valueArray = value.split(',');
if (valueArray.length != arr.length) {
return false;
}
let flag = true;
for (const item of arr) {
const temp = item[props.valueField];
if (valueArray.indexOf(temp) < 0) {
flag = false;
}
}
return flag;
}
function formatData(formData) {
Object.keys(formData).map((k) => {
if (formData[k] instanceof Array) {
formData[k] = formData[k].join(',');
}
});
}
function initFormData(formData, linkFieldArray, record) {
if (!record) {
record = {};
}
if (linkFieldArray && linkFieldArray.length > 0) {
for (const str of linkFieldArray) {
const arr = str.split(',');
//["表单字段,表字典字段"]
const field = arr[0];
const dictField = arr[1];
if (!formData[field]) {
const value = record[dictField] || '';
formData[field] = [value];
} else {
formData[field].push(record[dictField]);
}
}
}
}
// 获取图片地址
function getImageSrc(item) {
if (props.imageField) {
let url = item[props.imageField];
// update-begin--author:liaozhiyang---date:20250517---for【TV360X-38】关联记录空间被关联数据优多个图片时封面图片不展示
if (typeof url === 'string') {
// 有多张图时默认取第一张
url = url.split(',')[0];
}
// update-end--author:liaozhiyang---date:20250517---for【TV360X-38】关联记录空间被关联数据优多个图片时封面图片不展示
return getFileAccessHttpUrl(url);
}
return '';
}
const showImage = computed(() => {
if (props.imageField) {
return true;
} else {
return false;
}
});
return {
pageNo,
otherColumns,
realShowColumns,
selectOptions,
reloadTableLinkOptions,
textFieldArray,
addQueryParams,
tableColumns,
transData,
mainContentField,
loadOne,
compareData,
formatData,
initFormData,
getImageSrc,
showImage,
auths,
};
}
/**
* 使用固定高度的modal
*/
export function useFixedHeightModal() {
const minWidth = 800;
const popModalFixedWidth = ref(800);
let tempWidth = window.innerWidth - 300;
if (tempWidth < minWidth) {
tempWidth = minWidth;
}
popModalFixedWidth.value = tempWidth;
// 弹窗高度控制
const popBodyStyle = ref({});
function resetBodyStyle() {
const height = window.innerHeight - 210;
popBodyStyle.value = {
height: height + 'px',
overflowY: 'auto',
};
}
return {
popModalFixedWidth,
popBodyStyle,
resetBodyStyle,
};
}

View File

@ -15,6 +15,9 @@
@search="loadData"
@change="handleAsyncChange"
@popupScroll="handlePopupScroll"
:mode="multiple?'multiple':''"
@select="handleSelect"
@deselect="handleDeSelect"
>
<template #notFoundContent>
<a-spin size="small" />
@ -33,6 +36,9 @@
:notFoundContent="loading ? undefined : null"
:dropdownAlign="{overflow: {adjustY: adjustY }}"
@change="handleChange"
:mode="multiple?'multiple':''"
@select="handleSelect"
@deselect="handleDeSelect"
>
<template #notFoundContent>
<a-spin v-if="loading" size="small" />
@ -83,6 +89,13 @@
default: ()=>{}
},
//update-end-author:taoyan date:2022-8-15 for: VUEN-1971 【online 专项测试】关联记录和他表字段 1
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
//是否为多选
multiple:{
type: Boolean,
default: false
},
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
},
emits: ['change', 'update:value'],
setup(props, { emit, refs }) {
@ -210,28 +223,55 @@
if (!selectedAsyncValue || !selectedAsyncValue.key || selectedAsyncValue.key !== value) {
defHttp.get({ url: `/sys/dict/loadDictItem/${dict}`, params: { key: value } }).then((res) => {
if (res && res.length > 0) {
let obj = {
key: value,
label: res,
};
if (props.value == value) {
selectedAsyncValue.value = { ...obj };
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
//判断组件是否为多选
if(props.multiple){
if(value){
let arr: any = [];
//多选返回的是以逗号拼接的方式
let values = value.toString().split(',');
for (let i = 0; i < res.length; i++) {
let obj = {
key: values[i],
label: res[i],
};
arr.push(obj);
selectedValue.value.push(obj.key);
}
selectedAsyncValue.value = arr;
}
} else {
let obj = {
key: value,
label: res,
};
if (props.value == value) {
selectedAsyncValue.value = { ...obj };
}
//update-begin-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online关联记录配置页面
if(props.immediateChange == true){
emit('change', props.value);
}
//update-end-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online关联记录配置页面
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
}
//update-begin-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online关联记录配置页面
if(props.immediateChange == true){
emit('change', props.value);
}
//update-end-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online关联记录配置页面
}
});
}
} else {
selectedValue.value = value.toString();
//update-begin-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online他表字段配置界面
if(props.immediateChange == true){
emit('change', value.toString());
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
if(!props.multiple){
selectedValue.value = value.toString();
//update-begin-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online他表字段配置界面
if(props.immediateChange == true){
emit('change', value.toString());
}
//update-end-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online他表字段配置界面
}else{
//多选的情况下需要转成数组
selectedValue.value = value.toString().split(',');
}
//update-end-author:taoyan date:2022-8-11 for: 值改变触发change事件--用于online他表字段配置界面
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
}
}
@ -306,35 +346,100 @@
* 同步改变事件
* */
function handleChange(value) {
selectedValue.value = value;
callback();
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
//多选也会触发change事件需要判断如果时多选不需要赋值
if(!props.multiple){
selectedValue.value = value;
callback();
}
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
}
/**
* 异步改变事件
* */
function handleAsyncChange(selectedObj) {
if (selectedObj) {
selectedAsyncValue.value = selectedObj;
selectedValue.value = selectedObj.key;
} else {
selectedAsyncValue.value = null;
selectedValue.value = null;
options.value = null;
loadData('');
}
callback();
// update-begin--author:liaozhiyang---date:20240524---for【TV360X-426】下拉搜索设置了默认值把查询条件删掉再点击重置没附上值
// 点x清空时需要把loadSelectText设置true
selectedObj ?? (loadSelectText.value = true);
// update-end--author:liaozhiyang---date:20240524---for【TV360X-426】下拉搜索设置了默认值把查询条件删掉再点击重置没附上值
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
// 单选情况下使用change事件
if(!props.multiple){
if (selectedObj) {
selectedAsyncValue.value = selectedObj;
selectedValue.value = selectedObj.key;
} else {
selectedAsyncValue.value = null;
selectedValue.value = null;
options.value = null;
loadData('');
}
callback();
// update-begin--author:liaozhiyang---date:20240524---for【TV360X-426】下拉搜索设置了默认值把查询条件删掉再点击重置没附上值
// 点x清空时需要把loadSelectText设置true
selectedObj ?? (loadSelectText.value = true);
// update-end--author:liaozhiyang---date:20240524---for【TV360X-426】下拉搜索设置了默认值把查询条件删掉再点击重置没附上值
}
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
}
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
/**
* 异步值选中事件
* @param selectedObj
*/
function handleSelect(selectedObj){
let key = selectedObj;
if(props.async){
key = selectedObj.key;
}
//多选情况下使用select事件
if(props.multiple && key){
//异步的时候才需要在selectedValue数组中添加值操作同步的情况下直接走更新值操作
if(props.async){
selectedValue.value.push(key);
}
selectedObj ?? (loadSelectText.value = true);
callback();
}
}
/**
* 异步值取消选中事件
* @param selectedObj
*/
function handleDeSelect(selectedObj){
let key = selectedObj;
if(props.async){
key = selectedObj.key;
}
//多选情况下使用select事件
if(props.multiple){
//异步的时候才需要在selectedValue数组中删除值操作同步的情况下直接走更新值操作
if(props.async){
let findIndex = selectedValue.value.findIndex(item => item === key);
if(findIndex != -1){
selectedValue.value.splice(findIndex,1);
}
}
selectedObj ?? (loadSelectText.value = true);
callback();
}
}
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
/**
*回调方法
* */
function callback() {
loadSelectText.value = false;
emit('change', unref(selectedValue));
emit('update:value', unref(selectedValue));
//update-begin---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
//单选直接走更新值操作
if(!props.multiple){
emit('change', unref(selectedValue));
emit('update:value', unref(selectedValue));
} else {
//多选需要把数组转成字符串
emit('change', unref(selectedValue).join(","));
emit('update:value', unref(selectedValue).join(","));
}
//update-end---author:wangshuai---date:2025-04-17---for:【issues/8101】前端dict组件导致内存溢出问题搜索组件支持多选---
}
/**
* 过滤选中option
@ -461,6 +566,8 @@
handleAsyncChange,
handleAsyncFocus,
handlePopupScroll,
handleSelect,
handleDeSelect,
};
},
});

View File

@ -71,6 +71,11 @@
*/
watch(selectValues, () => {
if (selectValues) {
// update-begin--author:liaozhiyang---date:20250616---for【QQYUN-12869】通过部门选择用户组件必填状态下选择用户后点击重置后会出校验信息
if (props.value === undefined && selectValues.value?.length == 0) {
return;
}
// update-end--author:liaozhiyang---date:20250616---for【QQYUN-12869】通过部门选择用户组件必填状态下选择用户后点击重置后会出校验信息
state.value = selectValues.value;
}
});

View File

@ -28,8 +28,12 @@
></a-select>
</a-col>
<a-col v-if="showButton" class="right">
<a-button v-if="buttonIcon" :preIcon="buttonIcon" type="primary" @click="openModal(true)" :disabled="disabled">选择</a-button>
<a-button v-else type="primary" @click="openModal(true)" :disabled="disabled">选择</a-button>
<a-button v-if="buttonIcon" :preIcon="buttonIcon" type="primary" @click="openModal(true)" :disabled="disabled">
{{ buttonText }}
</a-button>
<a-button v-else type="primary" @click="openModal(true)" :disabled="disabled">
{{ buttonText }}
</a-button>
</a-col>
</a-row>
</div>
@ -46,6 +50,7 @@
inheritAttrs: false,
props: {
showButton: propTypes.bool.def(true),
buttonText: propTypes.string.def('选择'),
disabled: propTypes.bool.def(false),
placeholder: {
type: String,

View File

@ -156,7 +156,9 @@ export interface FormSchema {
// Required
required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
suffix?: string | number | ((values: RenderCallbackParams) => string | number);
suffix?: string | number | VueNode | ((values: RenderCallbackParams) => string | number | VueNode);
// 【QQYUN-12876】是否是紧凑型 suffix当组件宽度未占满时可紧挨着组件右侧
suffixCompact?: boolean;
// Validation rules
rules?: Rule[];
@ -164,7 +166,7 @@ export interface FormSchema {
rulesMessageJoinLabel?: boolean;
// Reference formModelItem
itemProps?: Partial<FormItem>;
itemProps?: Partial<FormItem> | ((renderCallbackParams: RenderCallbackParams) => Partial<FormItem>);
// col configuration outside formModelItem
colProps?: Partial<ColEx>;

View File

@ -157,5 +157,6 @@ export type ComponentType =
| 'linkRecordSelect'
| 'RangeTime'
| 'JRangeNumber'
| 'JLinkTableCard'
| 'JInputSelect';

View File

@ -8,6 +8,9 @@
:style="{ width }"
@click="currentSelectClick"
>
<template #suffix v-if="allowClear && currentSelect">
<CloseCircleFilled class="menu-current-close" @click.stop="clearCurrentSelect" />
</template>
<template #addonAfter>
<span class="cursor-pointer px-2 py-1 flex items-center" v-if="isSvgMode && currentSelect">
<SvgIcon :name="currentSelect" @click="currentSelectClick"/>
@ -77,7 +80,7 @@
import { useI18n } from '/@/hooks/web/useI18n';
import svgIcons from 'virtual:svg-icons-names';
import IconList from "./IconList.vue";
import { CloseCircleFilled } from '@ant-design/icons-vue';
// 没有使用别名引入是因为WebStorm当前版本还不能正确识别会报unused警告
const AInput = Input;
@ -104,6 +107,7 @@
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'),
disabled: propTypes.bool.def(false),
clearSelect: propTypes.bool.def(false),
allowClear: propTypes.bool.def(false),
iconPrefixSave: propTypes.bool.def(true),
});
@ -196,6 +200,12 @@
iconOpen.value = false;
}
/**
* 清除当前选择图标
*/
function clearCurrentSelect(){
currentSelect.value = '';
}
onMounted(()=>{
//初始化加载图标
initOtherIcon();
@ -227,5 +237,16 @@
height: 220px;
}
}
//图标样式
.menu-current-close {
color: #cccccc;
}
}
//图标样式兼容暗黑模式
[data-theme='dark'] .@{prefix-cls} {
.menu-current-close {
color: #4f4f4f;
font-size: 12px;
}
}
</style>

View File

@ -0,0 +1,54 @@
<template>
<div>
<keep-alive>
<component
v-if="currentModal"
v-bind="bindParams"
:key="currentModal"
:is="currentModal"
@register="modalRegCache[currentModal].register"
@reply="handReply"
@selected="reloadPage"
/>
</keep-alive>
<!-- 系统公告弹窗 -->
<DynamicNotice ref="showDynamNotice" v-bind="bindParams" />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import { useDragNotice } from '/@/hooks/web/useDragNotice';
import DynamicNotice from '@/views/monitor/mynews/DynamicNotice.vue';
export default defineComponent({
name: 'JDragNotice',
components: {
DynamicNotice,
},
setup() {
const {
initDragWebSocket,
currentModal,
modalParams,
modalRegCache,
bindParams,
reloadPage,
} = useDragNotice();
onMounted(() => {
initDragWebSocket();
});
return {
currentModal,
modalParams,
modalRegCache,
bindParams,
reloadPage,
};
},
});
</script>
<style scoped lang="less"></style>

View File

@ -13,6 +13,7 @@
import { getTenantId, getToken } from '/@/utils/auth';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { uploadFile } from '@/api/common/api';
import {$electron} from "@/electron";
type Lang = 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' | undefined;
@ -109,6 +110,13 @@
function init() {
const wrapEl = unref(wrapRef) as HTMLElement;
if (!wrapEl) return;
// vditor组件本地化的路径配置【QQYUN-12053】
let localCdn = '/resource/vditor@3.9.4';
if ($electron.isElectron()) {
localCdn = '.' + localCdn;
}
const bindValue = { ...attrs, ...props };
const insEditor = new Vditor(wrapEl, {
theme: getDarkMode.value === 'dark' ? 'dark' : 'classic',
@ -151,8 +159,8 @@
],
// update-end--author:liaozhiyang---date:20240520---for【TV360X-146】Markdown组件去掉录音选项
mode: 'sv',
// cdn: 'https://cdn.jsdelivr.net/npm/vditor@3.9.6',
cdn: 'https://unpkg.com/vditor@3.10.1',
cdn: 'https://unpkg.com/vditor@3.10.8',
//cdn: localCdn,
fullscreen: {
index: 520,
},

View File

@ -17,7 +17,7 @@
{{ t('component.table.settingColumnShow') }}
</Checkbox>
<Checkbox v-model:checked="checkIndex" @change="handleIndexCheckChange">
<Checkbox :disabled="isTreeTable" v-model:checked="checkIndex" @change="handleIndexCheckChange">
{{ t('component.table.settingIndexColumnShow') }}
</Checkbox>
@ -143,6 +143,9 @@
setup(props, { emit, attrs }) {
const { t } = useI18n();
const table = useTableContext();
// update-begin--author:liaozhiyang---date:20250526---for【issues/8301】树形表格序号列禁用
const isTreeTable = computed(() => table.getBindValues.value.isTreeTable);
// update-end--author:liaozhiyang---date:20250526---for【issues/8301】树形表格序号列禁用
const popoverVisible = ref(false);
// update-begin--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
// nextTick(() => popoverVisible.value = false);
@ -479,6 +482,7 @@
defaultRowSelection,
handleColumnFixed,
getPopupContainer,
isTreeTable,
};
},
});

View File

@ -140,7 +140,12 @@ export function useCustomSelection(
// 解决selectedRowKeys在页面调用处使用ref失效
const value = unref(val);
if (Array.isArray(value) && !sameArray(value, selectedKeys.value)) {
setSelectedRowKeys(value);
// update-begin--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
// 延迟是为了等watch selectedRows
setTimeout(() => {
setSelectedRowKeys(value);
}, 0);
// update-end--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
}
},
{
@ -149,7 +154,22 @@ export function useCustomSelection(
}
);
// update-end--author:liaozhiyang---date:20240306---for【QQYUN-8390】部门人员组件点击重置未清空selectedRowKeys.value=[]watch没监听到加deep
// update-begin--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
// 编辑时selectedRows可能会回填
watch(
() => unref(propsRef)?.rowSelection?.selectedRows,
(val: string[]) => {
const value: any = unref(val);
if (Array.isArray(value) && !sameArray(value, selectedRows.value)) {
selectedRows.value = value;
}
},
{
immediate: true,
deep: true,
}
);
// update-end--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
/**
* 2024-03-06
* liaozhiyang
@ -581,7 +601,12 @@ export function useCustomSelection(
// 通过 selectedKeys 同步 selectedRows
function syncSelectedRows() {
if (selectedKeys.value.length !== selectedRows.value.length) {
setSelectedRowKeys(selectedKeys.value);
// update-begin--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
// 延迟是为了等watch selectedRows
setTimeout(() => {
setSelectedRowKeys(selectedKeys.value);
}, 0);
// update-end--author:liaozhiyang---date:20250429---for【issues/8163】关联记录夸页数据丢失
}
}

View File

@ -146,25 +146,27 @@ export function useTableScroll(
bodyEl!.style.height = `${height}px`;
// update-begin--author:liaozhiyang---date:20240609---for【issues/8374】分页始终显示在底部
if (maxHeight === undefined) {
if (unref(getPaginationInfo) && unref(getDataSourceRef).length) {
const pageSize = unref(getPaginationInfo)?.pageSize;
const current = unref(getPaginationInfo)?.current;
const total = unref(getPaginationInfo)?.total;
const tableBody = tableEl.querySelector('.ant-table-body') as HTMLElement;
const tr = tableEl.querySelector('.ant-table-tbody')?.children ?? [];
const lastrEl = tr[tr.length - 1] as HTMLElement;
const trHeight = lastrEl.offsetHeight;
const dataHeight = trHeight * pageSize;
if (tableBody && lastrEl) {
if (current === 1 && pageSize > unref(getDataSourceRef).length && total <= pageSize) {
tableBody.style.height = `${height}px`;
} else {
tableBody.style.height = `${dataHeight < height ? dataHeight : height}px`;
nextTick(() => {
if (maxHeight === undefined) {
if (unref(getPaginationInfo) && unref(getDataSourceRef).length) {
const pageSize = unref(getPaginationInfo)?.pageSize;
const current = unref(getPaginationInfo)?.current;
const total = unref(getPaginationInfo)?.total;
const tableBody = tableEl.querySelector('.ant-table-body') as HTMLElement;
const tr = tableEl.querySelector('.ant-table-tbody')?.children ?? [];
const lastrEl = tr[tr.length - 1] as HTMLElement;
const trHeight = lastrEl.offsetHeight;
const dataHeight = trHeight * pageSize;
if (tableBody && lastrEl) {
if (current === 1 && pageSize > unref(getDataSourceRef).length && total <= pageSize) {
tableBody.style.height = `${height}px`;
} else {
tableBody.style.height = `${dataHeight < height ? dataHeight : height}px`;
}
}
}
}
}
});
// update-end--author:liaozhiyang---date:20240609---for【issues/8374】分页始终显示在底部
}
useWindowSizeFn(calcTableHeight, 280);

View File

@ -38,6 +38,8 @@ export interface TableRowSelection<T = any> extends ITableRowSelection {
* @type Function
*/
onSelectInvert?: (selectedRows: string[] | number[]) => any;
//【issues/8163】关联记录新增丢失
selectedRows?: any[];
}
export interface TableCustomRecord<T> {