v3.14.0 更新;【新增】EasyExcel重磅升级为FastExcel;【新增】使用最强Argon2算法作为密码存储;【新增】大家吐槽的数据字典改为可重复;【新增】前端布局再增加多种样式;

This commit is contained in:
zhuoda
2025-03-12 21:30:24 +08:00
parent e74f179a91
commit fecb3a9d81
207 changed files with 4260 additions and 2019 deletions

View File

@@ -0,0 +1,28 @@
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="values.includes(item.valueCode)">
{{ item.valueName }}
<span> </span>
</template>
</template>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
// 数据
options: {
type: Array,
default: null,
},
// 当前的值
value: [Number, String, Array],
});
const values = computed(() => {
if (props.value === null || typeof props.value === 'undefined' || props.value === '') return [];
return Array.isArray(props.value) ? props.value.map((item) => item.valueCode) : props.value.split(',');
});
</script>

View File

@@ -9,7 +9,11 @@
*
-->
<template>
<a-checkbox-group :style="`width: ${width}`" v-model:value="selectValue" :options="optionList" @change="handleChange" />
<a-checkbox-group :style="`width: ${width}`" v-model:value="selectValue" @change="handleChange" :disabled="disabled">
<a-checkbox v-for="item in valueDescList" :key="item.value" :value="item.value" :disabled="disabledOption.includes(item.value)">
{{ item.desc }}
</a-checkbox>
</a-checkbox-group>
</template>
<script setup>
@@ -22,19 +26,32 @@
type: String,
default: '200px',
},
// 禁用整个多选框
disabled: {
type: Boolean,
default: false,
},
// 需要禁用的选项枚举值
disabledOption: {
type: Array,
default: () => [],
},
// 需要隐藏的选项枚举值
hiddenOption: {
type: Array,
default: () => [],
},
});
// ------------ 枚举数据 加载和构建 ------------
const optionList = ref([]);
function buildOptionList() {
const valueDescList = ref([]);
onMounted(() => {
const internalInstance = getCurrentInstance(); // 有效 全局
const smartEnumPlugin = internalInstance.appContext.config.globalProperties.$smartEnumPlugin;
const valueList = smartEnumPlugin.getValueDescList(props.enumName);
optionList.value = valueList.map((e) => Object.assign({}, { value: e.value, label: e.desc }));
}
onMounted(buildOptionList);
valueDescList.value = smartEnumPlugin.getValueDescList(props.enumName).filter((item) => !props.hiddenOption.includes(item.value));
});
// ------------ 数据选中 事件及其相关 ------------
@@ -43,11 +60,14 @@
watch(
() => props.value,
(newValue) => {
selectValue.value = newValue;
}
// 如果传入的值是被禁用或被隐藏的选项,则移除这些选项
selectValue.value = newValue.filter((item) => !props.hiddenOption.includes(item) && !props.disabledOption.includes(item));
},
{ immediate: true }
);
const emit = defineEmits(['update:value', 'change']);
function handleChange(value) {
emit('update:value', value);
emit('change', value);

View File

@@ -10,15 +10,15 @@
-->
<template>
<template v-if="isButton">
<a-radio-group v-model:value="selectValue" @change="handleChange" button-style="solid">
<a-radio-button v-for="item in $smartEnumPlugin.getValueDescList(props.enumName)" :key="item.value" :value="item.value">
<a-radio-group v-model:value="selectValue" @change="handleChange" button-style="solid" :disabled="disabled">
<a-radio-button v-for="item in valueDescList" :key="item.value" :value="item.value" :disabled="disabledOption.includes(item.value)">
{{ item.desc }}
</a-radio-button>
</a-radio-group>
</template>
<template v-else>
<a-radio-group v-model:value="selectValue" @change="handleChange">
<a-radio v-for="item in $smartEnumPlugin.getValueDescList(props.enumName)" :key="item.value" :value="item.value">
<a-radio-group v-model:value="selectValue" @change="handleChange" :disabled="disabled">
<a-radio v-for="item in valueDescList" :key="item.value" :value="item.value" :disabled="disabledOption.includes(item.value)">
{{ item.desc }}
</a-radio>
</a-radio-group>
@@ -26,7 +26,7 @@
</template>
<script setup>
import { ref, watch } from 'vue';
import { ref, watch, onMounted, getCurrentInstance } from 'vue';
const props = defineProps({
enumName: String,
@@ -43,19 +43,44 @@
type: Boolean,
default: false,
},
// 禁用整个单选框
disabled: {
type: Boolean,
default: false,
},
// 需要禁用的选项枚举值
disabledOption: {
type: Array,
default: () => [],
},
// 需要隐藏的选项枚举值
hiddenOption: {
type: Array,
default: () => [],
},
});
const emit = defineEmits(['update:value', 'change']);
const valueDescList = ref([]);
onMounted(() => {
const internalInstance = getCurrentInstance(); // 有效 全局
const smartEnumPlugin = internalInstance.appContext.config.globalProperties.$smartEnumPlugin;
valueDescList.value = smartEnumPlugin.getValueDescList(props.enumName).filter((item) => !props.hiddenOption.includes(item.value));
});
const selectValue = ref(props.value);
watch(
() => props.value,
(newValue) => {
selectValue.value = newValue;
}
// 如果传入的值是被禁用或被隐藏的选项,则移除该选项
selectValue.value = props.disabledOption.includes(newValue) || props.hiddenOption.includes(newValue) ? undefined : newValue;
},
{ immediate: true }
);
const emit = defineEmits(['update:value', 'change']);
function handleChange(e) {
emit('update:value', e.target.value);
emit('change', e.target.value);

View File

@@ -19,18 +19,18 @@
@change="handleChange"
:disabled="disabled"
>
<a-select-option v-for="item in $smartEnumPlugin.getValueDescList(props.enumName)" :key="item.value" :value="item.value">
<a-select-option v-for="item in valueDescList" :key="item.value" :value="item.value" :disabled="disabledOption.includes(item.value)">
{{ item.desc }}
</a-select-option>
</a-select>
</template>
<script setup>
import { ref, watch } from 'vue';
import { ref, watch, onMounted, getCurrentInstance } from 'vue';
const props = defineProps({
enumName: String,
value: [Number,String],
value: [Number, String],
width: {
type: String,
default: '100%',
@@ -43,23 +43,44 @@
type: String,
default: 'default',
},
// 禁用整个下拉选择框
disabled: {
type: Boolean,
default: false,
},
// 需要禁用的选项枚举值
disabledOption: {
type: Array,
default: () => [],
},
// 需要隐藏的选项枚举值
hiddenOption: {
type: Array,
default: () => [],
},
});
const emit = defineEmits(['update:value', 'change']);
const valueDescList = ref([]);
onMounted(() => {
const internalInstance = getCurrentInstance(); // 有效 全局
const smartEnumPlugin = internalInstance.appContext.config.globalProperties.$smartEnumPlugin;
valueDescList.value = smartEnumPlugin.getValueDescList(props.enumName).filter((item) => !props.hiddenOption.includes(item.value));
});
const selectValue = ref(props.value);
watch(
() => props.value,
(newValue) => {
selectValue.value = newValue;
}
// 如果传入的值是被禁用或被隐藏的选项,则移除该选项
selectValue.value = props.disabledOption.includes(newValue) || props.hiddenOption.includes(newValue) ? undefined : newValue;
},
{ immediate: true }
);
const emit = defineEmits(['update:value', 'change']);
function handleChange(value) {
emit('update:value', value);
emit('change', value);

View File

@@ -99,10 +99,20 @@
getHtml,
getText,
});
</script>
<style scoped>
.w-e-full-screen-container {
z-index: 9999 !important;
}
</style>
<!-- 解决弹窗高度警告信息显示 -->
<style>
::v-deep .w-e-text-container {
height: 420px !important;
}
.w-e-text-container .w-e-scroll {
height: 500px !important;
-webkit-overflow-scrolling: touch;
}
</style>

View File

@@ -0,0 +1,38 @@
<template>
<CopyOutlined
@click="copy"
:style="{
color: `${color}`,
}"
class="icon"
/>
</template>
<script setup>
import { message } from 'ant-design-vue';
const props = defineProps({
value: {
type: [String, Number],
default: '',
},
color: {
type: String,
default: '#1890ff',
},
});
function copy() {
const textarea = document.createElement('textarea');
textarea.value = props.value;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
message.success('复制成功');
}
</script>
<style scoped lang="less">
.icon {
margin: 0 10px;
}
</style>

View File

@@ -0,0 +1,178 @@
<template>
<div class="container">
<div class="table-title">
<slot name="title">
{{ column.title }}
</slot>
</div>
<div class="filter" style="max-width: 300px; min-height: 40px">
<slot>
<template v-if="column.filterOptions">
<template v-if="column.filterOptions.type === 'input'">
<a-input-search
@change="change('no-search')"
v-model:value="modelValue"
allowClear
:placeholder="column.placeholder || column.title"
@search="change"
/>
</template>
<template v-else-if="column.filterOptions.type === 'date-range'">
<a-range-picker
v-model:value="createDateRange"
:ranges="column.filterOptions.ranges ? defaultTimeRanges : []"
style="width: 100%"
@change="changeCreateDate"
/>
</template>
<template v-else-if="column.filterOptions.type === 'datetime-range'">
<a-range-picker
show-time
v-model:value="createDateRange"
:ranges="column.filterOptions.ranges ? defaultTimeRanges : []"
style="width: 100%"
@change="changeCreateDate"
/>
</template>
<template v-else-if="column.filterOptions.type === 'month'">
<a-range-picker v-model:value="createDateRange" picker="month" @change="changeCreateDate" />
</template>
<template v-else-if="column.filterOptions.type === 'submit'">
<div class="smart-table-operate"><a-button :type="column.filterOptions.btnType" @click="submit">查询</a-button></div>
</template>
<template v-else>
<component
v-if="componentsKey.includes(column.filterOptions.type)"
:is="getComponent(column.filterOptions.type)"
width="100%"
v-model:value="modelValue"
:multiple="column.filterOptions.multiple"
:keyCode="column.filterOptions.keyCode"
:enumName="column.filterOptions.enumName"
:systemConfigKey="column.filterOptions.systemConfigKey"
:placeholder="column.placeholder"
:leaveFlag="column.filterOptions.leaveFlag"
:categoryType="column.filterOptions.categoryType"
@change="change"
/>
<div v-else class="error-component">未定义的组件类型</div>
</template>
</template>
</slot>
</div>
</div>
</template>
<script setup>
import { ref, useSlots, watch, onMounted, defineAsyncComponent } from 'vue';
import dayjs from 'dayjs';
import _ from 'lodash';
import { defaultTimeRanges } from '/@/lib/default-time-ranges';
const props = defineProps({
value: {
type: [Number, String, Array, Object],
},
column: {
type: Object,
default: () => {},
},
});
const components = {
'enum-select': defineAsyncComponent(() => import('/@/components/framework/smart-enum-select/index.vue')),
'dict-select': defineAsyncComponent(() => import('/@/components/support/dict-select/index.vue')),
'employee-select': defineAsyncComponent(() => import('/@/components/system/employee-select/index.vue')),
'enterprise-select': defineAsyncComponent(() => import('/@/components/business/oa/enterprise-select/index.vue')),
'boolean-select': defineAsyncComponent(() => import('/@/components/framework/boolean-select/index.vue')),
'category-tree': defineAsyncComponent(() => import('/@/components/business/category-tree-select/index.vue')),
};
const componentsKey = Object.keys(components);
function getComponent(key) {
return components[key];
}
watch(
() => props.value,
() => {
if (props.column.filterOptions && (props.column.filterOptions.type === 'date-range' || props.column.filterOptions.type === 'datetime-range')) {
if (!_.isEmpty(props.value) && props.value.length === 2 && !_.isEmpty(props.value[0]) && !_.isEmpty(props.value[1])) {
createDateRange.value = [dayjs(props.value[0]), dayjs(props.value[1])];
} else {
createDateRange.value = [];
}
} else {
modelValue.value = props.value;
}
}
);
const slots = useSlots();
const emits = defineEmits(['change', 'update:value']);
const createDateRange = ref([]);
const modelValue = ref(undefined);
function changeCreateDate(dates, dateStrings) {
// emits('update:value',dates)
emits('change', {
type: props.column.filterOptions.type,
key: props.column.filterOptions.key || props.column.dataIndex,
value: [dateStrings[0], dateStrings[1]],
search: true,
});
}
//是否立即查询
function change(search) {
let isSearch = true;
if (search === 'no-search') {
isSearch = false;
}
emits('update:value', modelValue.value);
emits('change', {
type: props.column.filterOptions.type,
key: props.column.filterOptions.key || props.column.dataIndex,
value: modelValue.value,
search: isSearch,
});
}
function submit() {
emits('change', {
search: true,
});
}
onMounted(() => {
if (props.column.filterOptions && (props.column.filterOptions.type === 'date-range' || props.column.filterOptions.type === 'datetime-range')) {
if (!_.isEmpty(props.value) && props.value.length === 2 && !_.isEmpty(props.value[0]) && !_.isEmpty(props.value[1])) {
createDateRange.value = [dayjs(props.value[0]), dayjs(props.value[1])];
} else {
createDateRange.value = [];
}
} else {
modelValue.value = props.value;
}
});
</script>
<style scoped lang="less">
.container {
overflow: hidden;
}
.table-title {
border-bottom: 1px solid #f0f0f0;
}
.filter {
padding-top: 8px;
}
.error-component {
color: red;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@@ -18,6 +18,7 @@
:allowClear="true"
:size="size"
@change="onChange"
:disabled="disabled"
>
<a-select-option v-for="item in dictKeyCodeList" :key="item.keyCode" :value="item.keyCode">
{{ item.keyName }}
@@ -27,7 +28,7 @@
</template>
<script setup>
import { computed, onMounted, ref, watch, defineExpose } from 'vue';
import { onMounted, ref, watch } from 'vue';
import { dictApi } from '/@/api/support/dict-api';
defineExpose({
@@ -49,7 +50,7 @@
default: 'default',
},
// 禁用标识
disabledFlag: {
disabled: {
type: Number,
default: null,
},

View File

@@ -20,7 +20,12 @@
@change="onChange"
:disabled="disabled"
>
<a-select-option v-for="item in dictValueList" :key="item.valueCode" :value="item.valueCode">
<a-select-option
v-for="item in dictValueList"
:key="item.valueCode"
:value="item.valueCode"
:disabled="disabledOption.includes(item.valueCode)"
>
{{ item.valueName }}
</a-select-option>
</a-select>
@@ -28,7 +33,7 @@
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue';
import { onMounted, ref, watch } from 'vue';
import { dictApi } from '/@/api/support/dict-api';
const props = defineProps({
@@ -50,10 +55,21 @@
type: String,
default: 'default',
},
// 禁用整个下拉选择框
disabled: {
type: Boolean,
default: false,
},
// 需要禁用的选项字典值编码
disabledOption: {
type: Array,
default: () => [],
},
// 需要隐藏的选项字典值编码
hiddenOption: {
type: Array,
default: () => [],
},
});
// -------------------------- 查询 字典数据 --------------------------
@@ -61,7 +77,7 @@
const dictValueList = ref([]);
async function queryDict() {
let res = await dictApi.valueList(props.keyCode);
dictValueList.value = res.data;
dictValueList.value = res.data.filter((item) => !props.hiddenOption.includes(item.valueCode));
}
onMounted(queryDict);
@@ -69,26 +85,24 @@
// -------------------------- 选中 相关、事件 --------------------------
const selectValue = ref(props.value);
watch(
() => props.value,
(value) => {
selectValue.value = value;
}
(newValue) => {
// 如果传入的值是被禁用或被隐藏的选项,则移除这些选项
if (Array.isArray(newValue)) {
selectValue.value = newValue.filter((item) => !props.disabledOption.includes(item) && !props.hiddenOption.includes(item));
} else {
selectValue.value = props.hiddenOption.includes(newValue) || props.disabledOption.includes(newValue) ? undefined : newValue;
}
},
{ immediate: true }
);
const emit = defineEmits(['update:value', 'change']);
function onChange(value) {
if (!value) {
emit('update:value', []);
emit('change', []);
return;
}
if (Array.isArray(value)) {
emit('update:value', value);
emit('change', value);
} else {
emit('update:value', value);
emit('change', value);
}
emit('update:value', value);
emit('change', value);
}
</script>

View File

@@ -11,12 +11,12 @@
<template>
<div class="clearfix">
<a-upload
multiple
:multiple="props.multiple"
:accept="props.accept"
:before-upload="beforeUpload"
:customRequest="customRequest"
:file-list="fileList"
:headers="{ 'x-access-token': useUserStore().getToken }"
:headers="{ Authorization: 'Bearer ' + useUserStore().getToken }"
:list-type="listType"
@change="handleChange"
@preview="handlePreview"

View File

@@ -38,7 +38,7 @@
<script setup>
import _ from 'lodash';
import { tableColumnApi } from '/@/api/support/table-column-api';
import { onMounted, ref, watch } from 'vue';
import { onMounted, ref, watch, reactive } from 'vue';
import SmartTableColumnModal from './smart-table-column-modal.vue';
import { message } from 'ant-design-vue';
import { mergeColumn } from './smart-table-column-merge';
@@ -66,8 +66,16 @@
const emit = defineEmits(['update:modelValue']);
// 原始表格列数据复制一份最原始的columns集合以供后续各个地方使用
let originalColumn = _.cloneDeep(props.modelValue);
let originalColumn = reactive(_.cloneDeep(props.modelValue));
watch(
() => props.modelValue,
(value) => {
originalColumn = value;
},
{
deep: true,
}
);
onMounted(buildUserTableColumns);
//构建用户的数据列
@@ -168,7 +176,8 @@
// 将弹窗修改的列数据,赋值给原表格 列数组
function updateColumn(changeColumnArray) {
//合并列
const newColumns = mergeColumn(_.cloneDeep(originalColumn), changeColumnArray);
let obj = mergeColumn(_.cloneDeep(originalColumn), changeColumnArray);
const newColumns = obj.newColumns;
emit(
'update:modelValue',
newColumns.filter((e) => e.showFlag)

View File

@@ -1,12 +1,12 @@
/*
* 表格列设置
*
* @Author: 1024创新实验室-主任:卓大
* @Date: 2022-08-26 23:45:51
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
/*
* 表格列设置
*
* @Author: 1024创新实验室-主任:卓大
* @Date: 2022-08-26 23:45:51
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
*/
import _ from 'lodash';
@@ -16,6 +16,7 @@ import _ from 'lodash';
* @param {*} userTableColumnArray
*/
export function mergeColumn(originalTableColumnArray, userTableColumnArray) {
let saveFlag = false;
if (!userTableColumnArray) {
return originalTableColumnArray;
}
@@ -40,8 +41,13 @@ export function mergeColumn(originalTableColumnArray, userTableColumnArray) {
if (userColumn) {
fontColumn.sort = userColumn.sort;
fontColumn.showFlag = userColumn.showFlag;
if (userColumn.width) {
fontColumn.width = userColumn.width;
if (fontColumn.dragAndDropFlag) {
saveFlag = true;
delete fontColumn.dragAndDropFlag;
} else {
if (userColumn.width) {
fontColumn.width = userColumn.width;
}
}
}
newColumns.push(fontColumn);
@@ -50,5 +56,8 @@ export function mergeColumn(originalTableColumnArray, userTableColumnArray) {
//第三步:前端列进行排序
newColumns = _.sortBy(newColumns, (e) => e.sort);
return newColumns;
return {
newColumns,
saveFlag,
};
}

View File

@@ -9,46 +9,70 @@
*
-->
<template>
<a-modal :width="700" :open="visible" title="设置列" :destroyOnClose="true" :closable="false">
<a-alert type="info" show-icon class="smart-margin-bottom10">
<template #icon><smile-outlined /></template>
<template #message> 可以通过拖拽行直接修改顺序哦 <pushpin-outlined />为固定列不可拖拽 </template>
</a-alert>
<a-table
id="smartTableColumnModalTable"
rowKey="columnKey"
row-class-name="column-row"
:columns="tableColumns"
:dataSource="tableData"
:rowSelection="{ checkStrictly: false, selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
:pagination="false"
size="small"
bordered
>
<template #bodyCell="{ text, record, index, column }">
<template v-if="column.dataIndex === 'title'">
<a-button type="text" :class="record.fixed ? '' : 'handle'" size="small" style="width: 100%; text-align: left">
<template #icon v-if="!record.fixed"> <drag-outlined /> </template>
<template #icon v-if="record.fixed"> <pushpin-outlined /> </template>
{{ text }}
</a-button>
<a-modal :width="800" :open="visible" title="设置列" :destroyOnClose="true" :closable="false">
<div v-if="!tableId">
<a-alert type="error" show-icon class="smart-margin-bottom10">
<template #message> 您尚未设置 TableOperator 组件的 tableId</template>
</a-alert>
<a-alert type="error" class="smart-margin-bottom10">
<template #message>
1. 请在 src\constants\support\table-id-const.js 中配置 tableId 常量
<br />
<br />
2. 在自己的业务表格页面组件中使用如下
<br />
导入: import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
<br />
使用: {{ '<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.XXX" :refresh="queryData" />' }}
<br />
<br />
3. 具体用法可参考员工管理
</template>
<template v-if="column.dataIndex === 'width'">
<a-input-number v-model:value="record.width" style="width: 90px; margin-left: 10px; margin-right: 3px" size="small" />px
</a-alert>
</div>
<div v-else>
<a-alert type="info" show-icon class="smart-margin-bottom10">
<template #icon><smile-outlined /></template>
<template #message> 可以通过拖拽行直接修改顺序哦 <pushpin-outlined />为固定列不可拖拽 </template>
</a-alert>
<a-table
id="smartTableColumnModalTable"
rowKey="columnKey"
row-class-name="column-row"
:columns="tableColumns"
:dataSource="tableData"
:rowSelection="{ checkStrictly: false, selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
:pagination="false"
size="small"
bordered
>
<template #bodyCell="{ text, record, index, column }">
<template v-if="column.dataIndex === 'title'">
<a-button type="text" :class="record.fixed ? '' : 'handle'" size="small" style="width: 100%; text-align: left">
<template #icon>
<drag-outlined v-if="!record.fixed" />
<pushpin-outlined v-else />
</template>
{{ text }}
</a-button>
</template>
<template v-if="column.dataIndex === 'width'">
<a-input-number v-model:value="record.width" style="width: 90px; margin-left: 10px; margin-right: 3px" size="small" />px
</template>
<template v-if="column.dataIndex === 'operate'">
<div class="smart-table-operate" v-if="!record.fixed">
<a-button @click="up(index)" v-show="index > 0" type="link" class="handle" size="small" style="margin-right: 12px"> 上移 </a-button>
<a-button @click="down(index)" type="link" class="handle" size="small" v-show="index !== tableData.length - 1"> 下移</a-button>
</div>
</template>
</template>
<template v-if="column.dataIndex === 'operate'">
<div class="smart-table-operate" v-if="!record.fixed">
<a-button @click="up(index)" v-show="index > 0" type="link" class="handle" size="small" style="margin-right: 12px"> 上移 </a-button>
<a-button @click="down(index)" type="link" class="handle" size="small" v-show="index !== tableData.length - 1"> 下移</a-button>
</div>
</template>
</template>
</a-table>
</a-table>
</div>
<template #footer>
<a-button key="back" @click="hide">取消</a-button>
<a-button key="submit" type="primary" :loading="submitLoading" @click="save">保存</a-button>
<a-button key="back" :loading="submitLoading" @click="reset" danger style="margin-left: 20px">恢复默认</a-button>
<a-button v-if="tableId" key="submit" type="primary" :loading="submitLoading" @click="save">保存</a-button>
<a-button v-if="tableId" key="back" :loading="submitLoading" @click="reset" danger style="margin-left: 20px">恢复默认</a-button>
</template>
</a-modal>
</template>
@@ -67,7 +91,7 @@
defineExpose({ show });
// ---------------- 显示 / 隐藏 --------------------
let tableId = 1;
let tableId = null;
const visible = ref(false);
//显示
function show(columns, showTableId) {
@@ -80,9 +104,12 @@
function hide() {
visible.value = false;
}
const saveFlag = ref(false);
//获取用户的列数据
async function getUserTableColumns(tableId, columns) {
if (!tableId) {
return;
}
SmartLoading.show();
let userTableColumnArray = [];
try {
@@ -101,14 +128,18 @@
}
//根据前端列和后端列构建新的列数据
tableData.value = mergeColumn(columns, userTableColumnArray);
let obj = mergeColumn(columns, userTableColumnArray);
tableData.value = obj.newColumns;
saveFlag.value = obj.saveFlag;
//将已经显示的展示出来
for (const item of tableData.value) {
if (item.showFlag) {
selectedRowKeyList.value.push(item.columnKey);
}
}
if (saveFlag.value) {
save(false);
}
nextTick(() => {
initDrag();
@@ -226,7 +257,7 @@
}
//保存
async function save() {
async function save(closeFlag = true) {
submitLoading.value = true;
try {
let columnList = [];
@@ -250,9 +281,11 @@
columnList,
});
message.success('保存成功');
emit('change', columnList);
hide();
if (closeFlag) {
message.success('保存成功');
hide();
}
} catch (e) {
smartSentry.captureError(e);
} finally {

View File

@@ -0,0 +1,77 @@
<template>
<div :class="className">
<div v-if="overflow" class="ellipsis-box">
<a-popover>
<template #content>
{{ text }}
<SmartCopyIcon :value="text" />
</template>
<div>
<slot>
{{ text }}
</slot>
</div>
</a-popover>
</div>
<div v-else>
<slot>
{{ text }}
</slot>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, nextTick } from 'vue';
import { Modal } from 'ant-design-vue';
import { v4 as uuid } from 'uuid';
import SmartCopyIcon from '/@/components/smart-copy-icon/index.vue';
const props = defineProps({
text: {
type: String,
default: '',
},
classKey: {
type: String,
default: '',
},
});
const overflow = ref(false);
const className = ref();
onMounted(() => {
className.value = props.classKey + uuid();
nextTick(() => {
let doc = document.querySelector(`.${className.value}`);
let fontSize = window.getComputedStyle(doc).fontSize.replace('px', '');
let clientWidth = doc.clientWidth;
let span = document.createElement('span');
document.body.appendChild(span);
span.style.fontSize = `${fontSize}px`;
span.innerText = props.text;
let width = span.offsetWidth;
document.body.removeChild(span);
overflow.value = width > clientWidth;
});
});
function showModel() {
Modal.info({
content: props.text,
icon: '',
okText: '关闭',
});
}
</script>
<style lang="less" scoped>
.ellipsis-box {
display: flex;
align-items: center;
div {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
}
</style>