Compare commits
11 Commits
d1189bcae9
...
deploy-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6202151242 | ||
|
|
ad9a43a7c6 | ||
|
|
57b55b5f82 | ||
|
|
ca0ebf33f7 | ||
| 0585818abf | |||
|
|
9dfc3173ac | ||
|
|
7690f72636 | ||
|
|
211b013084 | ||
| a94531bd57 | |||
| 7802223799 | |||
|
|
e648da4b6e |
65
README.md
@@ -26,68 +26,3 @@ Run `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
||||
4. Open the VSCode command palette
|
||||
5. Search and run "Select TypeScript version" -> "Use workspace version"
|
||||
test
|
||||
#### 目录结构
|
||||
|-- build 构建相关
|
||||
|-- hx-ai-intelligent AI智能BSA系统
|
||||
|-- mock 定义模拟数据(登录/登出/获取用户信息等)
|
||||
|-- public 静态资源
|
||||
|-- resources 资源文件
|
||||
|-- src
|
||||
|-- api 定义接口请求地址
|
||||
|-- components 当前项目的公共组件
|
||||
|-- ns-modal-form.vue 经过二次封装后的“弹窗”通用组件
|
||||
|-- ns-steps.vue 经过二次封装后的“步骤条”通用组件
|
||||
|-- config 配置文件
|
||||
|-- app.config.ts(包含应用程序配置的对象,包含api路径/组件配置等)
|
||||
|-- directives 自定义指令(在vue应用程序中设置全局指令)
|
||||
|-- enum 枚举(用于http请求配置和错误代码的处理)
|
||||
|-- icon 图标(svg图标文件)
|
||||
|-- router 路由
|
||||
|-- store 状态管理
|
||||
|-- theme 主题样式(less/scss)文件
|
||||
|-- util 工具类
|
||||
|-- debounce.ts 防抖函数(用于优化频繁出发的事件处理函数,例如窗口大小改变/滚动事件等)
|
||||
|-- view 页面
|
||||
|-- App.vue 根组件
|
||||
|-- .env.development 当前项目开发环境配置
|
||||
|-- .env.production 当前项目生产环境配置
|
||||
|-- index.html 当前项目入口页
|
||||
|-- tsconfig.json typescript配置
|
||||
|-- vite.config.ts vite配置(包含当前项目请求接口地址)
|
||||
|-- lib
|
||||
|-- component 公共组件(color/drawer/echarts/flowChart/form/modal/table/tree等组件的二次封装或将组件注册为插件形式使用)
|
||||
|-- paas 私有组件
|
||||
|-- saas 私有组件
|
||||
|-- type 类型定义
|
||||
|-- use 自定义hook文件
|
||||
|-- util (http/axios等工具类)
|
||||
|-- node_modules 依赖包
|
||||
|-- public 静态资源(不会被编译)
|
||||
|-- src
|
||||
|-- main.ts 入口文件(初始化saasInit函数的相关配置或服务的入口点。)
|
||||
|-- type 声明定义应用程序的全局类型
|
||||
|-- .env.development 开发环境配置
|
||||
|-- .env.production 生产环境配置
|
||||
|-- index.html 项目入口文件
|
||||
|-- package.json 项目依赖包管理
|
||||
|-- tsconfig.json typescript配置
|
||||
|-- vite.config.ts vite配置
|
||||
|-- README.md 项目说明
|
||||
|
||||
#### 开发前的相关配置或调试时需要本地启动项目
|
||||
1、node官网下载并安装node环境,node版本18.12以上稳定版。官网地址:https://nodejs.cn/download/
|
||||
node版本安装18.12以上版本,npm版本安装9.6.0以上版即可
|
||||
查看版本:node -v npm -v
|
||||
2、更换npm源为淘宝镜像
|
||||
命令:npm config set registry https://registry.npmmirror.com/
|
||||
输入此命令查看是否完成修改:npm config get registry
|
||||
3、安装pnpm包管理器,由于有时npm启动项目会因为存在重复配置及文件而报错,使用pnpm可以避开这些问题,将资源整合,性能提高的同时也扩展了场景。
|
||||
命令:npm install -g pnpm
|
||||
输入此命令查看是否完成安装:pnpm -v
|
||||
4、安装依赖包
|
||||
命令:pnpm install
|
||||
5、启动hx-ai-intelligent 项目命令:pnpm run ai 打包到线上命令:pnpm run ai-build
|
||||
6、启动hx-op项目 项目命令:pnpm run ai-op 打包到线上命令:pnpm run ai-op-build
|
||||
7、如使用vscode编辑器,可以在终端使用cmd终端启动项目,powershell终端会报错
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<a-config-provider :locale="locale">
|
||||
<div style="width:100%;height:100%;">
|
||||
<a-spin :spinning="state.isLoading" size="large">
|
||||
<router-view />
|
||||
</a-spin>
|
||||
</div>
|
||||
<router-view />
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
@@ -14,7 +10,6 @@
|
||||
import { useRouter } from 'vue-router';
|
||||
import Cookies from 'js-cookie';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { items } from '/@/store/item';
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
|
||||
@@ -42,8 +37,6 @@
|
||||
return {
|
||||
cachedViews,
|
||||
locale: zhCN,
|
||||
// 获得全局变量
|
||||
state: items(),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -195,13 +188,4 @@
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
}
|
||||
:deep(.ant-spin-nested-loading) {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-spin-container) {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
const prefix = '/carbon-smart/api';
|
||||
|
||||
// 照明系统及相关接口
|
||||
export enum lightingManage {
|
||||
|
||||
// 主页 ========================================================
|
||||
|
||||
// 获得分区与线路
|
||||
getTree = prefix + '/illuminationCtrl/getCtrlPanelTree',
|
||||
getArea = '/carbon-smart/IlluminationInfo/region',
|
||||
// 修改线路的可用/禁用状态
|
||||
setDisable = '/carbon-smart/api/illuminationCtrl/changePanelStatus',
|
||||
// 获得设备 - 小灯泡
|
||||
getBulbs = prefix + '/illuminationCtrl/getDeviceState',
|
||||
setDisable = '/carbon-smart/IlluminationInfo/revisePanel',
|
||||
|
||||
// 主页 > 抽屉 > 控制面板 =======================================
|
||||
// 控制面板tab页 ================================================
|
||||
|
||||
// 获取当前修改的内容对比数据
|
||||
getChangeList = prefix + '/illuminationCtrl/getSceneChangeInfo',
|
||||
getChangeList = '/carbon-smart/IlluminationInfo/getLightSceneChangeInfo',
|
||||
// 提交当前修改
|
||||
submitChangeList = prefix + '/illuminationCtrl/changeToSceneMode',
|
||||
submitChangeList = '/carbon-smart/IlluminationInfo/changeLightScene',
|
||||
|
||||
// 主页 > 抽屉 > 计划列表 =======================================
|
||||
// 计划列表tab页 ================================================
|
||||
|
||||
// 右侧表格修改数据提交
|
||||
submitTableData = prefix + '/illuminationCtrl/refreshPlanStatus',
|
||||
|
||||
// 主页 > 抽屉 > 日志 ===========================================
|
||||
|
||||
// 获取日志
|
||||
getLog = prefix + '/illuminationInfo/pageAbleLog',
|
||||
// 获取日志详情
|
||||
getLogDetail = prefix + '/illuminationInfo/fullLog',
|
||||
// 获得计划列表tab页的表格数据
|
||||
getPlanTable = '/carbon-smart/IlluminationPlan/selectPanelPlan',
|
||||
// 获得计划列表tab页的穿梭框左侧数据
|
||||
getLeftPlan = '/carbon-smart/IlluminationPlan/getPlan',
|
||||
// 提交穿梭框被选择的数据
|
||||
submitLeftPlan = '/carbon-smart/IlluminationPlan/joinPlan',
|
||||
// 删除表格中的计划
|
||||
deletePlan = '/carbon-smart/IlluminationPlan/deletePlan',
|
||||
// 重启表格计划
|
||||
restartPlan = '/carbon-smart/IlluminationPlan/enable',
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
const prefix = '/carbon-smart/api';
|
||||
// 空调系统及相关接口
|
||||
export enum airConditionControl {
|
||||
// 主页 ======================================================
|
||||
|
||||
// 主页分区结构
|
||||
getTree = prefix + '/airConditioningCtrl/getCtrlPanelTree',
|
||||
// 主页小灯泡
|
||||
getDeviceList = prefix + '/airConditioningCtrl/getDeviceState',
|
||||
|
||||
// 主页 > 抽屉 > 控制面板 =======================================
|
||||
|
||||
// 获得修改的比对列表
|
||||
getChangeList = prefix + '/airConditioningCtrl/getSceneChangeInfo',
|
||||
// 提交修改结果
|
||||
submitChangeList = prefix + '/airConditioningCtrl/changeToSceneMode',
|
||||
|
||||
// 主页 > 抽屉 > 计划列表 =======================================
|
||||
|
||||
// 右侧表格修改数据提交
|
||||
submitTableData = prefix + '/airConditioningCtrl/refreshPlanStatus',
|
||||
|
||||
// 主页 > 抽屉 > 日志 ===========================================
|
||||
|
||||
// 获取日志
|
||||
getLog = prefix + '/airConditioningInfo/pageAbleLog',
|
||||
// 获取日志详情
|
||||
getLogDetail = prefix + '/airConditioningInfo/fullLog',
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
|
||||
export enum airConditioningSystemApi {
|
||||
getVentHostCtrlList = `${BASE_URL}/api/ventHostCtrl/getDeviceState`, // 查询新风主机最新状态
|
||||
getAcBoxCtrlList = `${BASE_URL}/api/acBoxCtrl/getDeviceState`, // 查询空调箱最新状态
|
||||
getTempSysCtrlList = `${BASE_URL}/api/tempSysCtrl/getFloorHeatingState`, // 查询地暖最新状态
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { BASE_URL } from '../index';
|
||||
|
||||
export enum alarmOverviewApi {
|
||||
getAlarmEquipment = `${BASE_URL}/api/AlarmOverview/alarmEquipment`, //设备告警 数量
|
||||
getAlarmEnergyConsumption = `${BASE_URL}/api/AlarmOverview/alarmEnergyConsumption`, //能碳告警 数量
|
||||
getAlarmGateway = `${BASE_URL}/api/AlarmOverview/alarmGateway`, //网关告警 数量
|
||||
getPriority = `${BASE_URL}/api/AlarmOverview/priority`, //优先级 数量
|
||||
getProcessProgress = `${BASE_URL}/api/AlarmOverview/processProgress`, //进度 数量
|
||||
getAlarmTrend = `${BASE_URL}/api/AlarmOverview/alarmTrend`, //30天告警 数量
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import { BASE_URL } from '../../index';
|
||||
|
||||
export enum deviceAlarms {
|
||||
getTableList = `${BASE_URL}/api/AlarmEquipment/selectAlarmEquipment`, //设备告警分页
|
||||
addOrUpNewData = `${BASE_URL}/api/AlarmEquipment/creatOrUpdate`, //设备告警添加 修改
|
||||
del = `${BASE_URL}/api/AlarmEquipment/delete`, //设备告警删除
|
||||
configGetTableList = `${BASE_URL}/api/AlarmEquipmentRule/selectAlarmEquipmentRule`, //配置设备告警分页
|
||||
configAddOrUpNewData = `${BASE_URL}/api/AlarmEquipmentRule/creatOrUpdate`, //配置设备告警添加 修改
|
||||
configFindById = `${BASE_URL}/api/AlarmEquipmentRule/findById`, //配置设备告警 查询详情
|
||||
configDel = `${BASE_URL}/api/AlarmEquipmentRule/delete`, //配置设备告警删除
|
||||
getTableList = '/carbon-smart/api/AlarmEquipment/selectAlarmEquipment', //设备告警分页
|
||||
addOrUpNewData = '/carbon-smart/api/AlarmEquipment/creatOrUpdate', //设备告警添加 修改
|
||||
del = '/carbon-smart/api/AlarmEquipment/delete', //设备告警删除
|
||||
configGetTableList = '/carbon-smart/api/AlarmEquipmentRule/selectAlarmEquipmentRule', //配置设备告警分页
|
||||
configAddOrUpNewData = '/carbon-smart/api/AlarmEquipmentRule/creatOrUpdate', //配置设备告警添加 修改
|
||||
configFindById = '/carbon-smart/api/AlarmEquipmentRule/findById', //配置设备告警 查询详情
|
||||
configDel = '/carbon-smart/api/AlarmEquipmentRule/delete', //配置设备告警删除
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { BASE_URL } from '../../index';
|
||||
|
||||
export enum energyAlarms {
|
||||
getTableList = `${BASE_URL}/api/AlarmEnergyConsumption/selectAlarmEnergyConsumption`, //能耗告警分页
|
||||
addOrUpNewData = `${BASE_URL}/api/AlarmEnergyConsumption/creatOrUpdate`, //能耗告警添加 修改
|
||||
del = `${BASE_URL}/api/AlarmEnergyConsumption/delete`, //能耗删除
|
||||
configGetTableList = `${BASE_URL}/api/AlarmEnergyConsumptionRule/selectAlarmEnergyConsumptionRule`, //配置设备告警分页
|
||||
configAddOrUpNewData = `${BASE_URL}/api/AlarmEnergyConsumptionRule/creatOrUpdate`, //配置设备告警添加 修改
|
||||
configFindById = `${BASE_URL}/api/AlarmEnergyConsumptionRule/findById`, //配置设备告警 查询详情
|
||||
configDel = `${BASE_URL}/api/AlarmEnergyConsumptionRule/delete`, //配置设备告警删除
|
||||
getTableList = '/carbon-smart/api/AlarmEnergyConsumption/selectAlarmEnergyConsumption', //能耗告警分页
|
||||
addOrUpNewData = '/carbon-smart/api/AlarmEnergyConsumption/creatOrUpdate', //能耗告警添加 修改
|
||||
del = '/carbon-smart/api/AlarmEnergyConsumption/delete', //能耗删除
|
||||
configGetTableList = '/carbon-smart/api/AlarmEnergyConsumptionRule/selectAlarmEnergyConsumptionRule', //配置设备告警分页
|
||||
configAddOrUpNewData = '/carbon-smart/api/AlarmEnergyConsumptionRule/creatOrUpdate', //配置设备告警添加 修改
|
||||
configFindById = '/carbon-smart/api/AlarmEnergyConsumptionRule/findById', //配置设备告警 查询详情
|
||||
configDel = '/carbon-smart/api/AlarmEnergyConsumptionRule/delete', //配置设备告警删除
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { BASE_URL } from '../../index';
|
||||
|
||||
export enum notificationManagementApi {
|
||||
getTableList = `${BASE_URL}/api/AlarmContactInformation/selectAlarmContactInformation`, //通知管理分页
|
||||
upData = `${BASE_URL}/api/AlarmContactInformation/update`, //通知管理 修改
|
||||
findById = `${BASE_URL}/api/AlarmContactInformation/findById`, //通知管理 查询详情
|
||||
getTableList = '/carbon-smart/api/AlarmContactInformation/selectAlarmContactInformation', //通知管理分页
|
||||
upData = '/carbon-smart/api/AlarmContactInformation/update', //通知管理 修改
|
||||
findById = '/carbon-smart/api/AlarmContactInformation/findById', //通知管理 查询详情
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { BASE_URL } from '../index';
|
||||
|
||||
export enum energyAlarmApi {
|
||||
getTableList = `${BASE_URL}/api/AlarmEnergyConsumptionLog/selectAlarmEnergyConsumptionLog`, //能碳告警 列表
|
||||
getCodeList = `${BASE_URL}/api/AlarmEnergyConsumptionLog/selectErrorCodeList `, //能碳告警 列表
|
||||
getSelectAlarmEnergyConsumptionLogStatusProcess = `${BASE_URL}/api/AlarmEnergyConsumptionLogStatusProcess/selectAlarmEnergyConsumptionLogStatusProcess`, //能碳告警 状态 没有创建工单log接口
|
||||
noCreatOrUpdateLog = `${BASE_URL}/api/AlarmEnergyConsumptionLogStatusProcess/creatOrUpdate`, //能碳告警 状态 没有创建工单 添加 修改状态log
|
||||
getEnergyGraph = `${BASE_URL}/energy/trigger/getEnergyGraph`, //能碳告警 状态 echarts图
|
||||
getTableList = '/carbon-smart/api/AlarmEnergyConsumptionLog/selectAlarmEnergyConsumptionLog', //能碳告警 列表
|
||||
getCodeList = '/carbon-smart/api/AlarmEnergyConsumptionLog/selectErrorCodeList ', //能碳告警 列表
|
||||
getSelectAlarmEnergyConsumptionLogStatusProcess = '/carbon-smart/api/AlarmEnergyConsumptionLogStatusProcess/selectAlarmEnergyConsumptionLogStatusProcess', //能碳告警 状态 没有创建工单log接口
|
||||
noCreatOrUpdateLog = '/carbon-smart/api/AlarmEnergyConsumptionLogStatusProcess/creatOrUpdate', //能碳告警 状态 没有创建工单 添加 修改状态log
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { BASE_URL } from '../index';
|
||||
|
||||
export enum equipmentAlarmApi {
|
||||
getTableList = `${BASE_URL}/api/AlarmEquipmentLog/selectAlarmEquipmentLog`, //设备告警 列表
|
||||
getCodeList = `${BASE_URL}/api/AlarmEquipmentLog/selectErrorCodeList`, //设备告警 列表
|
||||
getSelectAlarmEquipmentLogStatusProcess = `${BASE_URL}/api/AlarmEquipmentLogStatusProcess/selectAlarmEquipmentLogStatusProcess`, //设备告警 状态 没有创建工单log接口
|
||||
noCreatOrUpdateLog = `${BASE_URL}/api/AlarmEquipmentLogStatusProcess/creatOrUpdate`, //设备告警 状态 没有创建工单 添加 修改状态log
|
||||
getDeviceGraph = `${BASE_URL}/equipment/trigger/getDeviceGraph`, //设备告警 echats图
|
||||
getTableList = '/carbon-smart/api/AlarmEquipmentLog/selectAlarmEquipmentLog', //设备告警 列表
|
||||
getCodeList = '/carbon-smart/api/AlarmEquipmentLog/selectErrorCodeList', //设备告警 列表
|
||||
getSelectAlarmEquipmentLogStatusProcess = '/carbon-smart/api/AlarmEquipmentLogStatusProcess/selectAlarmEquipmentLogStatusProcess', //设备告警 状态 没有创建工单log接口
|
||||
noCreatOrUpdateLog = '/carbon-smart/api/AlarmEquipmentLogStatusProcess/creatOrUpdate', //设备告警 状态 没有创建工单 添加 修改状态log
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { BASE_URL } from '../index';
|
||||
export enum gatewayAlarmApi {
|
||||
getTableList = `${BASE_URL}/api/AlarmGatewayLog/selectAlarmGatewayLog`, //网关告警 列表
|
||||
getTableList = '/carbon-smart/api/AlarmGatewayLog/selectAlarmGatewayLog', //网关告警 列表
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ export enum carbonEmissionFactorLibrary {
|
||||
getCarbonFactorTree = '/carbon-smart/api/carbon/emission/type/getCarbonFactorTree',
|
||||
creat = '/carbon-smart/api/carbon/emission/type/creatOrUpdate',
|
||||
delTreeNode = '/carbon-smart/api/carbon/emission/type/del',
|
||||
move = '/carbon-smart/api/carbon/emission/type/move',
|
||||
import = '/carbon-smart/api/carbon/emission/factor/import',
|
||||
export = '/carbon-smart/api/carbon/emission/factor/export',
|
||||
gasAndDatabase = '/carbon-smart/api/carbon/emission/factor/gasAndDatabase',
|
||||
// 单位管理
|
||||
dictionaryUnitManagement = '/carbon-smart/client/dict/dictionaryUnitManagement',
|
||||
findOutermost = '/carbon-smart/client/dict/findOutermost',
|
||||
@@ -19,7 +15,7 @@ export enum carbonEmissionFactorLibrary {
|
||||
updateDictionary = '/carbon-smart/client/dict/updateDictionary',
|
||||
delDictionary = '/carbon-smart/client/dict/delDictionary',
|
||||
}
|
||||
// 碳排管理-能耗统计接口
|
||||
// 碳排管理-碳排统计接口
|
||||
export enum energyConsumption {
|
||||
getDicList = '/carbon-smart/client/dict/list',
|
||||
pageList = '/carbon-smart/api/carbon/stats/pageList',
|
||||
@@ -27,10 +23,6 @@ export enum energyConsumption {
|
||||
creat = '/carbon-smart/api/carbon/stats/creat',
|
||||
update = '/carbon-smart/api/carbon/stats/update',
|
||||
del = '/carbon-smart/api/carbon/stats/del',
|
||||
voucherDownloadList = '/carbon-smart/api/carbon/stats/voucherDownloadList',
|
||||
energyAcquisition = '/carbon-smart/api/carbon/stats/energyAcquisition',
|
||||
import = '/carbon-smart/api/carbon/stats/import',
|
||||
export = '/carbon-smart/api/carbon/stats/export',
|
||||
}
|
||||
// 碳排管理-碳排速算接口
|
||||
export enum quickCalculation {
|
||||
@@ -50,7 +42,6 @@ export enum carbonInventoryCheck {
|
||||
createOrUpdate = '/carbon-smart/api/carbon/report/createOrUpdate',
|
||||
findById = '/carbon-smart/api/carbon/report/findById',
|
||||
delete = '/carbon-smart/api/carbon/report/delete',
|
||||
downloadZip = '/carbon-smart/api/carbon/report/downloadZip',
|
||||
// 填报页面接口
|
||||
// 最左侧碳盘查报告树
|
||||
getCategoryTree = '/carbon-smart/api/carbon/inventory/contact/getCategoryTree',
|
||||
@@ -61,52 +52,9 @@ export enum carbonInventoryCheck {
|
||||
update = '/carbon-smart/api/carbon/inventory/update',
|
||||
del = '/carbon-smart/api/carbon/inventory/del',
|
||||
// 获取排放源表格数据
|
||||
findUnitById = '/carbon-smart/api/carbon/inventory/findById',
|
||||
findUnitById = '/carbon-smartapi/carbon/inventory/findById',
|
||||
getDetailsList = '/carbon-smart/api/carbon/inventory/details/getDetailsList',
|
||||
updateTable = '/carbon-smart/api/carbon/inventory/details/update',
|
||||
voucherDownloadList = '/carbon-smart/api/carbon/inventory/details/voucherDownloadList',
|
||||
nodeCancellationConsumption = '/carbon-smart/api/carbon/inventory/details/nodeCancellationConsumption',
|
||||
// 排放统计接口
|
||||
emissionStatistic = '/carbon-smart/api/carbon/inventory/emissionStatistic',
|
||||
// 碳排流向
|
||||
carbonFlowDirection = '/carbon-smart/api/carbon/inventory/carbonFlowDirection',
|
||||
}
|
||||
// 碳资产
|
||||
export enum carbonAssets {
|
||||
// 全部
|
||||
carbonAssets = '/carbon-smart/api/carbon/trade/details/carbonAssets',
|
||||
// 详情
|
||||
carbonDetailsList = '/carbon-smart/api/carbon/trade/details/carbonDetailsList',
|
||||
createOrUpdate = '/carbon-smart/api/carbon/trade/details/createOrUpdate',
|
||||
delete = '/carbon-smart/api/carbon/trade/details/delete',
|
||||
quotaStatistics = '/carbon-smart/api/carbon/trade/details/quotaStatistics',
|
||||
import = '/carbon-smart/api/carbon/trade/details/import',
|
||||
export = '/carbon-smart/api/carbon/trade/details/export',
|
||||
}
|
||||
// 上传图片接口
|
||||
export enum uploadPic {
|
||||
uploadfiles = '/carbon-smart/api/common/file/uploadfiles',
|
||||
select = '/carbon-smart/api/common/file/select',
|
||||
uploadfile = '/carbon-smart/api/common/file/uploadfile',
|
||||
download = '/carbon-smart/api/common/file/download',
|
||||
downloadZip = '/carbon-smart/api/common/file/downloadZip',
|
||||
}
|
||||
// 碳规划
|
||||
export enum carbonPlanning {
|
||||
// 全部
|
||||
whole = '/carbon-smart/api/carbon/planning/whole',
|
||||
// 详情
|
||||
searchListByYear = '/carbon-smart/api/carbon/planning/searchListByYear',
|
||||
searchListByMonth = '/carbon-smart/api/carbon/planning/searchListByMonth',
|
||||
yearAndMonthAchievement = '/carbon-smart/api/carbon/planning/yearAndMonthAchievement',
|
||||
annualElectricityConsumption = '/carbon-smart/api/carbon/planning/annualElectricityConsumption',
|
||||
electricityUsageBackThen = '/carbon-smart/api/carbon/planning/electricityUsageBackThen',
|
||||
detailedStatisticalDataTable = '/carbon-smart/api/carbon/planning/detailedStatisticalDataTable',
|
||||
detailedStatisticalDataChart = '/carbon-smart/api/carbon/planning/detailedStatisticalDataChart',
|
||||
batchOrUpdate = '/carbon-smart/api/carbon/planning/batchOrUpdate',
|
||||
addNodes = '/carbon-smart/api/carbon/planning/addNodes',
|
||||
benchmarkSetting = '/carbon-smart/api/carbon/planning/benchmarkSetting',
|
||||
monthBenchmarkSetting = '/carbon-smart/api/carbon/planning/monthBenchmarkSetting',
|
||||
benchmarkSubmit = '/carbon-smart/api/carbon/planning/benchmarkSubmit',
|
||||
autoObtained = '/carbon-smart/api/carbon/planning/autoObtained',
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
|
||||
export enum coldAndHeatSourcesApi {
|
||||
getUserWaterPumpState = `${BASE_URL}/api/tempSysCtrl/getUserWaterPumpState`, // 用户水泵查询最新状态
|
||||
getLandWaterPumpState = `${BASE_URL}/api/tempSysCtrl/getLandWaterPumpState`, // 地源水泵查询最新状态
|
||||
getLandHeatPumpState = `${BASE_URL}/api/tempSysCtrl/getLandHeatPumpState`, //螺旋式地源热泵 - 查询最新状态
|
||||
getEnergyTankState = `${BASE_URL}/api/tempSysCtrl/getEnergyTankState`, //冷热水双蓄储能罐 - 查询最新状态
|
||||
getCoolPumpState = `${BASE_URL}/api/tempSysCtrl/getCoolPumpState`, //释冷泵 - 查询最新状态
|
||||
getAirHeatPumpState = `${BASE_URL}/api/tempSysCtrl/getAirHeatPumpState`, //空气源热泵 - 查询最新状态
|
||||
}
|
||||
@@ -29,9 +29,4 @@ export enum group {
|
||||
dropGroupFilter = `${BASE_URL}/deviceGroup/dropGroupFilter`, // 分组列表查询
|
||||
dropGroupInfoFilter = `${BASE_URL}/deviceGroup/dropGroupInfoFilter`, // 计算列表查询
|
||||
queryDeviceToEnergy = `${BASE_URL}/deviceGroup/queryDeviceToEnergy`, // 能耗监测用查询设备(能耗监测设备树)
|
||||
|
||||
getCarbonGroupList = `${BASE_URL}/deviceGroup/carbonEmissions/getGroupList`, // 分组管理-碳排放-分组查询设备
|
||||
deleteCarbonDevice = `${BASE_URL}/deviceGroup/carbonEmissions/deleteDevice`, // 分组管理-碳排放-删除设备
|
||||
addCarbonDevice = `${BASE_URL}/deviceGroup/carbonEmissions/addDevice`, // 分组管理-碳排放-添加设备
|
||||
updateCarbonFactor = `${BASE_URL}/deviceGroup/carbonEmissions/updateFactor`, // 分组管理-碳排放-设置因子
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
|
||||
export enum electricDoorApi {
|
||||
getDeviceState = `${BASE_URL}/api/eleDoorCtrl/getDeviceState`, // 查询设备最新状态
|
||||
getDeviceRecordList = `${BASE_URL}/api/eleDoorCtrl/getDeviceRecordList`, // 查询设备日志列表
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export const dict = async ({
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取所有枚举(参数为数组,可以不传参)
|
||||
* 获取所有枚举(无需传参)
|
||||
*/
|
||||
export const getAllEnum = async ({
|
||||
api = `${BASE_URL}/operation/enum/getAllEnum`,
|
||||
@@ -60,13 +60,3 @@ export const getEnum = async ({
|
||||
const res = await http.get(api, params);
|
||||
return Promise.resolve(res);
|
||||
};
|
||||
/**
|
||||
* 获取谈规划单位(需传参,参数 enumType)
|
||||
*/
|
||||
export const getEnumEnergy = async ({
|
||||
api = `${BASE_URL}/operation/enum/getEnumEnergy`,
|
||||
params = {},
|
||||
}: dictHttpConfig) => {
|
||||
const res = await http.get(api, params);
|
||||
return Promise.resolve(res);
|
||||
};
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
|
||||
export enum liftSystemApi {
|
||||
getDeviceState = `${BASE_URL}/api/elevatorCtrl/getDeviceState`, // 查询设备最新状态
|
||||
getDeviceRecordList = `${BASE_URL}/api/elevatorCtrl/getDeviceRecordList`, // 查询设备日志列表
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
export enum menuS {
|
||||
queryMenuPage = `${BASE_URL}/deviceInfo/queryDevicePage`, // 菜单列表
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// 设备监测
|
||||
export enum deviceMonitor {
|
||||
getDeviceGraph = '/carbon-smart/api/monitor/getDeviceGraph',
|
||||
getDevicePointToMonitor = '/carbon-smart/api/monitor/getDevicePointToMonitor',
|
||||
getDevicePointToMonitor = '/carbon-smart//api/monitor/getDevicePointToMonitor',
|
||||
}
|
||||
|
||||
// 能耗监测
|
||||
@@ -11,18 +11,4 @@ export enum energyMonitor {
|
||||
}
|
||||
|
||||
// 环境监测
|
||||
export enum environmentMonitor {
|
||||
getDeviceStatus = '/carbon-smart/api/monitor/getDeviceStatus', //环境监测-获取设备状态
|
||||
getDeviceAverages = '/carbon-smart/api/monitor/getDeviceAverages', //环境监测-获取设备平均值
|
||||
queryDeviceArea = '/carbon-smart/deviceInfo/queryDeviceArea', //查询区域位置组成树结构
|
||||
getDeviceHotMap = '/carbon-smart/api/monitor/getDeviceHotMap', //环境监测-获取环境热力图
|
||||
|
||||
getDeviceHistory = '/carbon-smart/api/monitor/getDeviceHistory', //环境监测-历史数据-获取环境设备历史数据
|
||||
|
||||
getDeviceAveragesByRate = '/carbon-smart/api/monitor/getDeviceAveragesByRate', //环境监测-平均数据-获取环境设备平均数据
|
||||
|
||||
queryDeviceInfoListPage = '/carbon-smart/api/monitor/queryDeviceInfoListPage', //环境监测-根据条件查询设备数据(分页) 配置监测点位
|
||||
|
||||
startUpDevice = '/carbon-smart/api/monitor/startUpDevice', // 环境监测-配置启动设备
|
||||
stopDevice = '/carbon-smart/api/monitor/stopDevice', // 环境监测-停用设备
|
||||
}
|
||||
export enum environmentMonitor {}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
const prefix = '/carbon-smart/api';
|
||||
// 照明系统及相关接口
|
||||
export enum planManage {
|
||||
/**
|
||||
* @param deviceType 设备类型(1照明,2空调,3排风扇,4风幕机,5电动窗,6给排水)
|
||||
*/
|
||||
// 获得未激活的计划
|
||||
getTransData = prefix + '/deviceCtrlPlan/getDeActivatedPlanList',
|
||||
// 获得激活的计划
|
||||
getTableData = prefix + '/deviceCtrlPlan/getActivatedPlanList',
|
||||
// 提交计划状态修改
|
||||
submitTransData = prefix + '/deviceCtrlPlan/activePlanByIdList',
|
||||
// 用于确认当前是否有计划正在运行
|
||||
getRunningPlan = prefix + '/deviceCtrlPlan/getRunningPlan',
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { BASE_URL } from './index';
|
||||
|
||||
export enum planToAddApi {
|
||||
getActivatedPlanTree = `${BASE_URL}/api/deviceCtrlPlan/getPlanLibTree`, //计划树
|
||||
getActivatedPlanListByTree = `${BASE_URL}/api/deviceCtrlPlan/getPageAblePlanListByTree`, //计划列表
|
||||
updPlan = `${BASE_URL}/api/deviceCtrlPlan/updateCtrlPlan`, //修改计划
|
||||
delPlan = `${BASE_URL}/api/deviceCtrlPlan/deleteCtrlPlanByIdList`, //修改计划
|
||||
addPlan = `${BASE_URL}/api/deviceCtrlPlan/addCtrlPlan`, //添加计划
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// 前缀
|
||||
const prefix = '/carbon-smart/api';
|
||||
// 通风系统相关接口
|
||||
export enum ventilating {
|
||||
//传感器获取数据
|
||||
getSensorData = prefix + '/sensorCtrl/getMultiFuncSensorState',
|
||||
// 排风扇相关 =============================================
|
||||
// 获得排风扇系统的树形结构
|
||||
getTree1 = prefix + '/ventilatingFanCtrl/getCtrlPanelTree',
|
||||
// 获得排风扇的 场景/禁用 修改数据
|
||||
getChangeList1 = prefix + '/ventilatingFanCtrl/getSceneChangeInfo',
|
||||
// 提交排风扇的修改内容
|
||||
sendChangeList1 = prefix + '/ventilatingFanCtrl/changeToSceneMode',
|
||||
// 获得排风扇的设备状态
|
||||
getDevice1 = prefix + '/ventilatingFanCtrl/getDeviceState',
|
||||
// 提交排风扇的修改内容
|
||||
submitTableData1 = prefix + '/ventilatingFanCtrl/refreshPlanStatus',
|
||||
// 排风扇日志
|
||||
getLog1 = prefix + '/ventilatingFanInfo/pageAbleLog',
|
||||
// 排风扇日志详情
|
||||
getLogDetail1 = prefix + '/ventilatingFanInfo/fullLog',
|
||||
|
||||
// 风幕机相关 =============================================
|
||||
// 获得风幕机的树形结构
|
||||
getTree2 = prefix + '/airCurtainMachineCtrl/getCtrlPanelTree',
|
||||
// 获得风幕机的 场景/禁用 修改数据
|
||||
getChangeList2 = prefix + '/airCurtainMachineCtrl/getSceneChangeInfo',
|
||||
// 提交风幕机的修改内容
|
||||
sendChangeList2 = prefix + '/airCurtainMachineCtrl/changeToSceneMode',
|
||||
// 获得风幕机的设备状态
|
||||
getDevice2 = prefix + '/airCurtainMachineCtrl/getDeviceState',
|
||||
// 提交风幕机的修改内容
|
||||
submitTableData2 = prefix + '/airCurtainMachineCtrl/refreshPlanStatus',
|
||||
// 风幕机日志
|
||||
getLog2 = prefix + '/airCurtainMachineInfo/pageAbleLog',
|
||||
// 风幕机日志详情
|
||||
getLogDetail2 = prefix + '/airCurtainMachineInfo/fullLog',
|
||||
|
||||
// 电动窗相关 =============================================
|
||||
// 获得电动窗的树形结构
|
||||
getTree3 = prefix + '/eleOperatedWindowCtrl/getCtrlPanelTree',
|
||||
// 获得电动窗的 场景/禁用 修改数据
|
||||
getChangeList3 = prefix + '/eleOperatedWindowCtrl/getSceneChangeInfo',
|
||||
// 提交电动窗的修改内容
|
||||
sendChangeList3 = prefix + '/eleOperatedWindowCtrl/changeToSceneMode',
|
||||
// 获得电动窗的设备状态
|
||||
getDevice3 = prefix + '/eleOperatedWindowCtrl/getDeviceState',
|
||||
// 提交电动窗的修改内容
|
||||
submitTableData3 = prefix + '/eleOperatedWindowCtrl/refreshPlanStatus',
|
||||
// 电动窗日志
|
||||
getLog3 = prefix + '/eleOperatedWindowInfo/pageAbleLog',
|
||||
// 电动窗日志详情
|
||||
getLogDetail3 = prefix + '/eleOperatedWindowInfo/fullLog',
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// 前缀
|
||||
const prefix = '/carbon-smart/api';
|
||||
// 通风系统相关接口
|
||||
export enum waterSys {
|
||||
// 首页 ====================================================
|
||||
|
||||
// 获得污水池状态
|
||||
getPool1 = prefix + '/waterSysCtrl/getSewagePoolState',
|
||||
// 获得阀门状态
|
||||
getValve = prefix + '/waterSysCtrl/getValveState',
|
||||
// 获得集水池状态
|
||||
getPool2 = prefix + '/waterSysCtrl/getCollectPoolState',
|
||||
// 获得水泵状态
|
||||
getPump = prefix + '/waterSysCtrl/getPumpState',
|
||||
// 提交场景模式修改
|
||||
submitList = prefix + '/waterSysCtrl/changeToSceneMode',
|
||||
|
||||
// 计划 tab1 ===============================================
|
||||
submitTableData = prefix + '/waterSysCtrl/refreshPlanStatus',
|
||||
|
||||
// 日志 tab2 ===============================================
|
||||
// 获得设备日志
|
||||
getLog = prefix + '/waterSysInfo/pageAbleLog',
|
||||
// 获得日志详情
|
||||
getLogDetail = prefix + '/waterSysInfo/fullLog',
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { withInstall } from '/@/utils';
|
||||
import basicDrawer from './src/BasicDrawer.vue';
|
||||
|
||||
export const BasicDrawer = withInstall(basicDrawer);
|
||||
export * from './src/typing';
|
||||
export { useDrawer, useDrawerInner } from './src/useDrawer';
|
||||
@@ -1,255 +0,0 @@
|
||||
<template>
|
||||
<Drawer :class="prefixCls" @close="onClose" v-bind="getBindValues">
|
||||
<template #title v-if="!$slots.title">
|
||||
<DrawerHeader :title="getMergeProps.title" :isDetail="isDetail" :showDetailBack="showDetailBack" @close="onClose">
|
||||
<template #titleToolbar>
|
||||
<slot name="titleToolbar"></slot>
|
||||
</template>
|
||||
</DrawerHeader>
|
||||
</template>
|
||||
<template v-else #title>
|
||||
<slot name="title"></slot>
|
||||
</template>
|
||||
|
||||
<ScrollContainer :style="getScrollContentStyle" v-loading="getLoading" :loading-tip="loadingText || t('common.loadingText')">
|
||||
<slot></slot>
|
||||
</ScrollContainer>
|
||||
<DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</DrawerFooter>
|
||||
</Drawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { DrawerInstance, DrawerProps } from './typing';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { defineComponent, ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue';
|
||||
import { Drawer } from 'ant-design-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isFunction, isNumber } from '/@/utils/is';
|
||||
import { deepMerge } from '/@/utils';
|
||||
import DrawerFooter from './components/DrawerFooter.vue';
|
||||
import DrawerHeader from './components/DrawerHeader.vue';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
import { basicProps } from './props';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Drawer, ScrollContainer, DrawerFooter, DrawerHeader },
|
||||
inheritAttrs: false,
|
||||
props: basicProps,
|
||||
emits: ['visible-change', 'open-change', 'ok', 'close', 'register'],
|
||||
setup(props, { emit }) {
|
||||
const visibleRef = ref(false);
|
||||
const attrs = useAttrs();
|
||||
const propsRef = ref<Partial<Nullable<DrawerProps>>>(null);
|
||||
|
||||
const { t } = useI18n();
|
||||
const { prefixVar, prefixCls } = useDesign('basic-drawer');
|
||||
|
||||
const drawerInstance: DrawerInstance = {
|
||||
setDrawerProps: setDrawerProps,
|
||||
emitVisible: undefined,
|
||||
};
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
instance && emit('register', drawerInstance, instance.uid);
|
||||
|
||||
const getMergeProps = computed((): DrawerProps => {
|
||||
// update-begin--author:liaozhiyang---date:20240320---for:【QQYUN-8389】vue3.4以上版本导致角色抽屉隐藏footer逻辑错误(toRaw改成cloneDeep,否则props的变化不会触发computed)
|
||||
return { ...deepMerge(cloneDeep(props), unref(propsRef)) };
|
||||
// update-end--author:liaozhiyang---date:20240320---for:【QQYUN-8389】vue3.4以上版本导致角色抽屉隐藏footer逻辑错误(toRaw改成cloneDeep,否则props的变化不会触发computed)
|
||||
});
|
||||
|
||||
const getProps = computed((): DrawerProps => {
|
||||
// update-begin--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
const opt = {
|
||||
placement: 'right',
|
||||
...unref(attrs),
|
||||
...unref(getMergeProps),
|
||||
open: unref(visibleRef),
|
||||
};
|
||||
// update-end--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
opt.title = undefined;
|
||||
let { isDetail, width, wrapClassName, getContainer } = opt;
|
||||
if (isDetail) {
|
||||
if (!width) {
|
||||
opt.width = '100%';
|
||||
}
|
||||
const detailCls = `${prefixCls}__detail`;
|
||||
wrapClassName = opt['class'] ? opt['class'] : wrapClassName;
|
||||
opt.class = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls;
|
||||
|
||||
if (!getContainer) {
|
||||
// TODO type error?
|
||||
opt.getContainer = `.${prefixVar}-layout-content` as any;
|
||||
}
|
||||
}
|
||||
console.log('getProps:opt',opt);
|
||||
return opt as DrawerProps;
|
||||
});
|
||||
|
||||
const getBindValues = computed((): DrawerProps => {
|
||||
return {
|
||||
...attrs,
|
||||
...unref(getProps),
|
||||
};
|
||||
});
|
||||
|
||||
// Custom implementation of the bottom button,
|
||||
const getFooterHeight = computed(() => {
|
||||
const { footerHeight, showFooter } = unref(getProps);
|
||||
if (showFooter && footerHeight) {
|
||||
return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
|
||||
}
|
||||
return `0px`;
|
||||
});
|
||||
|
||||
const getScrollContentStyle = computed((): CSSProperties => {
|
||||
const footerHeight = unref(getFooterHeight);
|
||||
return {
|
||||
position: 'relative',
|
||||
height: `calc(100% - ${footerHeight})`,
|
||||
};
|
||||
});
|
||||
|
||||
const getLoading = computed(() => {
|
||||
return !!unref(getProps)?.loading;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) visibleRef.value = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) visibleRef.value = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => visibleRef.value,
|
||||
(visible) => {
|
||||
nextTick(() => {
|
||||
emit('visible-change', visible);
|
||||
emit('open-change', visible);
|
||||
instance && drawerInstance.emitVisible?.(visible, instance.uid);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Cancel event
|
||||
async function onClose(e: Recordable) {
|
||||
const { closeFunc } = unref(getProps);
|
||||
emit('close', e);
|
||||
if (closeFunc && isFunction(closeFunc)) {
|
||||
const res = await closeFunc();
|
||||
visibleRef.value = !res;
|
||||
return;
|
||||
}
|
||||
visibleRef.value = false;
|
||||
}
|
||||
|
||||
function setDrawerProps(props: Partial<DrawerProps>): void {
|
||||
// Keep the last setDrawerProps
|
||||
propsRef.value = deepMerge(unref(propsRef) || ({} as any), props);
|
||||
|
||||
if (Reflect.has(props, 'visible')) {
|
||||
visibleRef.value = !!props.visible;
|
||||
}
|
||||
if (Reflect.has(props, 'open')) {
|
||||
visibleRef.value = !!props.open;
|
||||
}
|
||||
}
|
||||
|
||||
function handleOk() {
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
return {
|
||||
onClose,
|
||||
t,
|
||||
prefixCls,
|
||||
getMergeProps: getMergeProps as any,
|
||||
getScrollContentStyle,
|
||||
getProps: getProps as any,
|
||||
getLoading,
|
||||
getBindValues,
|
||||
getFooterHeight,
|
||||
handleOk,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@header-height: 60px;
|
||||
@detail-header-height: 40px;
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer';
|
||||
@prefix-cls-detail: ~'@{namespace}-basic-drawer__detail';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-drawer-wrapper-body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ant-drawer-close {
|
||||
&:hover {
|
||||
color: @error-color;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
height: calc(100% - @header-height);
|
||||
padding: 0;
|
||||
background-color: @component-background;
|
||||
|
||||
.scrollbar__wrap {
|
||||
padding: 16px !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
> .scrollbar > .scrollbar__bar.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls-detail} {
|
||||
position: absolute;
|
||||
|
||||
.ant-drawer-header {
|
||||
width: 100%;
|
||||
height: @detail-header-height;
|
||||
padding: 0;
|
||||
border-top: 1px solid @border-color-base;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ant-drawer-title {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-drawer-close {
|
||||
height: @detail-header-height;
|
||||
line-height: @detail-header-height;
|
||||
}
|
||||
|
||||
.scrollbar__wrap {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
height: calc(100% - @detail-header-height);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<div :class="prefixCls" :style="getStyle" v-if="showFooter || $slots.footer">
|
||||
<template v-if="!$slots.footer">
|
||||
<slot name="insertFooter"></slot>
|
||||
<a-button v-bind="cancelButtonProps" @click="handleClose" class="mr-2" v-if="showCancelBtn">
|
||||
{{ cancelText }}
|
||||
</a-button>
|
||||
<slot name="centerFooter"></slot>
|
||||
<a-button :type="okType" @click="handleOk" v-bind="okButtonProps" class="mr-2" :loading="confirmLoading" v-if="showOkBtn">
|
||||
{{ okText }}
|
||||
</a-button>
|
||||
<slot name="appendFooter"></slot>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<slot name="footer"></slot>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { footerProps } from '../props';
|
||||
export default defineComponent({
|
||||
name: 'BasicDrawerFooter',
|
||||
props: {
|
||||
...footerProps,
|
||||
height: {
|
||||
type: String,
|
||||
default: '60px',
|
||||
},
|
||||
},
|
||||
emits: ['ok', 'close'],
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('basic-drawer-footer');
|
||||
|
||||
const getStyle = computed((): CSSProperties => {
|
||||
const heightStr = `${props.height}`;
|
||||
return {
|
||||
height: heightStr,
|
||||
lineHeight: heightStr,
|
||||
};
|
||||
});
|
||||
|
||||
function handleOk() {
|
||||
emit('ok');
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
emit('close');
|
||||
}
|
||||
return { handleOk, prefixCls, handleClose, getStyle };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-footer';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 0 12px 0 20px;
|
||||
text-align: right;
|
||||
background-color: @component-background;
|
||||
border-top: 1px solid @border-color-base;
|
||||
|
||||
> * {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,74 +0,0 @@
|
||||
<template>
|
||||
<BasicTitle v-if="!isDetail" :class="[prefixCls, 'is-drawer']">
|
||||
<slot name="title"></slot>
|
||||
{{ !$slots.title ? title : '' }}
|
||||
</BasicTitle>
|
||||
|
||||
<div :class="[prefixCls, `${prefixCls}--detail`]" v-else>
|
||||
<span :class="`${prefixCls}__twrap`">
|
||||
<span @click="handleClose" v-if="showDetailBack">
|
||||
<ArrowLeftOutlined :class="`${prefixCls}__back`" />
|
||||
</span>
|
||||
<span v-if="title">{{ title }}</span>
|
||||
</span>
|
||||
|
||||
<span :class="`${prefixCls}__toolbar`">
|
||||
<slot name="titleToolbar"></slot>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicTitle } from '/@/components/Basic';
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
export default defineComponent({
|
||||
name: 'BasicDrawerHeader',
|
||||
components: { BasicTitle, ArrowLeftOutlined },
|
||||
props: {
|
||||
isDetail: propTypes.bool,
|
||||
showDetailBack: propTypes.bool,
|
||||
title: propTypes.string,
|
||||
},
|
||||
emits: ['close'],
|
||||
setup(_, { emit }) {
|
||||
const { prefixCls } = useDesign('basic-drawer-header');
|
||||
|
||||
function handleClose() {
|
||||
emit('close');
|
||||
}
|
||||
|
||||
return { prefixCls, handleClose };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-drawer-header';
|
||||
@footer-height: 60px;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
&__back {
|
||||
padding: 0 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__twrap {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
padding-right: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,46 +0,0 @@
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
export const footerProps = {
|
||||
confirmLoading: { type: Boolean },
|
||||
/**
|
||||
* @description: Show close button
|
||||
*/
|
||||
showCancelBtn: { type: Boolean, default: true },
|
||||
cancelButtonProps: Object as PropType<Recordable>,
|
||||
cancelText: { type: String, default: t('common.cancelText') },
|
||||
/**
|
||||
* @description: Show confirmation button
|
||||
*/
|
||||
showOkBtn: { type: Boolean, default: true },
|
||||
okButtonProps: Object as PropType<Recordable>,
|
||||
okText: { type: String, default: t('common.okText') },
|
||||
okType: { type: String, default: 'primary' },
|
||||
showFooter: { type: Boolean },
|
||||
footerHeight: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: 60,
|
||||
},
|
||||
};
|
||||
export const basicProps = {
|
||||
class: {type: [String, Object, Array]},
|
||||
isDetail: { type: Boolean },
|
||||
title: { type: String, default: '' },
|
||||
loadingText: { type: String },
|
||||
showDetailBack: { type: Boolean, default: true },
|
||||
visible: { type: Boolean },
|
||||
open: { type: Boolean },
|
||||
loading: { type: Boolean },
|
||||
maskClosable: { type: Boolean, default: true },
|
||||
getContainer: {
|
||||
type: [Object, String] as PropType<any>,
|
||||
},
|
||||
closeFunc: {
|
||||
type: [Function, Object] as PropType<any>,
|
||||
default: null,
|
||||
},
|
||||
destroyOnClose: { type: Boolean },
|
||||
...footerProps,
|
||||
};
|
||||
@@ -1,199 +0,0 @@
|
||||
import type { ButtonProps } from 'ant-design-vue/lib/button/buttonTypes';
|
||||
import type { CSSProperties, VNodeChild, ComputedRef } from 'vue';
|
||||
import type { ScrollContainerOptions } from '/@/components/Container/index';
|
||||
|
||||
export interface DrawerInstance {
|
||||
setDrawerProps: (props: Partial<DrawerProps> | boolean) => void;
|
||||
emitVisible?: (visible: boolean, uid: number) => void;
|
||||
}
|
||||
|
||||
export interface ReturnMethods extends DrawerInstance {
|
||||
openDrawer: <T = any>(visible?: boolean, data?: T, openOnSet?: boolean) => void;
|
||||
closeDrawer: () => void;
|
||||
getVisible?: ComputedRef<boolean>;
|
||||
getOpen?: ComputedRef<boolean>;
|
||||
}
|
||||
|
||||
export type RegisterFn = (drawerInstance: DrawerInstance, uuid?: string) => void;
|
||||
|
||||
export interface ReturnInnerMethods extends DrawerInstance {
|
||||
closeDrawer: () => void;
|
||||
changeLoading: (loading: boolean) => void;
|
||||
changeOkLoading: (loading: boolean) => void;
|
||||
getVisible?: ComputedRef<boolean>;
|
||||
getOpen?: ComputedRef<boolean>;
|
||||
}
|
||||
|
||||
export type UseDrawerReturnType = [RegisterFn, ReturnMethods];
|
||||
|
||||
export type UseDrawerInnerReturnType = [RegisterFn, ReturnInnerMethods];
|
||||
|
||||
export interface DrawerFooterProps {
|
||||
showOkBtn: boolean;
|
||||
showCancelBtn: boolean;
|
||||
/**
|
||||
* Text of the Cancel button
|
||||
* @default 'cancel'
|
||||
* @type string
|
||||
*/
|
||||
cancelText: string;
|
||||
/**
|
||||
* Text of the OK button
|
||||
* @default 'OK'
|
||||
* @type string
|
||||
*/
|
||||
okText: string;
|
||||
|
||||
/**
|
||||
* Button type of the OK button
|
||||
* @default 'primary'
|
||||
* @type string
|
||||
*/
|
||||
okType: 'primary' | 'danger' | 'dashed' | 'ghost' | 'default';
|
||||
/**
|
||||
* The ok button props, follow jsx rules
|
||||
* @type object
|
||||
*/
|
||||
okButtonProps: { props: ButtonProps; on: {} };
|
||||
|
||||
/**
|
||||
* The cancel button props, follow jsx rules
|
||||
* @type object
|
||||
*/
|
||||
cancelButtonProps: { props: ButtonProps; on: {} };
|
||||
/**
|
||||
* Whether to apply loading visual effect for OK button or not
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
confirmLoading: boolean;
|
||||
|
||||
showFooter: boolean;
|
||||
footerHeight: string | number;
|
||||
}
|
||||
export interface DrawerProps extends DrawerFooterProps {
|
||||
isDetail?: boolean;
|
||||
loading?: boolean;
|
||||
showDetailBack?: boolean;
|
||||
visible?: boolean;
|
||||
open?: boolean;
|
||||
/**
|
||||
* Built-in ScrollContainer component configuration
|
||||
* @type ScrollContainerOptions
|
||||
*/
|
||||
scrollOptions?: ScrollContainerOptions;
|
||||
closeFunc?: () => Promise<any>;
|
||||
triggerWindowResize?: boolean;
|
||||
/**
|
||||
* Whether a close (x) button is visible on top right of the Drawer dialog or not.
|
||||
* @default true
|
||||
* @type boolean
|
||||
*/
|
||||
closable?: boolean;
|
||||
|
||||
/**
|
||||
* Whether to unmount child components on closing drawer or not.
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
destroyOnClose?: boolean;
|
||||
|
||||
/**
|
||||
* Return the mounted node for Drawer.
|
||||
* @default 'body'
|
||||
* @type any ( HTMLElement| () => HTMLElement | string)
|
||||
*/
|
||||
getContainer?: () => HTMLElement | string;
|
||||
|
||||
/**
|
||||
* Whether to show mask or not.
|
||||
* @default true
|
||||
* @type boolean
|
||||
*/
|
||||
mask?: boolean;
|
||||
|
||||
/**
|
||||
* Clicking on the mask (area outside the Drawer) to close the Drawer or not.
|
||||
* @default true
|
||||
* @type boolean
|
||||
*/
|
||||
maskClosable?: boolean;
|
||||
|
||||
/**
|
||||
* Style for Drawer's mask element.
|
||||
* @default {}
|
||||
* @type object
|
||||
*/
|
||||
maskStyle?: CSSProperties;
|
||||
|
||||
/**
|
||||
* The title for Drawer.
|
||||
* @type any (string | slot)
|
||||
*/
|
||||
title?: VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* The class name of the container of the Drawer dialog.
|
||||
* @type string
|
||||
*/
|
||||
class?: string;
|
||||
// 兼容老版本的写法(后续可能会删除,优先写class)
|
||||
wrapClassName?: string;
|
||||
|
||||
/**
|
||||
* Style of wrapper element which **contains mask** compare to `drawerStyle`
|
||||
* @type object
|
||||
*/
|
||||
wrapStyle?: CSSProperties;
|
||||
|
||||
/**
|
||||
* Style of the popup layer element
|
||||
* @type object
|
||||
*/
|
||||
drawerStyle?: CSSProperties;
|
||||
|
||||
/**
|
||||
* Style of floating layer, typically used for adjusting its position.
|
||||
* @type object
|
||||
*/
|
||||
bodyStyle?: CSSProperties;
|
||||
headerStyle?: CSSProperties;
|
||||
|
||||
/**
|
||||
* Width of the Drawer dialog.
|
||||
* @default 256
|
||||
* @type string | number
|
||||
*/
|
||||
width?: string | number;
|
||||
|
||||
/**
|
||||
* placement is top or bottom, height of the Drawer dialog.
|
||||
* @type string | number
|
||||
*/
|
||||
height?: string | number;
|
||||
|
||||
/**
|
||||
* The z-index of the Drawer.
|
||||
* @default 1000
|
||||
* @type number
|
||||
*/
|
||||
zIndex?: number;
|
||||
|
||||
/**
|
||||
* The placement of the Drawer.
|
||||
* @default 'right'
|
||||
* @type string
|
||||
*/
|
||||
placement?: 'top' | 'right' | 'bottom' | 'left';
|
||||
afterVisibleChange?: (visible?: boolean) => void;
|
||||
keyboard?: boolean;
|
||||
/**
|
||||
* Specify a callback that will be called when a user clicks mask, close button or Cancel button.
|
||||
*/
|
||||
onClose?: (e?: Event) => void;
|
||||
}
|
||||
export interface DrawerActionType {
|
||||
scrollBottom: () => void;
|
||||
scrollTo: (to: number) => void;
|
||||
getScrollWrap: () => Element | null;
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import type { UseDrawerReturnType, DrawerInstance, ReturnMethods, DrawerProps, UseDrawerInnerReturnType } from './typing';
|
||||
import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw, computed } from 'vue';
|
||||
import { isProdMode } from '/@/utils/env';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { tryOnUnmounted } from '@vueuse/core';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { error } from '/@/utils/log';
|
||||
|
||||
const dataTransferRef = reactive<any>({});
|
||||
|
||||
const visibleData = reactive<{ [key: number]: boolean }>({});
|
||||
|
||||
/**
|
||||
* @description: Applicable to separate drawer and call outside
|
||||
*/
|
||||
export function useDrawer(): UseDrawerReturnType {
|
||||
if (!getCurrentInstance()) {
|
||||
throw new Error('useDrawer() can only be used inside setup() or functional components!');
|
||||
}
|
||||
const drawer = ref<DrawerInstance | null>(null);
|
||||
const loaded = ref<Nullable<boolean>>(false);
|
||||
const uid = ref<string>('');
|
||||
|
||||
function register(drawerInstance: DrawerInstance, uuid: string) {
|
||||
isProdMode() &&
|
||||
tryOnUnmounted(() => {
|
||||
drawer.value = null;
|
||||
loaded.value = null;
|
||||
dataTransferRef[unref(uid)] = null;
|
||||
});
|
||||
|
||||
if (unref(loaded) && isProdMode() && drawerInstance === unref(drawer)) {
|
||||
return;
|
||||
}
|
||||
uid.value = uuid;
|
||||
drawer.value = drawerInstance;
|
||||
loaded.value = true;
|
||||
|
||||
drawerInstance.emitVisible = (visible: boolean, uid: number) => {
|
||||
visibleData[uid] = visible;
|
||||
};
|
||||
}
|
||||
|
||||
const getInstance = () => {
|
||||
const instance = unref(drawer);
|
||||
if (!instance) {
|
||||
error('useDrawer instance is undefined!');
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
const methods: ReturnMethods = {
|
||||
setDrawerProps: (props: Partial<DrawerProps>): void => {
|
||||
getInstance()?.setDrawerProps(props);
|
||||
},
|
||||
|
||||
getVisible: computed((): boolean => {
|
||||
return visibleData[~~unref(uid)];
|
||||
}),
|
||||
|
||||
getOpen: computed((): boolean => {
|
||||
return visibleData[~~unref(uid)];
|
||||
}),
|
||||
|
||||
openDrawer: <T = any>(visible = true, data?: T, openOnSet = true): void => {
|
||||
// update-begin--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
getInstance()?.setDrawerProps({
|
||||
open: visible,
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
if (!data) return;
|
||||
|
||||
if (openOnSet) {
|
||||
dataTransferRef[unref(uid)] = null;
|
||||
dataTransferRef[unref(uid)] = toRaw(data);
|
||||
return;
|
||||
}
|
||||
const equal = isEqual(toRaw(dataTransferRef[unref(uid)]), toRaw(data));
|
||||
if (!equal) {
|
||||
dataTransferRef[unref(uid)] = toRaw(data);
|
||||
}
|
||||
},
|
||||
closeDrawer: () => {
|
||||
// update-begin--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
getInstance()?.setDrawerProps({ open: false });
|
||||
// update-end--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
},
|
||||
};
|
||||
|
||||
return [register, methods];
|
||||
}
|
||||
|
||||
export const useDrawerInner = (callbackFn?: Fn): UseDrawerInnerReturnType => {
|
||||
const drawerInstanceRef = ref<Nullable<DrawerInstance>>(null);
|
||||
const currentInstance = getCurrentInstance();
|
||||
const uidRef = ref<string>('');
|
||||
|
||||
if (!getCurrentInstance()) {
|
||||
throw new Error('useDrawerInner() can only be used inside setup() or functional components!');
|
||||
}
|
||||
|
||||
const getInstance = () => {
|
||||
const instance = unref(drawerInstanceRef);
|
||||
if (!instance) {
|
||||
error('useDrawerInner instance is undefined!');
|
||||
return;
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
const register = (modalInstance: DrawerInstance, uuid: string) => {
|
||||
isProdMode() &&
|
||||
tryOnUnmounted(() => {
|
||||
drawerInstanceRef.value = null;
|
||||
});
|
||||
|
||||
uidRef.value = uuid;
|
||||
drawerInstanceRef.value = modalInstance;
|
||||
currentInstance?.emit('register', modalInstance, uuid);
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
const data = dataTransferRef[unref(uidRef)];
|
||||
if (!data) return;
|
||||
if (!callbackFn || !isFunction(callbackFn)) return;
|
||||
nextTick(() => {
|
||||
callbackFn(data);
|
||||
});
|
||||
});
|
||||
|
||||
return [
|
||||
register,
|
||||
{
|
||||
changeLoading: (loading = true) => {
|
||||
getInstance()?.setDrawerProps({ loading });
|
||||
},
|
||||
|
||||
changeOkLoading: (loading = true) => {
|
||||
getInstance()?.setDrawerProps({ confirmLoading: loading });
|
||||
},
|
||||
getVisible: computed((): boolean => {
|
||||
return visibleData[~~unref(uidRef)];
|
||||
}),
|
||||
getOpen: computed((): boolean => {
|
||||
return visibleData[~~unref(uidRef)];
|
||||
}),
|
||||
closeDrawer: () => {
|
||||
getInstance()?.setDrawerProps({ open: false });
|
||||
},
|
||||
|
||||
setDrawerProps: (props: Partial<DrawerProps>) => {
|
||||
getInstance()?.setDrawerProps(props);
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
export { default as BasicTable } from './src/BasicTable.vue';
|
||||
export { default as TableAction } from './src/components/TableAction.vue';
|
||||
export { default as EditTableHeaderIcon } from './src/components/EditTableHeaderIcon.vue';
|
||||
// export { default as TableImg } from './src/components/TableImg.vue';
|
||||
export * from './src/types/table';
|
||||
// export * from './src/types/pagination';
|
||||
// export * from './src/types/tableAction';
|
||||
// export { useTable } from './src/hooks/useTable';
|
||||
// export type { FormSchema, FormProps } from '/@/components/Form/src/types/form';
|
||||
// export type { EditRecordRow } from './src/components/editable';
|
||||
@@ -1,605 +0,0 @@
|
||||
<template>
|
||||
<div ref="wrapRef" :class="getWrapperClass">
|
||||
<!-- <BasicForm
|
||||
:class="{ 'table-search-area-hidden': !getBindValues.formConfig?.schemas?.length }"
|
||||
submitOnReset
|
||||
v-bind="getFormProps"
|
||||
v-if="getBindValues.useSearchForm"
|
||||
:tableAction="tableAction"
|
||||
@register="registerForm"
|
||||
@submit="handleSearchInfoChange"
|
||||
@advanced-change="redoHeight"
|
||||
>
|
||||
<template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</BasicForm> -->
|
||||
|
||||
<!-- antd v3 升级兼容,阻止数据的收集,防止控制台报错 -->
|
||||
<!-- https://antdv.com/docs/vue/migration-v3-cn -->
|
||||
<a-form-item-rest>
|
||||
<!-- 【TV360X-377】关联记录必填影响到了table的输入框和页码样式 -->
|
||||
<a-form-item>
|
||||
<Table ref="tableElRef" v-bind="getBindValues" :rowClassName="getRowClassName" v-show="getEmptyDataIsShowTable" @resizeColumn="handleResizeColumn" @change="handleTableChange">
|
||||
<!-- antd的原生插槽直接传递 -->
|
||||
<template #[item]="data" v-for="item in slotNamesGroup.native" :key="item">
|
||||
<!-- update-begin--author:liaozhiyang---date:20240424---for:【issues/1146】BasicTable使用headerCell全选框出不来 -->
|
||||
<template v-if="item === 'headerCell'">
|
||||
<CustomSelectHeader v-if="isCustomSelection(data.column)" v-bind="selectHeaderProps" />
|
||||
<slot v-else :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<slot v-else :name="item" v-bind="data || {}"></slot>
|
||||
<!-- update-begin--author:liaozhiyang---date:20240424---for:【issues/1146】BasicTable使用headerCell全选框出不来 -->
|
||||
</template>
|
||||
<template #headerCell="{ column }">
|
||||
<!-- update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题 -->
|
||||
<CustomSelectHeader v-if="isCustomSelection(column)" v-bind="selectHeaderProps"/>
|
||||
<HeaderCell v-else :column="column" />
|
||||
<!-- update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题 -->
|
||||
</template>
|
||||
<!-- 增加对antdv3.x兼容 -->
|
||||
<template #bodyCell="data">
|
||||
<!-- update-begin--author:liaozhiyang---date:220230717---for:【issues-179】antd3 一些警告以及报错(针对表格) -->
|
||||
<!-- update-begin--author:liusq---date:20230921---for:【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
|
||||
<template v-if="data.column?.slotsBak?.customRender">
|
||||
<!-- update-end--author:liusq---date:20230921---for:【issues/770】slotsBak异常报错的问题,增加判断column是否存在 -->
|
||||
<slot :name="data.column.slotsBak.customRender" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot name="bodyCell" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<!-- update-begin--author:liaozhiyang---date:22030717---for:【issues-179】antd3 一些警告以及报错(针对表格) -->
|
||||
</template>
|
||||
<!-- update-begin--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计) -->
|
||||
<template v-if="showSummaryRef && !getBindValues.showSummary" #summary="data">
|
||||
<slot name="summary" v-bind="data || {}">
|
||||
<TableSummary :data="data || {}" v-bind="getSummaryProps" />
|
||||
</slot>
|
||||
</template>
|
||||
<!-- update-end--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计) -->
|
||||
</Table>
|
||||
</a-form-item>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { BasicTableProps, TableActionType, SizeType, ColumnChangeParam, BasicColumn } from './types/table';
|
||||
|
||||
import { defineComponent, ref, computed, unref, toRaw, inject, watchEffect, watch, onUnmounted, onMounted, nextTick } from 'vue';
|
||||
import { Table } from 'ant-design-vue';
|
||||
// import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
// import { PageWrapperFixedHeightKey } from '/@/components/Page/injectionKey';
|
||||
import CustomSelectHeader from './components/CustomSelectHeader.vue'
|
||||
import expandIcon from './components/ExpandIcon';
|
||||
// import HeaderCell from './components/HeaderCell.vue';
|
||||
import TableSummary from './components/TableSummary';
|
||||
import { InnerHandlers } from './types/table';
|
||||
import { usePagination } from './hooks/usePagination';
|
||||
import { useColumns } from './hooks/useColumns';
|
||||
import { useDataSource } from './hooks/useDataSource';
|
||||
import { useLoading } from './hooks/useLoading';
|
||||
import { useRowSelection } from './hooks/useRowSelection';
|
||||
import { useTableScroll } from './hooks/useTableScroll';
|
||||
import { useCustomRow } from './hooks/useCustomRow';
|
||||
import { useTableStyle } from './hooks/useTableStyle';
|
||||
import { useTableHeader } from './hooks/useTableHeader';
|
||||
import { useTableExpand } from './hooks/useTableExpand';
|
||||
import { createTableContext } from './hooks/useTableContext';
|
||||
import { useTableFooter } from './hooks/useTableFooter';
|
||||
import { useTableForm } from './hooks/useTableForm';
|
||||
// import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useCustomSelection } from "./hooks/useCustomSelection";
|
||||
|
||||
import { omit, pick } from 'lodash-es';
|
||||
import { basicProps } from './props';
|
||||
// import { isFunction } from '/@/utils/is';
|
||||
// import { warn } from '/@/utils/log';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Table,
|
||||
// BasicForm,
|
||||
HeaderCell,
|
||||
TableSummary,
|
||||
CustomSelectHeader,
|
||||
},
|
||||
props: basicProps,
|
||||
emits: [
|
||||
'fetch-success',
|
||||
'fetch-error',
|
||||
'selection-change',
|
||||
'register',
|
||||
'row-click',
|
||||
'row-dbClick',
|
||||
'row-contextmenu',
|
||||
'row-mouseenter',
|
||||
'row-mouseleave',
|
||||
'edit-end',
|
||||
'edit-cancel',
|
||||
'edit-row-end',
|
||||
'edit-change',
|
||||
'expanded-rows-change',
|
||||
'change',
|
||||
'columns-change',
|
||||
'table-redo',
|
||||
],
|
||||
setup(props, { attrs, emit, slots, expose }) {
|
||||
const tableElRef = ref(null);
|
||||
const tableData = ref<Recordable[]>([]);
|
||||
|
||||
const wrapRef = ref(null);
|
||||
const innerPropsRef = ref<Partial<BasicTableProps>>();
|
||||
|
||||
const { prefixCls } = useDesign('basic-table');
|
||||
const [registerForm, formActions] = useForm();
|
||||
|
||||
const getProps = computed(() => {
|
||||
return { ...props, ...unref(innerPropsRef) } as BasicTableProps;
|
||||
});
|
||||
|
||||
const isFixedHeightPage = inject(PageWrapperFixedHeightKey, false);
|
||||
watchEffect(() => {
|
||||
unref(isFixedHeightPage) &&
|
||||
props.canResize &&
|
||||
warn("'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)");
|
||||
});
|
||||
|
||||
const { getLoading, setLoading } = useLoading(getProps);
|
||||
const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } = usePagination(getProps);
|
||||
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
// const { getRowSelection, getRowSelectionRef, getSelectRows, clearSelectedRowKeys, getSelectRowKeys, deleteSelectRowByKey, setSelectedRowKeys } =
|
||||
// useRowSelection(getProps, tableData, emit);
|
||||
|
||||
// 子级列名
|
||||
const childrenColumnName = computed(() => getProps.value.childrenColumnName || 'children');
|
||||
|
||||
// 自定义选择列
|
||||
const {
|
||||
getRowSelection,
|
||||
getSelectRows,
|
||||
getSelectRowKeys,
|
||||
setSelectedRowKeys,
|
||||
getRowSelectionRef,
|
||||
selectHeaderProps,
|
||||
isCustomSelection,
|
||||
handleCustomSelectColumn,
|
||||
clearSelectedRowKeys,
|
||||
deleteSelectRowByKey,
|
||||
getExpandIconColumnIndex,
|
||||
} = useCustomSelection(
|
||||
getProps,
|
||||
emit,
|
||||
wrapRef,
|
||||
getPaginationInfo,
|
||||
tableData,
|
||||
childrenColumnName
|
||||
)
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
const {
|
||||
handleTableChange: onTableChange,
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
getRawDataSource,
|
||||
setTableData,
|
||||
updateTableDataRecord,
|
||||
deleteTableDataRecord,
|
||||
insertTableDataRecord,
|
||||
findTableDataRecord,
|
||||
fetch,
|
||||
getRowKey,
|
||||
reload,
|
||||
getAutoCreateKey,
|
||||
updateTableData,
|
||||
} = useDataSource(
|
||||
getProps,
|
||||
{
|
||||
tableData,
|
||||
getPaginationInfo,
|
||||
setLoading,
|
||||
setPagination,
|
||||
validate: formActions.validate,
|
||||
clearSelectedRowKeys,
|
||||
},
|
||||
emit
|
||||
);
|
||||
|
||||
function handleTableChange(...args) {
|
||||
onTableChange.call(undefined, ...args);
|
||||
emit('change', ...args);
|
||||
// 解决通过useTable注册onChange时不起作用的问题
|
||||
const { onChange } = unref(getProps);
|
||||
onChange && isFunction(onChange) && onChange.call(undefined, ...args);
|
||||
}
|
||||
|
||||
const { getViewColumns, getColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
|
||||
getProps,
|
||||
getPaginationInfo,
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
handleCustomSelectColumn,
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
);
|
||||
|
||||
const { getScrollRef, redoHeight } = useTableScroll(getProps, tableElRef, getColumnsRef, getRowSelectionRef, getDataSourceRef);
|
||||
|
||||
const { customRow } = useCustomRow(getProps, {
|
||||
setSelectedRowKeys,
|
||||
getSelectRowKeys,
|
||||
clearSelectedRowKeys,
|
||||
getAutoCreateKey,
|
||||
emit,
|
||||
});
|
||||
|
||||
const { getRowClassName } = useTableStyle(getProps, prefixCls);
|
||||
|
||||
const { getExpandOption, expandAll, collapseAll } = useTableExpand(getProps, tableData, emit);
|
||||
|
||||
const handlers: InnerHandlers = {
|
||||
onColumnsChange: (data: ColumnChangeParam[]) => {
|
||||
emit('columns-change', data);
|
||||
// support useTable
|
||||
unref(getProps).onColumnsChange?.(data);
|
||||
},
|
||||
};
|
||||
|
||||
const { getHeaderProps } = useTableHeader(getProps, slots, handlers);
|
||||
// update-begin--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
const getSummaryProps = computed(() => {
|
||||
return pick(unref(getProps), ['summaryFunc', 'summaryData', 'hasExpandedRow', 'rowKey']);
|
||||
});
|
||||
const getIsEmptyData = computed(() => {
|
||||
return (unref(getDataSourceRef) || []).length === 0;
|
||||
});
|
||||
const showSummaryRef = computed(() => {
|
||||
const summaryProps = unref(getSummaryProps);
|
||||
return (summaryProps.summaryFunc || summaryProps.summaryData) && !unref(getIsEmptyData);
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
|
||||
const { getFooterProps } = useTableFooter(getProps, slots, getScrollRef, tableElRef, getDataSourceRef);
|
||||
|
||||
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = useTableForm(getProps, slots, fetch, getLoading);
|
||||
|
||||
const getBindValues = computed(() => {
|
||||
const dataSource = unref(getDataSourceRef);
|
||||
let propsData: Recordable = {
|
||||
// ...(dataSource.length === 0 ? { getPopupContainer: () => document.body } : {}),
|
||||
...attrs,
|
||||
customRow,
|
||||
//树列表展开使用AntDesignVue默认的加减图标 author:scott date:20210914
|
||||
//expandIcon: slots.expandIcon ? null : expandIcon(),
|
||||
...unref(getProps),
|
||||
...unref(getHeaderProps),
|
||||
scroll: unref(getScrollRef),
|
||||
loading: unref(getLoading),
|
||||
tableLayout: 'fixed',
|
||||
rowSelection: unref(getRowSelectionRef),
|
||||
rowKey: unref(getRowKey),
|
||||
columns: toRaw(unref(getViewColumns)),
|
||||
pagination: toRaw(unref(getPaginationInfo)),
|
||||
dataSource,
|
||||
footer: unref(getFooterProps),
|
||||
...unref(getExpandOption),
|
||||
// 【QQYUN-5837】动态计算 expandIconColumnIndex
|
||||
expandIconColumnIndex: getExpandIconColumnIndex.value,
|
||||
};
|
||||
|
||||
//update-begin---author:wangshuai ---date:20230214 for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
|
||||
//额外的展开行存在插槽时会将滚动移除掉,注释掉
|
||||
/*if (slots.expandedRowRender) {
|
||||
propsData = omit(propsData, 'scroll');
|
||||
}*/
|
||||
//update-end---author:wangshuai ---date:20230214 for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
|
||||
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
// 自定义选择列,需要去掉原生的
|
||||
delete propsData.rowSelection
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
// update-begin--author:liaozhiyang---date:20230919---for:【QQYUN-6387】展开写法(去掉报错)
|
||||
!propsData.isTreeTable && delete propsData.expandIconColumnIndex;
|
||||
propsData.expandedRowKeys === null && delete propsData.expandedRowKeys;
|
||||
// update-end--author:liaozhiyang---date:20230919---for:【QQYUN-6387】展开写法(去掉报错)
|
||||
propsData = omit(propsData, ['class', 'onChange']);
|
||||
return propsData;
|
||||
});
|
||||
|
||||
// 统一设置表格列宽度
|
||||
const getMaxColumnWidth = computed(() => {
|
||||
const values = unref(getBindValues);
|
||||
return values.maxColumnWidth > 0 ? values.maxColumnWidth + 'px' : null;
|
||||
});
|
||||
|
||||
const getWrapperClass = computed(() => {
|
||||
const values = unref(getBindValues);
|
||||
return [
|
||||
prefixCls,
|
||||
attrs.class,
|
||||
{
|
||||
[`${prefixCls}-form-container`]: values.useSearchForm,
|
||||
[`${prefixCls}--inset`]: values.inset,
|
||||
[`${prefixCls}-col-max-width`]: getMaxColumnWidth.value != null,
|
||||
// 是否显示表尾合计
|
||||
[`${prefixCls}--show-summary`]: values.showSummary,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const getEmptyDataIsShowTable = computed(() => {
|
||||
const { emptyDataIsShowTable, useSearchForm } = unref(getProps);
|
||||
if (emptyDataIsShowTable || !useSearchForm) {
|
||||
return true;
|
||||
}
|
||||
return !!unref(getDataSourceRef).length;
|
||||
});
|
||||
|
||||
function setProps(props: Partial<BasicTableProps>) {
|
||||
innerPropsRef.value = { ...unref(innerPropsRef), ...props };
|
||||
}
|
||||
|
||||
const tableAction: TableActionType = {
|
||||
reload,
|
||||
getSelectRows,
|
||||
clearSelectedRowKeys,
|
||||
getSelectRowKeys,
|
||||
deleteSelectRowByKey,
|
||||
setPagination,
|
||||
setTableData,
|
||||
updateTableDataRecord,
|
||||
deleteTableDataRecord,
|
||||
insertTableDataRecord,
|
||||
findTableDataRecord,
|
||||
redoHeight,
|
||||
setSelectedRowKeys,
|
||||
setColumns,
|
||||
setLoading,
|
||||
getDataSource,
|
||||
getRawDataSource,
|
||||
setProps,
|
||||
getRowSelection,
|
||||
getPaginationRef: getPagination,
|
||||
getColumns,
|
||||
getCacheColumns,
|
||||
emit,
|
||||
updateTableData,
|
||||
setShowPagination,
|
||||
getShowPagination,
|
||||
setCacheColumnsByField,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
getSize: () => {
|
||||
return unref(getBindValues).size as SizeType;
|
||||
},
|
||||
};
|
||||
createTableContext({ ...tableAction, wrapRef, getBindValues });
|
||||
|
||||
// update-begin--author:sunjianlei---date:220230718---for:【issues/179】兼容新老slots写法,移除控制台警告
|
||||
// 获取分组之后的slot名称
|
||||
const slotNamesGroup = computed<{
|
||||
// AntTable原生插槽
|
||||
native: string[];
|
||||
// 列自定义插槽
|
||||
custom: string[];
|
||||
}>(() => {
|
||||
const native: string[] = [];
|
||||
const custom: string[] = [];
|
||||
const columns = unref<Recordable[]>(getViewColumns) as BasicColumn[];
|
||||
const allCustomRender = columns.map<string>((column) => column.slotsBak?.customRender);
|
||||
for (const name of Object.keys(slots)) {
|
||||
// 过滤特殊的插槽
|
||||
if (['bodyCell'].includes(name)) {
|
||||
continue;
|
||||
}
|
||||
if (allCustomRender.includes(name)) {
|
||||
custom.push(name);
|
||||
} else {
|
||||
native.push(name);
|
||||
}
|
||||
}
|
||||
return { native, custom };
|
||||
});
|
||||
// update-end--author:sunjianlei---date:220230718---for:【issues/179】兼容新老slots写法,移除控制台警告
|
||||
// update-begin--author:liaozhiyang---date:20231226---for:【issues/945】BasicTable组件设置默认展开不生效
|
||||
nextTick(() => {
|
||||
getProps.value.defaultExpandAllRows && expandAll();
|
||||
})
|
||||
// update-end--author:sunjianlei---date:20231226---for:【issues/945】BasicTable组件设置默认展开不生效
|
||||
expose(tableAction);
|
||||
|
||||
emit('register', tableAction, formActions);
|
||||
|
||||
|
||||
return {
|
||||
tableElRef,
|
||||
getBindValues,
|
||||
getLoading,
|
||||
registerForm,
|
||||
handleSearchInfoChange,
|
||||
getEmptyDataIsShowTable,
|
||||
handleTableChange,
|
||||
getRowClassName,
|
||||
wrapRef,
|
||||
tableAction,
|
||||
redoHeight,
|
||||
handleResizeColumn: (w, col) => {
|
||||
console.log('col',col);
|
||||
col.width = w;
|
||||
},
|
||||
getFormProps: getFormProps as any,
|
||||
replaceFormSlotKey,
|
||||
getFormSlotKeys,
|
||||
getWrapperClass,
|
||||
getMaxColumnWidth,
|
||||
columns: getViewColumns,
|
||||
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
selectHeaderProps,
|
||||
isCustomSelection,
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
slotNamesGroup,
|
||||
// update-begin--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
getSummaryProps,
|
||||
showSummaryRef,
|
||||
// update-end--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@border-color: #cecece4d;
|
||||
|
||||
@prefix-cls: ~'@{namespace}-basic-table';
|
||||
|
||||
[data-theme='dark'] {
|
||||
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
|
||||
.ant-table-tbody > tr.ant-table-row-selected td {
|
||||
background-color: #262626;
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
//表格选择工具栏样式
|
||||
.alert {
|
||||
// background-color: #323232;
|
||||
// border-color: #424242;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
max-width: 100%;
|
||||
|
||||
&-row__striped {
|
||||
td {
|
||||
background-color: @app-content-background;
|
||||
}
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240613---for:【TV360X-1232】查询区域隐藏后点击刷新不走请求了(采用css隐藏)
|
||||
> .table-search-area-hidden {
|
||||
display: none;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240613---for:【TV360X-1232】查询区域隐藏后点击刷新不走请求了(采用css隐藏)
|
||||
&-form-container {
|
||||
padding: 10px;
|
||||
|
||||
.ant-form {
|
||||
padding: 12px 10px 6px 10px;
|
||||
margin-bottom: 8px;
|
||||
background-color: @component-background;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
//update-begin-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---
|
||||
.ant-picker-preset {
|
||||
.ant-tag {
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
}
|
||||
//update-end-author:liusq---date:20230517--for: [issues/526]RangePicker 设置预设范围按钮样式问题---
|
||||
|
||||
.ant-table-wrapper {
|
||||
padding: 6px;
|
||||
background-color: @component-background;
|
||||
border-radius: 2px;
|
||||
|
||||
.ant-table-title {
|
||||
min-height: 40px;
|
||||
padding: 0 0 8px 0 !important;
|
||||
}
|
||||
|
||||
.ant-table.ant-table-bordered .ant-table-title {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
padding: 8px 6px;
|
||||
border-bottom: none;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
//定义行颜色
|
||||
.trcolor {
|
||||
background-color: rgba(255, 192, 203, 0.31);
|
||||
color: red;
|
||||
}
|
||||
|
||||
//.ant-table-tbody > tr.ant-table-row-selected td {
|
||||
//background-color: fade(@primary-color, 8%) !important;
|
||||
//}
|
||||
}
|
||||
|
||||
.ant-pagination {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.ant-table-footer {
|
||||
padding: 0;
|
||||
|
||||
.ant-table-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.ant-table-content {
|
||||
overflow-x: hidden !important;
|
||||
// overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 12px 8px;
|
||||
}
|
||||
}
|
||||
//表格选择工具栏样式
|
||||
.alert {
|
||||
height: 38px;
|
||||
// background-color: #e6f7ff;
|
||||
// border-color: #91d5ff;
|
||||
}
|
||||
&--inset {
|
||||
.ant-table-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ------ 统一设置表格列最大宽度 ------
|
||||
&-col-max-width {
|
||||
.ant-table-thead tr th,
|
||||
.ant-table-tbody tr td {
|
||||
max-width: v-bind(getMaxColumnWidth);
|
||||
}
|
||||
}
|
||||
// ------ 统一设置表格列最大宽度 ------
|
||||
|
||||
// update-begin--author:sunjianlei---date:220230718---for:【issues/622】修复表尾合计错位的问题
|
||||
&--show-summary {
|
||||
.ant-table > .ant-table-footer {
|
||||
padding: 12px 0 0;
|
||||
}
|
||||
|
||||
.ant-table.ant-table-bordered > .ant-table-footer {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
// update-end--author:sunjianlei---date:220230718---for:【issues/622】修复表尾合计错位的问题
|
||||
// update-begin--author:liaozhiyang---date:20240604---for:【TV360X-377】关联记录必填影响到了table的输入框和页码样式
|
||||
> .ant-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240604---for:【TV360X-377】关联记录必填影响到了table的输入框和页码样式
|
||||
}
|
||||
</style>
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { Component } from 'vue';
|
||||
import { Input, Select, Checkbox, InputNumber, Switch, DatePicker, TimePicker } from 'ant-design-vue';
|
||||
import type { ComponentType } from './types/componentType';
|
||||
import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
|
||||
|
||||
const componentMap = new Map<ComponentType, Component>();
|
||||
|
||||
componentMap.set('Input', Input);
|
||||
componentMap.set('InputNumber', InputNumber);
|
||||
componentMap.set('Select', Select);
|
||||
componentMap.set('ApiSelect', ApiSelect);
|
||||
componentMap.set('ApiTreeSelect', ApiTreeSelect);
|
||||
componentMap.set('Switch', Switch);
|
||||
componentMap.set('Checkbox', Checkbox);
|
||||
componentMap.set('DatePicker', DatePicker);
|
||||
componentMap.set('TimePicker', TimePicker);
|
||||
|
||||
export function add(compName: ComponentType, component: Component) {
|
||||
componentMap.set(compName, component);
|
||||
}
|
||||
|
||||
export function del(compName: ComponentType) {
|
||||
componentMap.delete(compName);
|
||||
}
|
||||
|
||||
export { componentMap };
|
||||
@@ -1,67 +0,0 @@
|
||||
<!-- 自定义选择列,表头实现部分 -->
|
||||
<template>
|
||||
<!-- update-begin--author:liaozhiyang---date:20231130---for:【issues/5595】BasicTable组件hideSelectAll: true无法隐藏全选框 -->
|
||||
<template v-if="isRadio">
|
||||
<!-- radio不存在全选,所以放个空标签 -->
|
||||
<span></span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="hideSelectAll">
|
||||
<span></span>
|
||||
</template>
|
||||
<a-checkbox :disabled="disabled" v-else :checked="checked" :indeterminate="isHalf" @update:checked="onChange" />
|
||||
</template>
|
||||
<!-- update-end--author:liaozhiyang---date:20231130---for:【issues/5595】BasicTable组件hideSelectAll: true无法隐藏全选框 -->
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
isRadio: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
selectedLength: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
// 当前页条目数
|
||||
pageSize: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
hideSelectAll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20231016---for:【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20231016---for:【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
});
|
||||
const emit = defineEmits(['select-all']);
|
||||
|
||||
// 是否全选
|
||||
const checked = computed(() => {
|
||||
if (props.isRadio) {
|
||||
return false;
|
||||
}
|
||||
return props.selectedLength > 0 && props.selectedLength >= props.pageSize;
|
||||
});
|
||||
|
||||
// 是否半选
|
||||
const isHalf = computed(() => {
|
||||
if (props.isRadio) {
|
||||
return false;
|
||||
}
|
||||
return props.selectedLength > 0 && props.selectedLength < props.pageSize;
|
||||
});
|
||||
|
||||
function onChange(checked: boolean) {
|
||||
emit('select-all', checked);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<slot></slot>
|
||||
{{ title }}
|
||||
<FormOutlined />
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { FormOutlined } from '@ant-design/icons-vue';
|
||||
export default defineComponent({
|
||||
name: 'EditTableHeaderIcon',
|
||||
components: { FormOutlined },
|
||||
props: { title: { type: String, default: '' } },
|
||||
});
|
||||
</script>
|
||||
@@ -1,23 +0,0 @@
|
||||
import { BasicArrow } from '/@/components/Basic';
|
||||
|
||||
export default () => {
|
||||
return (props: Recordable) => {
|
||||
if (!props.expandable) {
|
||||
if (props.needIndentSpaced) {
|
||||
return <span class="ant-table-row-expand-icon ant-table-row-spaced" />;
|
||||
} else {
|
||||
return <span />;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<BasicArrow
|
||||
style="margin-right: 8px"
|
||||
iconStyle="margin-top: -2px;"
|
||||
onClick={(e: Event) => {
|
||||
props.onExpand(props.record, e);
|
||||
}}
|
||||
expand={props.expanded}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<EditTableHeaderCell v-if="getIsEdit">
|
||||
{{ getTitle }}
|
||||
</EditTableHeaderCell>
|
||||
<span v-else>{{ getTitle }}</span>
|
||||
<BasicHelp v-if="getHelpMessage" :text="getHelpMessage" :class="`${prefixCls}__help`" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import type { BasicColumn } from '../types/table';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import BasicHelp from '/@/components/Basic/src/BasicHelp.vue';
|
||||
import EditTableHeaderCell from './EditTableHeaderIcon.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableHeaderCell',
|
||||
components: {
|
||||
EditTableHeaderCell,
|
||||
BasicHelp,
|
||||
},
|
||||
props: {
|
||||
column: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('basic-table-header-cell');
|
||||
|
||||
const getIsEdit = computed(() => !!props.column?.edit);
|
||||
const getTitle = computed(() => {
|
||||
// update-begin--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
const result = props.column?.customTitle || props.column?.title;
|
||||
if (typeof result === 'string') {
|
||||
return result;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231218---for:【QQYUN-6366】升级到antd4.x
|
||||
});
|
||||
const getHelpMessage = computed(() => props.column?.helpMessage);
|
||||
|
||||
return { prefixCls, getIsEdit, getTitle, getHelpMessage };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table-header-cell';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&__help {
|
||||
margin-left: 8px;
|
||||
color: rgb(0 0 0 / 65%) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,283 +0,0 @@
|
||||
<template>
|
||||
<div :class="[prefixCls, getAlign]" @click="onCellClick">
|
||||
<template v-for="(action, index) in getActions" :key="`${index}-${action.label}`">
|
||||
<template v-if="action.slot">
|
||||
<slot name="customButton"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Tooltip v-if="action.tooltip" v-bind="getTooltip(action.tooltip)">
|
||||
<PopConfirmButton v-bind="action">
|
||||
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
|
||||
<template v-if="action.label">{{ action.label }}</template>
|
||||
</PopConfirmButton>
|
||||
</Tooltip>
|
||||
<PopConfirmButton v-else v-bind="action">
|
||||
<Icon :icon="action.icon" :class="{ 'mr-1': !!action.label }" v-if="action.icon" />
|
||||
<template v-if="action.label">{{ action.label }}</template>
|
||||
</PopConfirmButton>
|
||||
</template>
|
||||
|
||||
<Divider type="vertical" class="action-divider" v-if="divider && index < getActions.length - 1" />
|
||||
</template>
|
||||
<Dropdown
|
||||
:overlayClassName="dropdownCls"
|
||||
:trigger="['hover']"
|
||||
:dropMenuList="getDropdownList"
|
||||
popconfirm
|
||||
v-if="dropDownActions && getDropdownList.length > 0"
|
||||
>
|
||||
<slot name="more"></slot>
|
||||
<!-- 设置插槽 -->
|
||||
<template v-slot:[item.slot] v-for="(item, index) in getDropdownSlotList" :key="`${index}-${item.label}`">
|
||||
<slot :name="item.slot"></slot>
|
||||
</template>
|
||||
|
||||
<a-button type="link" size="small" v-if="!$slots.more"> 更多 <Icon icon="mdi-light:chevron-down"></Icon> </a-button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, toRaw, unref } from 'vue';
|
||||
import { MoreOutlined } from '@ant-design/icons-vue';
|
||||
import { Divider, Tooltip, TooltipProps } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { ActionItem, TableActionType } from '/@/components/Table';
|
||||
import { PopConfirmButton } from '/@/components/Button';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
import { isBoolean, isFunction, isString } from '/@/utils/is';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ACTION_COLUMN_FLAG } from '../const';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableAction',
|
||||
components: { Icon, PopConfirmButton, Divider, Dropdown, MoreOutlined, Tooltip },
|
||||
props: {
|
||||
actions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
},
|
||||
dropDownActions: {
|
||||
type: Array as PropType<ActionItem[]>,
|
||||
default: null,
|
||||
},
|
||||
divider: propTypes.bool.def(true),
|
||||
outside: propTypes.bool,
|
||||
stopButtonPropagation: propTypes.bool.def(false),
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('basic-table-action');
|
||||
const dropdownCls = `${prefixCls}-dropdown`;
|
||||
let table: Partial<TableActionType> = {};
|
||||
if (!props.outside) {
|
||||
table = useTableContext();
|
||||
}
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
function isIfShow(action: ActionItem): boolean {
|
||||
const ifShow = action.ifShow;
|
||||
|
||||
let isIfShow = true;
|
||||
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(action);
|
||||
}
|
||||
return isIfShow;
|
||||
}
|
||||
|
||||
const getActions = computed(() => {
|
||||
return (toRaw(props.actions) || [])
|
||||
.filter((action) => {
|
||||
return hasPermission(action.auth) && isIfShow(action);
|
||||
})
|
||||
.map((action) => {
|
||||
const { popConfirm } = action;
|
||||
// update-begin--author:liaozhiyang---date:20240105---for:【issues/951】table删除记录时按钮显示错位
|
||||
if (popConfirm) {
|
||||
const overlayClassName = popConfirm.overlayClassName;
|
||||
popConfirm.overlayClassName = `${overlayClassName ? overlayClassName : ''} ${prefixCls}-popconfirm`;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240105---for:【issues/951】table删除记录时按钮显示错位
|
||||
return {
|
||||
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
|
||||
type: 'link',
|
||||
size: 'small',
|
||||
...action,
|
||||
...(popConfirm || {}),
|
||||
// update-begin--author:liaozhiyang---date:20240108---for:【issues/936】表格操作栏删除当接口失败时,气泡确认框不会消失
|
||||
onConfirm: handelConfirm(popConfirm?.confirm),
|
||||
// update-end--author:liaozhiyang---date:20240108---for:【issues/936】表格操作栏删除当接口失败时,气泡确认框不会消失
|
||||
onCancel: popConfirm?.cancel,
|
||||
enable: !!popConfirm,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const getDropdownList = computed((): any[] => {
|
||||
//过滤掉隐藏的dropdown,避免出现多余的分割线
|
||||
const list = (toRaw(props.dropDownActions) || []).filter((action) => {
|
||||
return hasPermission(action.auth) && isIfShow(action);
|
||||
});
|
||||
return list.map((action, index) => {
|
||||
const { label, popConfirm } = action;
|
||||
// update-begin--author:liaozhiyang---date:20240105---for:【issues/951】table删除记录时按钮显示错位
|
||||
if (popConfirm) {
|
||||
const overlayClassName = popConfirm.overlayClassName;
|
||||
popConfirm.overlayClassName = `${overlayClassName ? overlayClassName : ''} ${prefixCls}-popconfirm`;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240105---for:【issues/951】table删除记录时按钮显示错位
|
||||
// update-begin--author:liaozhiyang---date:20240108---for:【issues/936】表格操作栏删除当接口失败时,气泡确认框不会消失
|
||||
if (popConfirm) {
|
||||
popConfirm.confirm = handelConfirm(popConfirm?.confirm);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240108---for:【issues/936】表格操作栏删除当接口失败时,气泡确认框不会消失
|
||||
return {
|
||||
...action,
|
||||
...popConfirm,
|
||||
onConfirm: handelConfirm(popConfirm?.confirm),
|
||||
onCancel: popConfirm?.cancel,
|
||||
text: label,
|
||||
divider: index < list.length - 1 ? props.divider : false,
|
||||
};
|
||||
});
|
||||
});
|
||||
/*
|
||||
2023-01-08
|
||||
liaozhiyang
|
||||
给传进来的函数包一层promise
|
||||
*/
|
||||
const handelConfirm = (fn) => {
|
||||
if (typeof fn !== 'function') return fn;
|
||||
const anyc = () => {
|
||||
return new Promise<void>((resolve) => {
|
||||
const result = fn();
|
||||
if (Object.prototype.toString.call(result) === '[object Promise]') {
|
||||
result
|
||||
.finally(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
};
|
||||
return anyc;
|
||||
};
|
||||
const getDropdownSlotList = computed((): any[] => {
|
||||
return unref(getDropdownList).filter((item) => item.slot);
|
||||
});
|
||||
const getAlign = computed(() => {
|
||||
const columns = (table as TableActionType)?.getColumns?.() || [];
|
||||
const actionColumn = columns.find((item) => item.flag === ACTION_COLUMN_FLAG);
|
||||
return actionColumn?.align ?? 'left';
|
||||
});
|
||||
|
||||
function getTooltip(data: string | TooltipProps): TooltipProps {
|
||||
return {
|
||||
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
|
||||
placement: 'bottom',
|
||||
...(isString(data) ? { title: data } : data),
|
||||
};
|
||||
}
|
||||
|
||||
function onCellClick(e: MouseEvent) {
|
||||
if (!props.stopButtonPropagation) return;
|
||||
const path = e.composedPath() as HTMLElement[];
|
||||
const isInButton = path.find((ele) => {
|
||||
return ele.tagName?.toUpperCase() === 'BUTTON';
|
||||
});
|
||||
isInButton && e.stopPropagation();
|
||||
}
|
||||
|
||||
return { prefixCls, getActions, getDropdownList, getDropdownSlotList, getAlign, onCellClick, getTooltip, dropdownCls };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table-action';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* update-begin-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/
|
||||
height: 22px;
|
||||
/* update-end-author:taoyan date:2022-11-18 for: 表格默认行高比官方示例多出2px*/
|
||||
|
||||
.action-divider {
|
||||
display: table;
|
||||
}
|
||||
|
||||
&.left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
button.ant-btn-circle {
|
||||
span {
|
||||
margin: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-divider,
|
||||
.ant-divider-vertical {
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.icon-more {
|
||||
transform: rotate(90deg);
|
||||
|
||||
svg {
|
||||
font-size: 1.1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
&-popconfirm {
|
||||
.ant-popconfirm-buttons {
|
||||
min-width: 120px;
|
||||
// update-begin--author:liaozhiyang---date:20240124---for:【issues/1019】popConfirm确认框待端后端返回过程中(处理中)样式错乱
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// update-end--author:liaozhiyang---date:20240124---for:【issues/1019】popConfirm确认框待端后端返回过程中(处理中)样式错乱
|
||||
}
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】调整table操作栏ant-dropdown样式
|
||||
&-dropdown {
|
||||
.ant-dropdown-menu .ant-dropdown-menu-item-divider {
|
||||
margin: 2px 0;
|
||||
}
|
||||
.ant-dropdown-menu .ant-dropdown-menu-item {
|
||||
padding: 3px 8px;
|
||||
font-size: 13.6px;
|
||||
}
|
||||
.dropdown-event-area {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】调整table操作栏ant-dropdown样式
|
||||
}
|
||||
</style>
|
||||
@@ -1,134 +0,0 @@
|
||||
<template>
|
||||
<Table
|
||||
v-if="summaryFunc || summaryData"
|
||||
:showHeader="false"
|
||||
:bordered="bordered"
|
||||
:pagination="false"
|
||||
:dataSource="getDataSource"
|
||||
:rowKey="(r) => r[rowKey]"
|
||||
:columns="getColumns"
|
||||
tableLayout="fixed"
|
||||
:scroll="scroll"
|
||||
/>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import { defineComponent, unref, computed, toRaw } from 'vue';
|
||||
import { Table } from 'ant-design-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import type { BasicColumn } from '../types/table';
|
||||
import { INDEX_COLUMN_FLAG } from '../const';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
|
||||
const SUMMARY_ROW_KEY = '_row';
|
||||
const SUMMARY_INDEX_KEY = '_index';
|
||||
export default defineComponent({
|
||||
name: 'BasicTableFooter',
|
||||
components: { Table },
|
||||
props: {
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
summaryFunc: {
|
||||
type: Function as PropType<Fn>,
|
||||
},
|
||||
summaryData: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
},
|
||||
scroll: {
|
||||
type: Object as PropType<Recordable>,
|
||||
},
|
||||
rowKey: propTypes.string.def('key'),
|
||||
// 是否有展开列
|
||||
hasExpandedRow: propTypes.bool,
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
|
||||
const getDataSource = computed((): Recordable[] => {
|
||||
const { summaryFunc, summaryData } = props;
|
||||
if (summaryData?.length) {
|
||||
summaryData.forEach((item, i) => (item[props.rowKey] = `${i}`));
|
||||
return summaryData;
|
||||
}
|
||||
if (!isFunction(summaryFunc)) {
|
||||
return [];
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20230227---for:【QQYUN-8172】可编辑单元格编辑完以后不更新合计值
|
||||
let dataSource = cloneDeep(unref(table.getDataSource()));
|
||||
// update-end--author:liaozhiyang---date:20230227---for:【QQYUN-8172】可编辑单元格编辑完以后不更新合计值
|
||||
dataSource = summaryFunc(dataSource);
|
||||
dataSource.forEach((item, i) => {
|
||||
item[props.rowKey] = `${i}`;
|
||||
});
|
||||
return dataSource;
|
||||
});
|
||||
|
||||
const getColumns = computed(() => {
|
||||
const dataSource = unref(getDataSource);
|
||||
let columns: BasicColumn[] = cloneDeep(table.getColumns());
|
||||
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||
columns = columns.filter((item) => !item.defaultHidden);
|
||||
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||
const index = columns.findIndex((item) => item.flag === INDEX_COLUMN_FLAG);
|
||||
const hasRowSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_ROW_KEY));
|
||||
const hasIndexSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_INDEX_KEY));
|
||||
|
||||
// 是否有序号列
|
||||
let hasIndexCol = false;
|
||||
// 是否有选择列
|
||||
let hasSelection = table.getRowSelection() && hasRowSummary
|
||||
|
||||
if (index !== -1) {
|
||||
if (hasIndexSummary) {
|
||||
hasIndexCol = true;
|
||||
columns[index].customRender = ({ record }) => record[SUMMARY_INDEX_KEY];
|
||||
columns[index].ellipsis = false;
|
||||
} else {
|
||||
Reflect.deleteProperty(columns[index], 'customRender');
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSelection) {
|
||||
// update-begin--author:liaozhiyang---date:20231009---for:【issues/776】显示100条/页,复选框只能显示3个的问题(fixed也有可能设置true)
|
||||
const isFixed = columns.some((col) => col.fixed === 'left' || col.fixed === true);
|
||||
// update-begin--author:liaozhiyang---date:20231009---for:【issues/776】显示100条/页,复选框只能显示3个的问题(fixed也有可能设置true)
|
||||
columns.unshift({
|
||||
width: 50,
|
||||
title: 'selection',
|
||||
key: 'selectionKey',
|
||||
align: 'center',
|
||||
...(isFixed ? { fixed: 'left' } : {}),
|
||||
customRender: ({ record }) => hasIndexCol ? '' : record[SUMMARY_ROW_KEY],
|
||||
});
|
||||
}
|
||||
|
||||
if (props.hasExpandedRow) {
|
||||
const isFixed = columns.some((col) => col.fixed === 'left');
|
||||
columns.unshift({
|
||||
width: 50,
|
||||
title: 'expandedRow',
|
||||
key: 'expandedRowKey',
|
||||
align: 'center',
|
||||
...(isFixed ? { fixed: 'left' } : {}),
|
||||
customRender: () => '',
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
});
|
||||
return { getColumns, getDataSource };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// update-begin--author:liaozhiyang---date:20231009---for:【issues/776】显示100条/页,复选框只能显示3个的问题(隐藏合计的滚动条)
|
||||
.ant-table-wrapper {
|
||||
:deep(.ant-table-body) {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231009---for:【issues/776】显示100条/页,复选框只能显示3个的问题(隐藏合计的滚动条)
|
||||
</style>
|
||||
@@ -1,165 +0,0 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div v-if="$slots.headerTop" style="margin: 5px">
|
||||
<slot name="headerTop"></slot>
|
||||
</div>
|
||||
<div :class="`flex items-center ${prefixCls}__table-title-box`">
|
||||
<div :class="`${prefixCls}__tableTitle`">
|
||||
<slot name="tableTitle" v-if="$slots.tableTitle"></slot>
|
||||
<!--修改标题插槽位置-->
|
||||
<TableTitle :helpMessage="titleHelpMessage" :title="title" v-if="!$slots.tableTitle && title" />
|
||||
</div>
|
||||
|
||||
<div :class="`${prefixCls}__toolbar`">
|
||||
<slot name="toolbar"></slot>
|
||||
<Divider type="vertical" v-if="$slots.toolbar && showTableSetting" />
|
||||
<TableSetting :class="`${prefixCls}__toolbar-desktop`" style="white-space: nowrap;" :setting="tableSetting" v-if="showTableSetting" @columns-change="handleColumnChange" />
|
||||
<a-popover :overlayClassName="`${prefixCls}__toolbar-mobile`" trigger="click" placement="left" :getPopupContainer="(n) => n?.parentElement">
|
||||
<template #content>
|
||||
<TableSetting mode="mobile" :setting="tableSetting" v-if="showTableSetting" @columns-change="handleColumnChange" />
|
||||
</template>
|
||||
<a-button :class="`${prefixCls}__toolbar-mobile`" v-if="showTableSetting" type="text" preIcon="ant-design:menu" shape="circle" />
|
||||
</a-popover>
|
||||
</div>
|
||||
</div>
|
||||
<!--添加tableTop插槽-->
|
||||
<div style="margin: -4px 0 -2px; padding-top: 5px">
|
||||
<slot name="tableTop">
|
||||
<a-alert type="info" show-icon class="alert" v-if="openRowSelection != null">
|
||||
<template #message>
|
||||
<template v-if="selectRowKeys.length > 0">
|
||||
<span>
|
||||
<span>已选中 {{ selectRowKeys.length }} 条记录</span>
|
||||
<span v-if="isAcrossPage">(可跨页)</span>
|
||||
</span>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="setSelectedRowKeys([])">清空</a>
|
||||
<slot name="alertAfter" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>未选中任何数据</span>
|
||||
</template>
|
||||
</template>
|
||||
</a-alert>
|
||||
</slot>
|
||||
</div>
|
||||
<!--添加tableTop插槽-->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { TableSetting, ColumnChangeParam } from '../types/table';
|
||||
import type { PropType } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import TableSettingComponent from './settings/index.vue';
|
||||
import TableTitle from './TableTitle.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicTableHeader',
|
||||
components: {
|
||||
Divider,
|
||||
TableTitle,
|
||||
TableSetting: TableSettingComponent,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: [Function, String] as PropType<string | ((data: Recordable) => string)>,
|
||||
},
|
||||
tableSetting: {
|
||||
type: Object as PropType<TableSetting>,
|
||||
},
|
||||
showTableSetting: {
|
||||
type: Boolean,
|
||||
},
|
||||
titleHelpMessage: {
|
||||
type: [String, Array] as PropType<string | string[]>,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['columns-change'],
|
||||
setup(_, { emit }) {
|
||||
const { prefixCls } = useDesign('basic-table-header');
|
||||
|
||||
function handleColumnChange(data: ColumnChangeParam[]) {
|
||||
emit('columns-change', data);
|
||||
}
|
||||
|
||||
const { getSelectRowKeys, setSelectedRowKeys, getRowSelection } = useTableContext();
|
||||
const selectRowKeys = computed(() => getSelectRowKeys());
|
||||
const openRowSelection = computed(() => getRowSelection());
|
||||
// 是否允许跨页选择
|
||||
const isAcrossPage = computed(() => openRowSelection.value?.preserveSelectedRowKeys === true);
|
||||
|
||||
return { prefixCls, handleColumnChange, selectRowKeys, setSelectedRowKeys, openRowSelection, isAcrossPage };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table-header';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&__toolbar {
|
||||
//flex: 1;
|
||||
width: 140px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
> * {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&-desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&__tableTitle {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
|
||||
> * {
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-lg) {
|
||||
&__table-title-box {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
&__toolbar {
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
|
||||
> * {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.table-settings > * {
|
||||
margin-right: 0;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
&-desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-mobile {
|
||||
display: block;
|
||||
.table-settings > * {
|
||||
margin-right: 6px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,76 +0,0 @@
|
||||
<template>
|
||||
<div :class="prefixCls" class="flex items-center mx-auto" v-if="imgList && imgList.length" :style="getWrapStyle">
|
||||
<Badge :count="!showBadge || imgList.length == 1 ? 0 : imgList.length" v-if="simpleShow">
|
||||
<div class="img-div">
|
||||
<PreviewGroup>
|
||||
<template v-for="(img, index) in imgList" :key="img">
|
||||
<Image
|
||||
:width="size"
|
||||
:style="{
|
||||
display: index === 0 ? '' : 'none !important',
|
||||
}"
|
||||
:src="srcPrefix + img"
|
||||
/>
|
||||
</template>
|
||||
</PreviewGroup>
|
||||
</div>
|
||||
</Badge>
|
||||
<PreviewGroup v-else>
|
||||
<template v-for="(img, index) in imgList" :key="img">
|
||||
<Image :width="size" :style="{ marginLeft: index === 0 ? 0 : margin }" :src="srcPrefix + img" />
|
||||
</template>
|
||||
</PreviewGroup>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { Image, Badge } from 'ant-design-vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableImage',
|
||||
components: { Image, PreviewGroup: Image.PreviewGroup, Badge },
|
||||
props: {
|
||||
imgList: propTypes.arrayOf(propTypes.string),
|
||||
size: propTypes.number.def(40),
|
||||
// 是否简单显示(只显示第一张图片)
|
||||
simpleShow: propTypes.bool,
|
||||
// 简单模式下是否显示图片数量的badge
|
||||
showBadge: propTypes.bool.def(true),
|
||||
// 图片间距
|
||||
margin: propTypes.number.def(4),
|
||||
// src前缀,将会附加在imgList中每一项之前
|
||||
srcPrefix: propTypes.string.def(''),
|
||||
},
|
||||
setup(props) {
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
const { size } = props;
|
||||
const s = `${size}px`;
|
||||
return { height: s, width: s };
|
||||
});
|
||||
|
||||
const { prefixCls } = useDesign('basic-table-img');
|
||||
return { prefixCls, getWrapStyle };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table-img';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-image {
|
||||
margin-right: 4px;
|
||||
cursor: zoom-in;
|
||||
|
||||
img {
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.img-div {
|
||||
display: inline-grid;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,163 +0,0 @@
|
||||
import type { PropType, VNode } from 'vue';
|
||||
import { defineComponent, unref, computed, isVNode } from 'vue';
|
||||
import { cloneDeep, pick } from 'lodash-es';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import type { BasicColumn } from '../types/table';
|
||||
import { INDEX_COLUMN_FLAG } from '../const';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useTableContext } from '../hooks/useTableContext';
|
||||
import { TableSummary, TableSummaryRow, TableSummaryCell } from 'ant-design-vue';
|
||||
|
||||
const SUMMARY_ROW_KEY = '_row';
|
||||
const SUMMARY_INDEX_KEY = '_index';
|
||||
export default defineComponent({
|
||||
name: 'BasicTableSummary',
|
||||
components: { TableSummary, TableSummaryRow, TableSummaryCell },
|
||||
props: {
|
||||
summaryFunc: {
|
||||
type: Function as PropType<Fn>,
|
||||
},
|
||||
summaryData: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
},
|
||||
rowKey: propTypes.string.def('key'),
|
||||
// 是否有展开列
|
||||
hasExpandedRow: propTypes.bool,
|
||||
data: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
|
||||
const getDataSource = computed((): Recordable[] => {
|
||||
const {
|
||||
summaryFunc,
|
||||
summaryData,
|
||||
data: { pageData },
|
||||
} = props;
|
||||
if (summaryData?.length) {
|
||||
summaryData.forEach((item, i) => (item[props.rowKey] = `${i}`));
|
||||
return summaryData;
|
||||
}
|
||||
if (!isFunction(summaryFunc)) {
|
||||
return [];
|
||||
}
|
||||
let dataSource = cloneDeep(unref(pageData));
|
||||
dataSource = summaryFunc(dataSource);
|
||||
dataSource.forEach((item, i) => {
|
||||
item[props.rowKey] = `${i}`;
|
||||
});
|
||||
return dataSource;
|
||||
});
|
||||
|
||||
const getColumns = computed(() => {
|
||||
const dataSource = unref(getDataSource);
|
||||
let columns: BasicColumn[] = cloneDeep(table.getColumns({ sort: true }));
|
||||
columns = columns.filter((item) => !item.defaultHidden);
|
||||
const index = columns.findIndex((item) => item.flag === INDEX_COLUMN_FLAG);
|
||||
const hasRowSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_ROW_KEY));
|
||||
const hasIndexSummary = dataSource.some((item) => Reflect.has(item, SUMMARY_INDEX_KEY));
|
||||
|
||||
// 是否有序号列
|
||||
let hasIndexCol = false;
|
||||
// 是否有选择列
|
||||
const hasSelection = table.getRowSelection() && hasRowSummary;
|
||||
|
||||
if (index !== -1) {
|
||||
if (hasIndexSummary) {
|
||||
hasIndexCol = true;
|
||||
columns[index].customSummaryRender = ({ record }) => record[SUMMARY_INDEX_KEY];
|
||||
columns[index].ellipsis = false;
|
||||
} else {
|
||||
Reflect.deleteProperty(columns[index], 'customSummaryRender');
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSelection) {
|
||||
const isFixed = columns.some((col) => col.fixed === 'left' || col.fixed === true);
|
||||
columns.unshift({
|
||||
width: 60,
|
||||
title: 'selection',
|
||||
key: 'selectionKey',
|
||||
align: 'center',
|
||||
...(isFixed ? { fixed: 'left' } : {}),
|
||||
customSummaryRender: ({ record }) => (hasIndexCol ? '' : record[SUMMARY_ROW_KEY]),
|
||||
});
|
||||
}
|
||||
|
||||
if (props.hasExpandedRow) {
|
||||
const isFixed = columns.some((col) => col.fixed === 'left');
|
||||
columns.unshift({
|
||||
width: 50,
|
||||
title: 'expandedRow',
|
||||
key: 'expandedRowKey',
|
||||
align: 'center',
|
||||
...(isFixed ? { fixed: 'left' } : {}),
|
||||
customSummaryRender: () => '',
|
||||
});
|
||||
}
|
||||
return columns;
|
||||
});
|
||||
|
||||
function isRenderCell(data: any) {
|
||||
return data && typeof data === 'object' && !Array.isArray(data) && !isVNode(data);
|
||||
}
|
||||
|
||||
const getValues = (row: Recordable, col: BasicColumn, index: number) => {
|
||||
const value = row[col.dataIndex as string];
|
||||
let childNode: VNode | JSX.Element | string | number | undefined | null;
|
||||
childNode = value;
|
||||
if (col.customSummaryRender) {
|
||||
const renderData = col.customSummaryRender({
|
||||
text: value,
|
||||
value,
|
||||
record: row,
|
||||
index,
|
||||
column: cloneDeep(col),
|
||||
});
|
||||
if (isRenderCell(renderData)) {
|
||||
childNode = renderData.children;
|
||||
} else {
|
||||
childNode = renderData;
|
||||
}
|
||||
if (typeof childNode === 'object' && !Array.isArray(childNode) && !isVNode(childNode)) {
|
||||
childNode = null;
|
||||
}
|
||||
if (Array.isArray(childNode) && childNode.length === 1) {
|
||||
childNode = childNode[0];
|
||||
}
|
||||
return childNode;
|
||||
}
|
||||
return childNode;
|
||||
};
|
||||
|
||||
const getCellProps = (col: BasicColumn) => {
|
||||
const cellProps = pick(col, ['colSpan', 'rowSpan', 'align']);
|
||||
return {
|
||||
...cellProps,
|
||||
};
|
||||
};
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<TableSummary fixed>
|
||||
{(unref(getDataSource) || []).map((row) => {
|
||||
return (
|
||||
<TableSummaryRow key={row[props.rowKey]}>
|
||||
{unref(getColumns).map((col, index) => {
|
||||
return (
|
||||
<TableSummaryCell {...getCellProps(col)} index={index} key={`${row[props.rowKey]}_${col.dataIndex}_${index}`}>
|
||||
{getValues(row, col, index)}
|
||||
</TableSummaryCell>
|
||||
);
|
||||
})}
|
||||
</TableSummaryRow>
|
||||
);
|
||||
})}
|
||||
</TableSummary>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<BasicTitle :class="prefixCls" v-if="getTitle" :helpMessage="helpMessage">
|
||||
{{ getTitle }}
|
||||
</BasicTitle>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import { BasicTitle } from '/@/components/Basic/index';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicTableTitle',
|
||||
components: { BasicTitle },
|
||||
props: {
|
||||
title: {
|
||||
type: [Function, String] as PropType<string | ((data: Recordable) => string)>,
|
||||
},
|
||||
getSelectRows: {
|
||||
type: Function as PropType<() => Recordable[]>,
|
||||
},
|
||||
helpMessage: {
|
||||
type: [String, Array] as PropType<string | string[]>,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('basic-table-title');
|
||||
|
||||
const getTitle = computed(() => {
|
||||
const { title, getSelectRows = () => {} } = props;
|
||||
let tit = title;
|
||||
|
||||
if (isFunction(title)) {
|
||||
tit = title({
|
||||
selectRows: getSelectRows(),
|
||||
});
|
||||
}
|
||||
return tit;
|
||||
});
|
||||
|
||||
return { getTitle, prefixCls };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-table-title';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { FunctionalComponent, defineComponent } from 'vue';
|
||||
import type { ComponentType } from '../../types/componentType';
|
||||
import { componentMap } from '/@/components/Table/src/componentMap';
|
||||
|
||||
import { Popover } from 'ant-design-vue';
|
||||
import { h } from 'vue';
|
||||
|
||||
export interface ComponentProps {
|
||||
component: ComponentType;
|
||||
rule: boolean;
|
||||
popoverVisible: boolean;
|
||||
ruleMessage: string;
|
||||
getPopupContainer?: Fn;
|
||||
}
|
||||
|
||||
export const CellComponent: FunctionalComponent = (
|
||||
{ component = 'Input', rule = true, ruleMessage, popoverVisible, getPopupContainer }: ComponentProps,
|
||||
{ attrs }
|
||||
) => {
|
||||
const Comp = componentMap.get(component) as typeof defineComponent;
|
||||
|
||||
const DefaultComp = h(Comp, attrs);
|
||||
if (!rule) {
|
||||
return DefaultComp;
|
||||
}
|
||||
return h(
|
||||
Popover,
|
||||
{
|
||||
overlayClassName: 'edit-cell-rule-popover',
|
||||
open: !!popoverVisible,
|
||||
...(getPopupContainer ? { getPopupContainer } : {}),
|
||||
},
|
||||
{
|
||||
default: () => DefaultComp,
|
||||
content: () => ruleMessage,
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -1,508 +0,0 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div v-show="!isEdit" :class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }" @click="handleEdit">
|
||||
<div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">
|
||||
<!-- update-begin--author:liaozhiyang---date:20240731---for:【issues/6957】editableCell组件值长度为0,无法编辑 -->
|
||||
<!-- update-begin--author:liaozhiyang---date:20240709---for:【issues/6851】editableCell组件值为0时不展示 -->
|
||||
{{ typeof getValues === 'string' && getValues.length === 0 ? ' ' : getValues ?? ' ' }}
|
||||
<!-- update-end--author:liaozhiyang---date:20240709---for:【issues/6851】editableCell组件值为0时不展示 -->
|
||||
<!-- update-end--author:liaozhiyang---date:20240731---for:【issues/6957】editableCell组件值长度为0,无法编辑 -->
|
||||
</div>
|
||||
<FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" />
|
||||
</div>
|
||||
|
||||
<a-spin v-if="isEdit" :spinning="spinning">
|
||||
<div :class="`${prefixCls}__wrapper`" v-click-outside="onClickOutside">
|
||||
<CellComponent
|
||||
v-bind="getComponentProps"
|
||||
:component="getComponent"
|
||||
:style="getWrapperStyle"
|
||||
:popoverVisible="getRuleVisible"
|
||||
:rule="getRule"
|
||||
:ruleMessage="ruleMessage"
|
||||
:class="getWrapperClass"
|
||||
ref="elRef"
|
||||
@change="handleChange"
|
||||
@options-change="handleOptionsChange"
|
||||
@pressEnter="handleEnter"
|
||||
/>
|
||||
<div :class="`${prefixCls}__action`" v-if="!getRowEditable">
|
||||
<CheckOutlined :class="[`${prefixCls}__icon`, 'mx-2']" @click="handleSubmitClick" />
|
||||
<CloseOutlined :class="`${prefixCls}__icon `" @click="handleCancel" />
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { CSSProperties, PropType } from 'vue';
|
||||
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue';
|
||||
import type { BasicColumn } from '../../types/table';
|
||||
import type { EditRecordRow } from './index';
|
||||
import { CheckOutlined, CloseOutlined, FormOutlined } from '@ant-design/icons-vue';
|
||||
import { CellComponent } from './CellComponent';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
import clickOutside from '/@/directives/clickOutside';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isArray, isBoolean, isFunction, isNumber, isString } from '/@/utils/is';
|
||||
import { createPlaceholderMessage } from './helper';
|
||||
import { omit, pick, set } from 'lodash-es';
|
||||
import { treeToList } from '/@/utils/helper/treeHelper';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EditableCell',
|
||||
components: { FormOutlined, CloseOutlined, CheckOutlined, CellComponent, ASpin: Spin },
|
||||
directives: {
|
||||
clickOutside,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number, Boolean, Object] as PropType<string | number | boolean | Recordable>,
|
||||
default: '',
|
||||
},
|
||||
record: {
|
||||
type: Object as PropType<EditRecordRow>,
|
||||
},
|
||||
column: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: () => ({}),
|
||||
},
|
||||
index: propTypes.number,
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
const isEdit = ref(false);
|
||||
const elRef = ref();
|
||||
const ruleVisible = ref(false);
|
||||
const ruleMessage = ref('');
|
||||
const optionsRef = ref<LabelValueOptions>([]);
|
||||
const currentValueRef = ref<any>(props.value);
|
||||
const defaultValueRef = ref<any>(props.value);
|
||||
const spinning = ref<boolean>(false);
|
||||
|
||||
const { prefixCls } = useDesign('editable-cell');
|
||||
|
||||
const getComponent = computed(() => props.column?.editComponent || 'Input');
|
||||
const getRule = computed(() => props.column?.editRule);
|
||||
|
||||
const getRuleVisible = computed(() => {
|
||||
return unref(ruleMessage) && unref(ruleVisible);
|
||||
});
|
||||
|
||||
const getIsCheckComp = computed(() => {
|
||||
const component = unref(getComponent);
|
||||
return ['Checkbox', 'Switch'].includes(component);
|
||||
});
|
||||
|
||||
const getComponentProps = computed(() => {
|
||||
const compProps = props.column?.editComponentProps ?? {};
|
||||
const component = unref(getComponent);
|
||||
const apiSelectProps: Recordable = {};
|
||||
if (component === 'ApiSelect') {
|
||||
apiSelectProps.cache = true;
|
||||
}
|
||||
|
||||
const isCheckValue = unref(getIsCheckComp);
|
||||
|
||||
const valueField = isCheckValue ? 'checked' : 'value';
|
||||
const val = unref(currentValueRef);
|
||||
|
||||
const value = isCheckValue ? (isNumber(val) && isBoolean(val) ? val : !!val) : val;
|
||||
|
||||
return {
|
||||
size: 'small',
|
||||
getPopupContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
||||
getCalendarContainer: () => unref(table?.wrapRef.value) ?? document.body,
|
||||
placeholder: createPlaceholderMessage(unref(getComponent)),
|
||||
...apiSelectProps,
|
||||
...omit(compProps, 'onChange'),
|
||||
[valueField]: value,
|
||||
};
|
||||
});
|
||||
|
||||
const getValues = computed(() => {
|
||||
const { editComponentProps, editValueMap } = props.column;
|
||||
|
||||
const value = unref(currentValueRef);
|
||||
|
||||
if (editValueMap && isFunction(editValueMap)) {
|
||||
return editValueMap(value);
|
||||
}
|
||||
|
||||
const component = unref(getComponent);
|
||||
if (!component.includes('Select')) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
|
||||
const option = options.find((item) => `${item.value}` === `${value}`);
|
||||
|
||||
return option?.label ?? value;
|
||||
});
|
||||
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
if (unref(getIsCheckComp) || unref(getRowEditable)) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
width: 'calc(100% - 48px)',
|
||||
};
|
||||
});
|
||||
|
||||
const getWrapperClass = computed(() => {
|
||||
const { align = 'center' } = props.column;
|
||||
return `edit-cell-align-${align}`;
|
||||
});
|
||||
|
||||
const getRowEditable = computed(() => {
|
||||
const { editable } = props.record || {};
|
||||
return !!editable;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
defaultValueRef.value = props.value;
|
||||
currentValueRef.value = props.value;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
const { editable } = props.column;
|
||||
if (isBoolean(editable) || isBoolean(unref(getRowEditable))) {
|
||||
isEdit.value = !!editable || unref(getRowEditable);
|
||||
}
|
||||
});
|
||||
|
||||
function handleEdit() {
|
||||
if (unref(getRowEditable) || unref(props.column?.editRow)) return;
|
||||
ruleMessage.value = '';
|
||||
isEdit.value = true;
|
||||
nextTick(() => {
|
||||
const el = unref(elRef);
|
||||
el?.focus?.();
|
||||
});
|
||||
}
|
||||
|
||||
async function handleChange(e: any) {
|
||||
const component = unref(getComponent);
|
||||
if (!e) {
|
||||
currentValueRef.value = e;
|
||||
} else if (e?.target && Reflect.has(e.target, 'value')) {
|
||||
currentValueRef.value = (e as ChangeEvent).target.value;
|
||||
} else if (component === 'Checkbox') {
|
||||
currentValueRef.value = (e as ChangeEvent).target.checked;
|
||||
} else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e)) {
|
||||
currentValueRef.value = e;
|
||||
}
|
||||
const onChange = props.column?.editComponentProps?.onChange;
|
||||
if (onChange && isFunction(onChange)) onChange(...arguments);
|
||||
|
||||
table.emit?.('edit-change', {
|
||||
column: props.column,
|
||||
value: unref(currentValueRef),
|
||||
record: toRaw(props.record),
|
||||
});
|
||||
handleSubmiRule();
|
||||
}
|
||||
|
||||
async function handleSubmiRule() {
|
||||
const { column, record } = props;
|
||||
const { editRule } = column;
|
||||
const currentValue = unref(currentValueRef);
|
||||
|
||||
if (editRule) {
|
||||
if (isBoolean(editRule) && !currentValue && !isNumber(currentValue)) {
|
||||
ruleVisible.value = true;
|
||||
const component = unref(getComponent);
|
||||
ruleMessage.value = createPlaceholderMessage(component);
|
||||
return false;
|
||||
}
|
||||
if (isFunction(editRule)) {
|
||||
const res = await editRule(currentValue, record as Recordable);
|
||||
if (!!res) {
|
||||
ruleMessage.value = res;
|
||||
ruleVisible.value = true;
|
||||
return false;
|
||||
} else {
|
||||
ruleMessage.value = '';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ruleMessage.value = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
async function handleSubmit(needEmit = true, valid = true) {
|
||||
if (valid) {
|
||||
const isPass = await handleSubmiRule();
|
||||
if (!isPass) return false;
|
||||
}
|
||||
|
||||
const { column, index, record } = props;
|
||||
if (!record) return false;
|
||||
const { key, dataIndex } = column;
|
||||
const value = unref(currentValueRef);
|
||||
if (!key || !dataIndex) return;
|
||||
|
||||
const dataKey = (dataIndex || key) as string;
|
||||
|
||||
if (!record.editable) {
|
||||
const { getBindValues } = table;
|
||||
|
||||
const { beforeEditSubmit, columns } = unref(getBindValues);
|
||||
|
||||
if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
|
||||
spinning.value = true;
|
||||
const keys: string[] = columns.map((_column) => _column.dataIndex).filter((field) => !!field) as string[];
|
||||
let result: any = true;
|
||||
try {
|
||||
result = await beforeEditSubmit({
|
||||
record: pick(record, keys),
|
||||
index,
|
||||
key,
|
||||
value,
|
||||
});
|
||||
} catch (e) {
|
||||
result = false;
|
||||
} finally {
|
||||
spinning.value = false;
|
||||
}
|
||||
if (result === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(record, dataKey, value);
|
||||
//const record = await table.updateTableData(index, dataKey, value);
|
||||
needEmit && table.emit?.('edit-end', { record, index, key, value });
|
||||
isEdit.value = false;
|
||||
}
|
||||
|
||||
async function handleEnter() {
|
||||
if (props.column?.editRow) {
|
||||
return;
|
||||
}
|
||||
handleSubmit();
|
||||
}
|
||||
|
||||
function handleSubmitClick() {
|
||||
handleSubmit();
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
isEdit.value = false;
|
||||
currentValueRef.value = defaultValueRef.value;
|
||||
const { column, index, record } = props;
|
||||
const { key, dataIndex } = column;
|
||||
table.emit?.('edit-cancel', {
|
||||
record,
|
||||
index,
|
||||
key: dataIndex || key,
|
||||
value: unref(currentValueRef),
|
||||
});
|
||||
}
|
||||
|
||||
function onClickOutside() {
|
||||
if (props.column?.editable || unref(getRowEditable)) {
|
||||
return;
|
||||
}
|
||||
const component = unref(getComponent);
|
||||
|
||||
if (component.includes('Input')) {
|
||||
handleCancel();
|
||||
}
|
||||
}
|
||||
|
||||
// only ApiSelect or TreeSelect
|
||||
function handleOptionsChange(options: LabelValueOptions) {
|
||||
const { replaceFields } = props.column?.editComponentProps ?? {};
|
||||
const component = unref(getComponent);
|
||||
if (component === 'ApiTreeSelect') {
|
||||
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {};
|
||||
let listOptions: Recordable[] = treeToList(options, { children });
|
||||
listOptions = listOptions.map((item) => {
|
||||
return {
|
||||
label: item[title],
|
||||
value: item[value],
|
||||
};
|
||||
});
|
||||
optionsRef.value = listOptions as LabelValueOptions;
|
||||
} else {
|
||||
optionsRef.value = options;
|
||||
}
|
||||
}
|
||||
|
||||
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) {
|
||||
if (props.record) {
|
||||
/* eslint-disable */
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
const { dataIndex, key } = props.column;
|
||||
const field: any = dataIndex || key;
|
||||
if (isArray(props.record[cbs])) {
|
||||
const findItem = props.record[cbs]?.find((item) => item[field]);
|
||||
if (findItem) {
|
||||
findItem[field] = handle;
|
||||
} else {
|
||||
props.record[cbs]?.push({ [field]: handle });
|
||||
}
|
||||
} else {
|
||||
props.record[cbs] = [{ [field]: handle }];
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
}
|
||||
}
|
||||
|
||||
if (props.record) {
|
||||
initCbs('submitCbs', handleSubmit);
|
||||
initCbs('validCbs', handleSubmiRule);
|
||||
initCbs('cancelCbs', handleCancel);
|
||||
|
||||
if (props.column.dataIndex) {
|
||||
if (!props.record.editValueRefs) props.record.editValueRefs = {};
|
||||
props.record.editValueRefs[props.column.dataIndex] = currentValueRef;
|
||||
}
|
||||
/* eslint-disable */
|
||||
props.record.onCancelEdit = () => {
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
isArray(props.record?.cancelCbs) &&
|
||||
props.record?.cancelCbs.forEach((item) => {
|
||||
const [fn] = Object.values(item);
|
||||
fn();
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
};
|
||||
/* eslint-disable */
|
||||
props.record.onSubmitEdit = async () => {
|
||||
if (isArray(props.record?.submitCbs)) {
|
||||
if (!props.record?.onValid?.()) return;
|
||||
const submitFns = props.record?.submitCbs || [];
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
submitFns.forEach((item) => {
|
||||
const [fn] = Object.values(item);
|
||||
fn(false, false);
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
table.emit?.('edit-row-end');
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isEdit,
|
||||
prefixCls,
|
||||
handleEdit,
|
||||
currentValueRef,
|
||||
handleSubmit,
|
||||
handleChange,
|
||||
handleCancel,
|
||||
elRef,
|
||||
getComponent,
|
||||
getRule,
|
||||
onClickOutside,
|
||||
ruleMessage,
|
||||
getRuleVisible,
|
||||
getComponentProps,
|
||||
handleOptionsChange,
|
||||
getWrapperStyle,
|
||||
getWrapperClass,
|
||||
getRowEditable,
|
||||
getValues,
|
||||
handleEnter,
|
||||
handleSubmitClick,
|
||||
spinning,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-editable-cell';
|
||||
|
||||
.edit-cell-align-left {
|
||||
text-align: left;
|
||||
|
||||
input:not(.ant-calendar-picker-input, .ant-time-picker-input) {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-cell-align-center {
|
||||
text-align: center;
|
||||
|
||||
input:not(.ant-calendar-picker-input, .ant-time-picker-input) {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-cell-align-right {
|
||||
text-align: right;
|
||||
|
||||
input:not(.ant-calendar-picker-input, .ant-time-picker-input) {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-cell-rule-popover {
|
||||
.ant-popover-inner-content {
|
||||
padding: 4px 8px;
|
||||
color: @error-color;
|
||||
// border: 1px solid @error-color;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
position: relative;
|
||||
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> .ant-select {
|
||||
min-width: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
|
||||
svg {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ellipsis-cell {
|
||||
.cell-content {
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
&__normal {
|
||||
&-icon {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 0;
|
||||
display: none;
|
||||
width: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.@{prefix-cls}__normal-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,28 +0,0 @@
|
||||
import { ComponentType } from '../../types/componentType';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
/**
|
||||
* @description: 生成placeholder
|
||||
*/
|
||||
export function createPlaceholderMessage(component: ComponentType) {
|
||||
if (component.includes('Input')) {
|
||||
return t('common.inputText');
|
||||
}
|
||||
if (component.includes('Picker')) {
|
||||
return t('common.chooseText');
|
||||
}
|
||||
|
||||
if (
|
||||
component.includes('Select') ||
|
||||
component.includes('Checkbox') ||
|
||||
component.includes('Radio') ||
|
||||
component.includes('Switch') ||
|
||||
component.includes('DatePicker') ||
|
||||
component.includes('TimePicker')
|
||||
) {
|
||||
return t('common.chooseText');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import type { BasicColumn } from '/@/components/Table/src/types/table';
|
||||
|
||||
import { h, Ref, toRaw } from 'vue';
|
||||
|
||||
import EditableCell from './EditableCell.vue';
|
||||
import { isArray } from '/@/utils/is';
|
||||
|
||||
interface Params {
|
||||
text: string;
|
||||
record: Recordable;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export function renderEditCell(column: BasicColumn) {
|
||||
return ({ text: value, record, index }: Params) => {
|
||||
toRaw(record).onValid = async () => {
|
||||
if (isArray(record?.validCbs)) {
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
const validFns = (record?.validCbs || []).map((item) => {
|
||||
const [fn] = Object.values(item);
|
||||
// @ts-ignore
|
||||
return fn();
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1165】解决canResize为true时第一行校验不过
|
||||
const res = await Promise.all(validFns);
|
||||
return res.every((item) => !!item);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
toRaw(record).onEdit = async (edit: boolean, submit = false) => {
|
||||
if (!submit) {
|
||||
record.editable = edit;
|
||||
}
|
||||
|
||||
if (!edit && submit) {
|
||||
if (!(await record.onValid())) return false;
|
||||
const res = await record.onSubmitEdit?.();
|
||||
if (res) {
|
||||
record.editable = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// cancel
|
||||
if (!edit && !submit) {
|
||||
record.onCancelEdit?.();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return h(EditableCell, {
|
||||
value,
|
||||
record,
|
||||
column,
|
||||
index,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
interface Cbs {
|
||||
[key: string]: Fn;
|
||||
}
|
||||
|
||||
export type EditRecordRow<T = Recordable> = Partial<
|
||||
{
|
||||
onEdit: (editable: boolean, submit?: boolean) => Promise<boolean>;
|
||||
onValid: () => Promise<boolean>;
|
||||
editable: boolean;
|
||||
onCancel: Fn;
|
||||
onSubmit: Fn;
|
||||
submitCbs: Cbs[];
|
||||
cancelCbs: Cbs[];
|
||||
validCbs: Cbs[];
|
||||
editValueRefs: Recordable<Ref>;
|
||||
} & T
|
||||
>;
|
||||
@@ -1,536 +0,0 @@
|
||||
<template>
|
||||
<Tooltip placement="top" v-bind="getBindProps" >
|
||||
<template #title>
|
||||
<span>{{ t('component.table.settingColumn') }}</span>
|
||||
</template>
|
||||
<Popover
|
||||
v-model:open="popoverVisible"
|
||||
placement="bottomLeft"
|
||||
trigger="click"
|
||||
@open-change="handleVisibleChange"
|
||||
:overlayClassName="`${prefixCls}__cloumn-list`"
|
||||
:getPopupContainer="getPopupContainer"
|
||||
>
|
||||
<template #title>
|
||||
<div :class="`${prefixCls}__popover-title`">
|
||||
<Checkbox :indeterminate="indeterminate" v-model:checked="checkAll" @change="onCheckAllChange">
|
||||
{{ t('component.table.settingColumnShow') }}
|
||||
</Checkbox>
|
||||
|
||||
<Checkbox v-model:checked="checkIndex" @change="handleIndexCheckChange">
|
||||
{{ t('component.table.settingIndexColumnShow') }}
|
||||
</Checkbox>
|
||||
|
||||
<!-- <Checkbox-->
|
||||
<!-- v-model:checked="checkSelect"-->
|
||||
<!-- @change="handleSelectCheckChange"-->
|
||||
<!-- :disabled="!defaultRowSelection"-->
|
||||
<!-- >-->
|
||||
<!-- {{ t('component.table.settingSelectColumnShow') }}-->
|
||||
<!-- </Checkbox>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<ScrollContainer>
|
||||
<CheckboxGroup v-model:value="checkedList" @change="onChange" ref="columnListRef">
|
||||
<template v-for="item in plainOptions" :key="item.value">
|
||||
<div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
|
||||
<DragOutlined class="table-column-drag-icon" />
|
||||
<Checkbox :value="item.value">
|
||||
{{ item.label }}
|
||||
</Checkbox>
|
||||
|
||||
<Tooltip placement="bottomLeft" :mouseLeaveDelay="0.4" :getPopupContainer="getPopupContainer">
|
||||
<template #title>
|
||||
{{ t('component.table.settingFixedLeft') }}
|
||||
</template>
|
||||
<Icon
|
||||
icon="line-md:arrow-align-left"
|
||||
:class="[
|
||||
`${prefixCls}__fixed-left`,
|
||||
{
|
||||
active: item.fixed === 'left',
|
||||
disabled: !checkedList.includes(item.value),
|
||||
},
|
||||
]"
|
||||
@click="handleColumnFixed(item, 'left')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Divider type="vertical" />
|
||||
<Tooltip placement="bottomLeft" :mouseLeaveDelay="0.4" :getPopupContainer="getPopupContainer">
|
||||
<template #title>
|
||||
{{ t('component.table.settingFixedRight') }}
|
||||
</template>
|
||||
<Icon
|
||||
icon="line-md:arrow-align-left"
|
||||
:class="[
|
||||
`${prefixCls}__fixed-right`,
|
||||
{
|
||||
active: item.fixed === 'right',
|
||||
disabled: !checkedList.includes(item.value),
|
||||
},
|
||||
]"
|
||||
@click="handleColumnFixed(item, 'right')"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</CheckboxGroup>
|
||||
</ScrollContainer>
|
||||
<div :class="`${prefixCls}__popover-footer`">
|
||||
<a-button size="small" @click="reset">
|
||||
{{ t('common.resetText') }}
|
||||
</a-button>
|
||||
<a-button size="small" type="primary" @click="saveSetting"> 保存 </a-button>
|
||||
</div>
|
||||
</template>
|
||||
<SettingOutlined />
|
||||
</Popover>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { BasicColumn, ColumnChangeParam } from '../../types/table';
|
||||
import { defineComponent, ref, reactive, toRefs, watchEffect, nextTick, unref, computed } from 'vue';
|
||||
import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
|
||||
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
|
||||
import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { useColumnsCache } from '../../hooks/useColumnsCache';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
// import { useSortable } from '/@/hooks/web/useSortable';
|
||||
import { isFunction, isNullAndUnDef } from '/@/utils/is';
|
||||
import { getPopupContainer as getParentContainer } from '/@/utils';
|
||||
import { cloneDeep, omit } from 'lodash-es';
|
||||
import Sortablejs from 'sortablejs';
|
||||
import type Sortable from 'sortablejs';
|
||||
|
||||
interface State {
|
||||
checkAll: boolean;
|
||||
isInit?: boolean;
|
||||
checkedList: string[];
|
||||
defaultCheckList: string[];
|
||||
}
|
||||
|
||||
interface Options {
|
||||
label: string;
|
||||
value: string;
|
||||
fixed?: boolean | 'left' | 'right';
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ColumnSetting',
|
||||
props: {
|
||||
isMobile: Boolean,
|
||||
},
|
||||
components: {
|
||||
SettingOutlined,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Checkbox,
|
||||
CheckboxGroup: Checkbox.Group,
|
||||
DragOutlined,
|
||||
ScrollContainer,
|
||||
Divider,
|
||||
Icon,
|
||||
},
|
||||
emits: ['columns-change'],
|
||||
|
||||
setup(props, { emit, attrs }) {
|
||||
const { t } = useI18n();
|
||||
const table = useTableContext();
|
||||
const popoverVisible = ref(false);
|
||||
// update-begin--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
|
||||
// nextTick(() => popoverVisible.value = false);
|
||||
// update-end--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
|
||||
const defaultRowSelection = omit(table.getRowSelection(), 'selectedRowKeys');
|
||||
let inited = false;
|
||||
|
||||
const cachePlainOptions = ref<Options[]>([]);
|
||||
const plainOptions = ref<Options[] | any>([]);
|
||||
|
||||
const plainSortOptions = ref<Options[]>([]);
|
||||
|
||||
const columnListRef = ref<ComponentRef>(null);
|
||||
|
||||
const state = reactive<State>({
|
||||
checkAll: true,
|
||||
checkedList: [],
|
||||
defaultCheckList: [],
|
||||
});
|
||||
|
||||
const checkIndex = ref(false);
|
||||
const checkSelect = ref(false);
|
||||
|
||||
const { prefixCls } = useDesign('basic-column-setting');
|
||||
|
||||
const getValues = computed(() => {
|
||||
return unref(table?.getBindValues) || {};
|
||||
});
|
||||
|
||||
const getBindProps = computed(() => {
|
||||
let obj = {};
|
||||
if (props.isMobile) {
|
||||
obj['open'] = false;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
let sortable: Sortable;
|
||||
const sortableOrder = ref<string[]>();
|
||||
|
||||
// 列表字段配置缓存
|
||||
const { saveSetting, resetSetting } = useColumnsCache(
|
||||
{
|
||||
state,
|
||||
popoverVisible,
|
||||
plainOptions,
|
||||
plainSortOptions,
|
||||
sortableOrder,
|
||||
checkIndex,
|
||||
},
|
||||
setColumns,
|
||||
handleColumnFixed
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
setTimeout(() => {
|
||||
const columns = table.getColumns();
|
||||
if (columns.length && !state.isInit) {
|
||||
init();
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
const values = unref(getValues);
|
||||
checkIndex.value = !!values.showIndexColumn;
|
||||
checkSelect.value = !!values.rowSelection;
|
||||
});
|
||||
|
||||
function getColumns() {
|
||||
const ret: Options[] = [];
|
||||
table.getColumns({ ignoreIndex: true, ignoreAction: true }).forEach((item) => {
|
||||
ret.push({
|
||||
label: (item.title as string) || (item.customTitle as string),
|
||||
value: (item.dataIndex || item.title) as string,
|
||||
...item,
|
||||
});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
function init() {
|
||||
const columns = getColumns();
|
||||
|
||||
const checkList = table
|
||||
.getColumns({ ignoreAction: true })
|
||||
.map((item) => {
|
||||
if (item.defaultHidden) {
|
||||
return '';
|
||||
}
|
||||
return item.dataIndex || item.title;
|
||||
})
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
if (!plainOptions.value.length) {
|
||||
plainOptions.value = columns;
|
||||
plainSortOptions.value = columns;
|
||||
cachePlainOptions.value = columns;
|
||||
state.defaultCheckList = checkList;
|
||||
} else {
|
||||
// const fixedColumns = columns.filter((item) =>
|
||||
// Reflect.has(item, 'fixed')
|
||||
// ) as BasicColumn[];
|
||||
|
||||
unref(plainOptions).forEach((item: BasicColumn) => {
|
||||
const findItem = columns.find((col: BasicColumn) => col.dataIndex === item.dataIndex);
|
||||
if (findItem) {
|
||||
item.fixed = findItem.fixed;
|
||||
}
|
||||
});
|
||||
}
|
||||
state.isInit = true;
|
||||
state.checkedList = checkList;
|
||||
}
|
||||
|
||||
// checkAll change
|
||||
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||
const checkList = plainOptions.value.map((item) => item.value);
|
||||
if (e.target.checked) {
|
||||
state.checkedList = checkList;
|
||||
setColumns(checkList);
|
||||
} else {
|
||||
state.checkedList = [];
|
||||
setColumns([]);
|
||||
}
|
||||
}
|
||||
|
||||
const indeterminate = computed(() => {
|
||||
const len = plainOptions.value.length;
|
||||
let checkedLen = state.checkedList.length;
|
||||
unref(checkIndex) && checkedLen--;
|
||||
return checkedLen > 0 && checkedLen < len;
|
||||
});
|
||||
|
||||
// Trigger when check/uncheck a column
|
||||
function onChange(checkedList: string[]) {
|
||||
const len = plainSortOptions.value.length;
|
||||
state.checkAll = checkedList.length === len;
|
||||
const sortList = unref(plainSortOptions).map((item) => item.value);
|
||||
checkedList.sort((prev, next) => {
|
||||
return sortList.indexOf(prev) - sortList.indexOf(next);
|
||||
});
|
||||
setColumns(checkedList);
|
||||
}
|
||||
|
||||
// reset columns
|
||||
function reset() {
|
||||
// state.checkedList = [...state.defaultCheckList];
|
||||
// update-begin--author:liaozhiyang---date:20231103---for:【issues/825】tabel的列设置隐藏列保存后切换路由问题[重置没勾选]
|
||||
state.checkedList = table
|
||||
.getColumns({ ignoreAction: true })
|
||||
.map((item) => {
|
||||
return item.dataIndex || item.title;
|
||||
})
|
||||
.filter(Boolean) as string[];
|
||||
// update-end--author:liaozhiyang---date:20231103---for:【issues/825】tabel的列设置隐藏列保存后切换路由问题[重置没勾选]
|
||||
state.checkAll = true;
|
||||
plainOptions.value = unref(cachePlainOptions);
|
||||
plainSortOptions.value = unref(cachePlainOptions);
|
||||
setColumns(table.getCacheColumns());
|
||||
if (sortableOrder.value) {
|
||||
sortable.sort(sortableOrder.value);
|
||||
}
|
||||
resetSetting();
|
||||
}
|
||||
|
||||
// Open the pop-up window for drag and drop initialization
|
||||
function handleVisibleChange() {
|
||||
if (inited) return;
|
||||
// update-begin--author:liaozhiyang---date:20240529---for:【TV360X-254】列设置闪现及苹果浏览器弹窗过长
|
||||
setTimeout(() => {
|
||||
// update-begin--author:liaozhiyang---date:20240529---for:【TV360X-254】列设置闪现及苹果浏览器弹窗过长
|
||||
const columnListEl = unref(columnListRef);
|
||||
if (!columnListEl) return;
|
||||
const el = columnListEl.$el as any;
|
||||
if (!el) return;
|
||||
// Drag and drop sort
|
||||
sortable = Sortablejs.create(unref(el), {
|
||||
animation: 500,
|
||||
delay: 400,
|
||||
delayOnTouchOnly: true,
|
||||
handle: '.table-column-drag-icon ',
|
||||
onEnd: (evt) => {
|
||||
const { oldIndex, newIndex } = evt;
|
||||
if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
|
||||
return;
|
||||
}
|
||||
// Sort column
|
||||
const columns = cloneDeep(plainSortOptions.value);
|
||||
|
||||
if (oldIndex > newIndex) {
|
||||
columns.splice(newIndex, 0, columns[oldIndex]);
|
||||
columns.splice(oldIndex + 1, 1);
|
||||
} else {
|
||||
columns.splice(newIndex + 1, 0, columns[oldIndex]);
|
||||
columns.splice(oldIndex, 1);
|
||||
}
|
||||
|
||||
plainSortOptions.value = columns;
|
||||
// update-begin--author:liaozhiyang---date:20230904---for:【QQYUN-6424】table字段列表设置不显示后,再拖拽字段顺序,原本不显示的,又显示了
|
||||
// update-begin--author:liaozhiyang---date:20240522---for:【TV360X-108】刷新后勾选之前未勾选的字段拖拽之后该字段对应的表格列消失了
|
||||
const cols = columns.map((item) => item.value);
|
||||
const arr = cols.filter((cItem) => state.checkedList.find((lItem) => lItem === cItem));
|
||||
setColumns(arr);
|
||||
// 最开始的代码
|
||||
// setColumns(columns);
|
||||
// update-end--author:liaozhiyang---date:20240522---for:【TV360X-108】刷新后勾选之前未勾选的字段拖拽之后该字段对应的表格列消失了
|
||||
// update-end--author:liaozhiyang---date:20230904---for:【QQYUN-6424】table字段列表设置不显示后,再拖拽字段顺序,原本不显示的,又显示了
|
||||
},
|
||||
});
|
||||
// 记录原始 order 序列
|
||||
if (!sortableOrder.value) {
|
||||
sortableOrder.value = sortable.toArray();
|
||||
}
|
||||
inited = true;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Control whether the serial number column is displayed
|
||||
function handleIndexCheckChange(e: CheckboxChangeEvent) {
|
||||
table.setProps({
|
||||
showIndexColumn: e.target.checked,
|
||||
});
|
||||
}
|
||||
|
||||
// Control whether the check box is displayed
|
||||
function handleSelectCheckChange(e: CheckboxChangeEvent) {
|
||||
table.setProps({
|
||||
rowSelection: e.target.checked ? defaultRowSelection : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
function handleColumnFixed(item: BasicColumn, fixed?: 'left' | 'right') {
|
||||
if (!state.checkedList.includes(item.dataIndex as string)) return;
|
||||
|
||||
const columns = getColumns() as BasicColumn[];
|
||||
const isFixed = item.fixed === fixed ? false : fixed;
|
||||
const index = columns.findIndex((col) => col.dataIndex === item.dataIndex);
|
||||
if (index !== -1) {
|
||||
columns[index].fixed = isFixed;
|
||||
}
|
||||
item.fixed = isFixed;
|
||||
|
||||
if (isFixed && !item.width) {
|
||||
item.width = 100;
|
||||
}
|
||||
table.setCacheColumnsByField?.(item.dataIndex as string, { fixed: isFixed });
|
||||
setColumns(columns);
|
||||
}
|
||||
|
||||
function setColumns(columns: BasicColumn[] | string[]) {
|
||||
table.setColumns(columns);
|
||||
const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
|
||||
const visible =
|
||||
columns.findIndex((c: BasicColumn | string) => c === col.value || (typeof c !== 'string' && c.dataIndex === col.value)) !== -1;
|
||||
return { dataIndex: col.value, fixed: col.fixed, visible };
|
||||
});
|
||||
|
||||
emit('columns-change', data);
|
||||
}
|
||||
|
||||
function getPopupContainer() {
|
||||
return isFunction(attrs.getPopupContainer) ? attrs.getPopupContainer() : getParentContainer();
|
||||
}
|
||||
|
||||
return {
|
||||
getBindProps,
|
||||
t,
|
||||
...toRefs(state),
|
||||
popoverVisible,
|
||||
indeterminate,
|
||||
onCheckAllChange,
|
||||
onChange,
|
||||
plainOptions,
|
||||
reset,
|
||||
saveSetting,
|
||||
prefixCls,
|
||||
columnListRef,
|
||||
handleVisibleChange,
|
||||
checkIndex,
|
||||
checkSelect,
|
||||
handleIndexCheckChange,
|
||||
handleSelectCheckChange,
|
||||
defaultRowSelection,
|
||||
handleColumnFixed,
|
||||
getPopupContainer,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-column-setting';
|
||||
|
||||
.table-column-drag-icon {
|
||||
margin: 0 5px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
&__popover-title {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* 卡片底部样式 */
|
||||
&__popover-footer {
|
||||
position: relative;
|
||||
top: 7px;
|
||||
text-align: right;
|
||||
padding: 4px 0 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
|
||||
.ant-btn {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&__check-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 100%;
|
||||
padding: 4px 16px 8px 0;
|
||||
|
||||
.ant-checkbox-wrapper {
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__fixed-left,
|
||||
&__fixed-right {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
cursor: pointer;
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&__fixed-right {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
&__cloumn-list {
|
||||
svg {
|
||||
width: 1em !important;
|
||||
height: 1em !important;
|
||||
}
|
||||
|
||||
.ant-popover-inner-content {
|
||||
// max-height: 360px;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
// overflow: auto;
|
||||
}
|
||||
|
||||
.ant-checkbox-group {
|
||||
// update-begin--author:liaozhiyang---date:20240118---for:【QQYUN-7887】表格列设置宽度过长
|
||||
// width: 100%;
|
||||
min-width: 260px;
|
||||
max-width: min-content;
|
||||
// update-end--author:liaozhiyang---date:20240118---for:【QQYUN-7887】表格列设置宽度过长
|
||||
// flex-wrap: wrap;
|
||||
}
|
||||
|
||||
// update-begin--author:liaozhiyang---date:20240529---for:【TV360X-254】列设置闪现及苹果浏览器弹窗过长
|
||||
&.ant-popover,
|
||||
.ant-popover-content,
|
||||
.ant-popover-inner,
|
||||
.ant-popover-inner-content,
|
||||
.scroll-container,
|
||||
.scrollbar__wrap {
|
||||
max-width: min-content;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240529---for:【TV360X-254】列设置闪现及苹果浏览器弹窗过长
|
||||
.scrollbar {
|
||||
height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,48 +0,0 @@
|
||||
<template>
|
||||
<Tooltip placement="top" v-bind="getBindProps">
|
||||
<template #title>
|
||||
<span>{{ t('component.table.settingFullScreen') }}</span>
|
||||
</template>
|
||||
<FullscreenOutlined @click="toggle" v-if="!isFullscreen" />
|
||||
<FullscreenExitOutlined @click="toggle" v-else />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FullScreenSetting',
|
||||
props: {
|
||||
isMobile: Boolean,
|
||||
},
|
||||
components: {
|
||||
FullscreenExitOutlined,
|
||||
FullscreenOutlined,
|
||||
Tooltip,
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
const { t } = useI18n();
|
||||
const { toggle, isFullscreen } = useFullscreen(table.wrapRef);
|
||||
const getBindProps = computed(() => {
|
||||
let obj = {};
|
||||
if (props.isMobile) {
|
||||
obj['visible'] = false;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
return {
|
||||
getBindProps,
|
||||
toggle,
|
||||
isFullscreen,
|
||||
t,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<Tooltip placement="top" v-bind="getBindProps">
|
||||
<template #title>
|
||||
<span>{{ t('common.redo') }}</span>
|
||||
</template>
|
||||
<RedoOutlined @click="redo" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RedoSetting',
|
||||
props: {
|
||||
isMobile: Boolean,
|
||||
},
|
||||
components: {
|
||||
RedoOutlined,
|
||||
Tooltip,
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
const { t } = useI18n();
|
||||
|
||||
const getBindProps = computed(() => {
|
||||
let obj = {};
|
||||
if (props.isMobile) {
|
||||
obj['visible'] = false;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
function redo() {
|
||||
table.reload();
|
||||
table.emit!('table-redo');
|
||||
}
|
||||
|
||||
return { getBindProps, redo, t };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,99 +0,0 @@
|
||||
<template>
|
||||
<Tooltip placement="top" v-bind="getBindProps">
|
||||
<template #title>
|
||||
<span>{{ t('component.table.settingDens') }}</span>
|
||||
</template>
|
||||
|
||||
<Dropdown placement="bottom" :trigger="['click']" :getPopupContainer="getPopupContainer">
|
||||
<ColumnHeightOutlined />
|
||||
<template #overlay>
|
||||
<Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">
|
||||
<MenuItem key="large">
|
||||
<span>{{ t('component.table.settingDensLarge') }}</span>
|
||||
</MenuItem>
|
||||
<MenuItem key="middle">
|
||||
<span>{{ t('component.table.settingDensMiddle') }}</span>
|
||||
</MenuItem>
|
||||
<MenuItem key="small">
|
||||
<span>{{ t('component.table.settingDensSmall') }}</span>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { SizeType } from '../../types/table';
|
||||
import { computed, defineComponent, ref } from 'vue';
|
||||
import { Tooltip, Dropdown, Menu } from 'ant-design-vue';
|
||||
import { ColumnHeightOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
import { getPopupContainer } from '/@/utils';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { createLocalStorage } from '/@/utils/cache';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SizeSetting',
|
||||
props: {
|
||||
isMobile: Boolean,
|
||||
},
|
||||
components: {
|
||||
ColumnHeightOutlined,
|
||||
Tooltip,
|
||||
Dropdown,
|
||||
Menu,
|
||||
MenuItem: Menu.Item,
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
const { t } = useI18n();
|
||||
const $ls = createLocalStorage();
|
||||
const route = useRoute();
|
||||
|
||||
const selectedKeysRef = ref<SizeType[]>([table.getSize()]);
|
||||
const getBindProps = computed(() => {
|
||||
let obj = {};
|
||||
if (props.isMobile) {
|
||||
obj['visible'] = false;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
function handleTitleClick({ key }: { key: SizeType }) {
|
||||
selectedKeysRef.value = [key];
|
||||
table.setProps({
|
||||
size: key,
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20240604---for:【TV360X-100】缓存表格密度
|
||||
$ls.set(cacheKey.value, key);
|
||||
// update-end--author:liaozhiyang---date:20240604---for:【TV360X-100】缓存表格密度
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240604---for:【TV360X-100】缓存表格密度
|
||||
const cacheKey = computed(() => {
|
||||
const path = route.path;
|
||||
let key = path.replace(/[\/\\]/g, '_');
|
||||
let cacheKey = table.getBindValues.value.tableSetting?.cacheKey;
|
||||
if (cacheKey) {
|
||||
key += ':' + cacheKey;
|
||||
}
|
||||
return 'tableSizeCache:' + key;
|
||||
});
|
||||
const local: SizeType | null = $ls.get(cacheKey.value);
|
||||
if (local) {
|
||||
selectedKeysRef.value = [local];
|
||||
table.setProps({
|
||||
size: local,
|
||||
});
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240604---for:【TV360X-100】缓存表格密度
|
||||
|
||||
return {
|
||||
getBindProps,
|
||||
handleTitleClick,
|
||||
selectedKeysRef,
|
||||
getPopupContainer,
|
||||
t,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,74 +0,0 @@
|
||||
<template>
|
||||
<div class="table-settings">
|
||||
<RedoSetting v-if="getSetting.redo" :isMobile="isMobile" :getPopupContainer="getTableContainer" />
|
||||
<SizeSetting v-if="getSetting.size" :isMobile="isMobile" :getPopupContainer="getTableContainer" />
|
||||
<ColumnSetting v-if="getSetting.setting" :isMobile="isMobile" @columns-change="handleColumnChange" :getPopupContainer="getTableContainer" />
|
||||
<FullScreenSetting v-if="getSetting.fullScreen" :isMobile="isMobile" :getPopupContainer="getTableContainer" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import type { TableSetting, ColumnChangeParam } from '../../types/table';
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import ColumnSetting from './ColumnSetting.vue';
|
||||
import SizeSetting from './SizeSetting.vue';
|
||||
import RedoSetting from './RedoSetting.vue';
|
||||
import FullScreenSetting from './FullScreenSetting.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTableContext } from '../../hooks/useTableContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TableSetting',
|
||||
components: {
|
||||
ColumnSetting,
|
||||
SizeSetting,
|
||||
RedoSetting,
|
||||
FullScreenSetting,
|
||||
},
|
||||
props: {
|
||||
setting: {
|
||||
type: Object as PropType<TableSetting>,
|
||||
default: () => ({}),
|
||||
},
|
||||
mode: String,
|
||||
},
|
||||
emits: ['columns-change'],
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n();
|
||||
const table = useTableContext();
|
||||
|
||||
const getSetting = computed((): TableSetting => {
|
||||
return {
|
||||
redo: true,
|
||||
size: true,
|
||||
setting: true,
|
||||
fullScreen: false,
|
||||
...props.setting,
|
||||
};
|
||||
});
|
||||
const isMobile = computed(() => props.mode === 'mobile');
|
||||
|
||||
function handleColumnChange(data: ColumnChangeParam[]) {
|
||||
emit('columns-change', data);
|
||||
}
|
||||
|
||||
function getTableContainer() {
|
||||
return table ? unref(table.wrapRef) : document.body;
|
||||
}
|
||||
|
||||
return { getSetting, t, handleColumnChange, getTableContainer, isMobile };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.table-settings {
|
||||
& > * {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,30 +0,0 @@
|
||||
import componentSetting from '/@/settings/componentSetting';
|
||||
|
||||
const { table } = componentSetting;
|
||||
|
||||
const { pageSizeOptions, defaultPageSize, defaultSize, fetchSetting, defaultSortFn, defaultFilterFn } = table;
|
||||
|
||||
export const ROW_KEY = 'key';
|
||||
|
||||
// Optional display number per page;
|
||||
export const PAGE_SIZE_OPTIONS = pageSizeOptions;
|
||||
|
||||
// Number of items displayed per page
|
||||
export const PAGE_SIZE = defaultPageSize;
|
||||
|
||||
// Common interface field settings
|
||||
export const FETCH_SETTING = fetchSetting;
|
||||
|
||||
// Configure general sort function
|
||||
export const DEFAULT_SORT_FN = defaultSortFn;
|
||||
|
||||
export const DEFAULT_FILTER_FN = defaultFilterFn;
|
||||
|
||||
// Default layout of table cells
|
||||
export const DEFAULT_ALIGN = 'center';
|
||||
// Default Size
|
||||
export const DEFAULT_SIZE = defaultSize;
|
||||
|
||||
export const INDEX_COLUMN_FLAG = 'INDEX';
|
||||
|
||||
export const ACTION_COLUMN_FLAG = 'ACTION';
|
||||
@@ -1,348 +0,0 @@
|
||||
import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import type { ComputedRef } from 'vue';
|
||||
import { Table } from 'ant-design-vue';
|
||||
import { computed, Ref, ref, toRaw, unref, watch, reactive } from 'vue';
|
||||
import { renderEditCell } from '../components/editable';
|
||||
import { usePermission } from '/@/hooks/web/usePermission';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isArray, isBoolean, isFunction, isMap, isString } from '/@/utils/is';
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
import { formatToDate } from '/@/utils/dateUtil';
|
||||
import { ACTION_COLUMN_FLAG, DEFAULT_ALIGN, INDEX_COLUMN_FLAG, PAGE_SIZE } from '../const';
|
||||
import { CUS_SEL_COLUMN_KEY } from './useCustomSelection';
|
||||
|
||||
function handleItem(item: BasicColumn, ellipsis: boolean) {
|
||||
const { key, dataIndex, children } = item;
|
||||
item.align = item.align || DEFAULT_ALIGN;
|
||||
if (ellipsis) {
|
||||
if (!key) {
|
||||
item.key = dataIndex;
|
||||
}
|
||||
if (!isBoolean(item.ellipsis)) {
|
||||
Object.assign(item, {
|
||||
ellipsis,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (children && children.length) {
|
||||
handleChildren(children, !!ellipsis);
|
||||
}
|
||||
}
|
||||
|
||||
function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) {
|
||||
if (!children) return;
|
||||
children.forEach((item) => {
|
||||
const { children } = item;
|
||||
handleItem(item, ellipsis);
|
||||
handleChildren(children, ellipsis);
|
||||
});
|
||||
}
|
||||
|
||||
function handleIndexColumn(propsRef: ComputedRef<BasicTableProps>, getPaginationRef: ComputedRef<boolean | PaginationProps>, columns: BasicColumn[]) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);
|
||||
|
||||
let pushIndexColumns = false;
|
||||
if (unref(isTreeTable)) {
|
||||
return;
|
||||
}
|
||||
columns.forEach(() => {
|
||||
const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG);
|
||||
if (showIndexColumn) {
|
||||
pushIndexColumns = indIndex === -1;
|
||||
} else if (!showIndexColumn && indIndex !== -1) {
|
||||
columns.splice(indIndex, 1);
|
||||
}
|
||||
});
|
||||
|
||||
if (!pushIndexColumns) return;
|
||||
|
||||
const isFixedLeft = columns.some((item) => item.fixed === 'left');
|
||||
|
||||
columns.unshift({
|
||||
flag: INDEX_COLUMN_FLAG,
|
||||
width: 50,
|
||||
title: t('component.table.index'),
|
||||
align: 'center',
|
||||
customRender: ({ index }) => {
|
||||
const getPagination = unref(getPaginationRef);
|
||||
if (isBoolean(getPagination)) {
|
||||
return `${index + 1}`;
|
||||
}
|
||||
const { current = 1, pageSize = PAGE_SIZE } = getPagination;
|
||||
return ((current < 1 ? 1 : current) - 1) * pageSize + index + 1;
|
||||
},
|
||||
...(isFixedLeft
|
||||
? {
|
||||
fixed: 'left',
|
||||
}
|
||||
: {}),
|
||||
...indexColumnProps,
|
||||
});
|
||||
}
|
||||
|
||||
function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
|
||||
const { actionColumn, showActionColumn } = unref(propsRef);
|
||||
if (!actionColumn || !showActionColumn) return;
|
||||
|
||||
const hasIndex = columns.findIndex((column) => column.flag === ACTION_COLUMN_FLAG);
|
||||
if (hasIndex === -1) {
|
||||
columns.push({
|
||||
...columns[hasIndex],
|
||||
...actionColumn,
|
||||
flag: ACTION_COLUMN_FLAG,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function useColumns(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
getPaginationRef: ComputedRef<boolean | PaginationProps>,
|
||||
handleCustomSelectColumn: Fn
|
||||
) {
|
||||
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
|
||||
let cacheColumns = unref(propsRef).columns;
|
||||
|
||||
const getColumnsRef = computed(() => {
|
||||
const columns = cloneDeep(unref(columnsRef));
|
||||
|
||||
handleIndexColumn(propsRef, getPaginationRef, columns);
|
||||
handleActionColumn(propsRef, columns);
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
handleCustomSelectColumn(columns);
|
||||
// update-end--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
if (!columns) {
|
||||
return [];
|
||||
}
|
||||
const { ellipsis } = unref(propsRef);
|
||||
|
||||
columns.forEach((item) => {
|
||||
const { customRender, slots } = item;
|
||||
|
||||
handleItem(item, Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots);
|
||||
});
|
||||
return columns;
|
||||
});
|
||||
|
||||
function isIfShow(column: BasicColumn): boolean {
|
||||
const ifShow = column.ifShow;
|
||||
|
||||
let isIfShow = true;
|
||||
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(column);
|
||||
}
|
||||
return isIfShow;
|
||||
}
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
const getViewColumns = computed(() => {
|
||||
const viewColumns = sortFixedColumn(unref(getColumnsRef));
|
||||
|
||||
const columns = cloneDeep(viewColumns);
|
||||
const result = columns
|
||||
.filter((column) => {
|
||||
return hasPermission(column.auth) && isIfShow(column);
|
||||
})
|
||||
.map((column) => {
|
||||
// update-begin--author:liaozhiyang---date:20230718---for: 【issues-179】antd3 一些警告以及报错(针对表格)
|
||||
if(column.slots?.customRender) {
|
||||
// slots的备份,兼容老的写法,转成新写法避免控制台警告
|
||||
column.slotsBak = column.slots;
|
||||
delete column.slots;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20230718---for: 【issues-179】antd3 一些警告以及报错(针对表格)
|
||||
|
||||
const { slots, customRender, format, edit, editRow, flag, title: metaTitle } = column;
|
||||
|
||||
if (!slots || !slots?.title) {
|
||||
// column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
|
||||
column.customTitle = column.title as string;
|
||||
Reflect.deleteProperty(column, 'title');
|
||||
}
|
||||
//update-begin-author:taoyan date:20211203 for:【online报表】分组标题显示错误,都显示成了联系信息 LOWCOD-2343
|
||||
if (column.children) {
|
||||
column.title = metaTitle;
|
||||
}
|
||||
//update-end-author:taoyan date:20211203 for:【online报表】分组标题显示错误,都显示成了联系信息 LOWCOD-2343
|
||||
|
||||
const isDefaultAction = [INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG].includes(flag!);
|
||||
if (!customRender && format && !edit && !isDefaultAction) {
|
||||
column.customRender = ({ text, record, index }) => {
|
||||
return formatCell(text, format, record, index);
|
||||
};
|
||||
}
|
||||
|
||||
// edit table
|
||||
if ((edit || editRow) && !isDefaultAction) {
|
||||
column.customRender = renderEditCell(column);
|
||||
}
|
||||
return reactive(column);
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20230919---for:【QQYUN-6387】展开写法(去掉报错)
|
||||
if (propsRef.value.expandedRowKeys && !propsRef.value.isTreeTable) {
|
||||
let index = 0;
|
||||
const findIndex = result.findIndex((item) => item.key === CUS_SEL_COLUMN_KEY);
|
||||
if (findIndex != -1) {
|
||||
index = findIndex + 1;
|
||||
}
|
||||
const next: any = result[index + 1];
|
||||
let expand = Table.EXPAND_COLUMN;
|
||||
if (next && (next['fixed'] == true || next['fixed'] == 'left')) {
|
||||
expand = Object.assign(expand, { fixed: 'left' });
|
||||
}
|
||||
result.splice(index, 0, expand);
|
||||
}
|
||||
return result;
|
||||
// update-end--author:liaozhiyang---date:20230919---for:【QQYUN-6387】展开写法(去掉报错)
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).columns,
|
||||
(columns) => {
|
||||
columnsRef.value = columns;
|
||||
cacheColumns = columns?.filter((item) => !item.flag) ?? [];
|
||||
}
|
||||
);
|
||||
|
||||
function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
|
||||
if (!dataIndex || !value) {
|
||||
return;
|
||||
}
|
||||
cacheColumns.forEach((item) => {
|
||||
if (item.dataIndex === dataIndex) {
|
||||
Object.assign(item, value);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// update-begin--author:sunjianlei---date:20220523---for: 【VUEN-1089】合并vben最新版代码,解决表格字段排序问题
|
||||
/**
|
||||
* set columns
|
||||
* @param columnList key|column
|
||||
*/
|
||||
function setColumns(columnList: Partial<BasicColumn>[] | (string | string[])[]) {
|
||||
const columns = cloneDeep(columnList);
|
||||
if (!isArray(columns)) return;
|
||||
|
||||
if (columns.length <= 0) {
|
||||
columnsRef.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const firstColumn = columns[0];
|
||||
|
||||
const cacheKeys = cacheColumns.map((item) => item.dataIndex);
|
||||
|
||||
if (!isString(firstColumn) && !isArray(firstColumn)) {
|
||||
columnsRef.value = columns as BasicColumn[];
|
||||
} else {
|
||||
const columnKeys = (columns as (string | string[])[]).map((m) => m.toString());
|
||||
const newColumns: BasicColumn[] = [];
|
||||
cacheColumns.forEach((item) => {
|
||||
newColumns.push({
|
||||
...item,
|
||||
defaultHidden: !columnKeys.includes(item.dataIndex?.toString() || (item.key as string)),
|
||||
});
|
||||
});
|
||||
// Sort according to another array
|
||||
if (!isEqual(cacheKeys, columns)) {
|
||||
newColumns.sort((prev, next) => {
|
||||
return columnKeys.indexOf(prev.dataIndex?.toString() as string) - columnKeys.indexOf(next.dataIndex?.toString() as string);
|
||||
});
|
||||
}
|
||||
columnsRef.value = newColumns;
|
||||
}
|
||||
}
|
||||
// update-end--author:sunjianlei---date:20220523---for: 【VUEN-1089】合并vben最新版代码,解决表格字段排序问题
|
||||
|
||||
function getColumns(opt?: GetColumnsParams) {
|
||||
const { ignoreIndex, ignoreAction, sort } = opt || {};
|
||||
let columns = toRaw(unref(getColumnsRef));
|
||||
if (ignoreIndex) {
|
||||
columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
|
||||
}
|
||||
if (ignoreAction) {
|
||||
columns = columns.filter((item) => item.flag !== ACTION_COLUMN_FLAG);
|
||||
}
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
// 过滤自定义选择列
|
||||
columns = columns.filter((item) => item.key !== CUS_SEL_COLUMN_KEY);
|
||||
// update-enb--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
if (sort) {
|
||||
columns = sortFixedColumn(columns);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
function getCacheColumns() {
|
||||
return cacheColumns;
|
||||
}
|
||||
|
||||
return {
|
||||
getColumnsRef,
|
||||
getCacheColumns,
|
||||
getColumns,
|
||||
setColumns,
|
||||
getViewColumns,
|
||||
setCacheColumnsByField,
|
||||
};
|
||||
}
|
||||
|
||||
function sortFixedColumn(columns: BasicColumn[]) {
|
||||
const fixedLeftColumns: BasicColumn[] = [];
|
||||
const fixedRightColumns: BasicColumn[] = [];
|
||||
const defColumns: BasicColumn[] = [];
|
||||
for (const column of columns) {
|
||||
if (column.fixed === 'left') {
|
||||
fixedLeftColumns.push(column);
|
||||
continue;
|
||||
}
|
||||
if (column.fixed === 'right') {
|
||||
fixedRightColumns.push(column);
|
||||
continue;
|
||||
}
|
||||
defColumns.push(column);
|
||||
}
|
||||
return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter((item) => !item.defaultHidden);
|
||||
}
|
||||
|
||||
// format cell
|
||||
export function formatCell(text: string, format: CellFormat, record: Recordable, index: number) {
|
||||
if (!format) {
|
||||
return text;
|
||||
}
|
||||
|
||||
// custom function
|
||||
if (isFunction(format)) {
|
||||
return format(text, record, index);
|
||||
}
|
||||
|
||||
try {
|
||||
// date type
|
||||
const DATE_FORMAT_PREFIX = 'date|';
|
||||
if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX)) {
|
||||
const dateFormat = format.replace(DATE_FORMAT_PREFIX, '');
|
||||
|
||||
if (!dateFormat) {
|
||||
return text;
|
||||
}
|
||||
return formatToDate(text, dateFormat);
|
||||
}
|
||||
|
||||
// Map
|
||||
if (isMap(format)) {
|
||||
return format.get(text);
|
||||
}
|
||||
} catch (error) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
import { computed, nextTick, unref, watchEffect } from 'vue';
|
||||
import { router } from '/@/router';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { createLocalStorage } from '/@/utils/cache';
|
||||
import { useTableContext } from './useTableContext';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
/**
|
||||
* 列表配置缓存
|
||||
*/
|
||||
export function useColumnsCache(opt, setColumns, handleColumnFixed) {
|
||||
let isInit = false;
|
||||
const table = useTableContext();
|
||||
const $ls = createLocalStorage();
|
||||
const { createMessage: $message } = useMessage();
|
||||
const route = useRoute();
|
||||
// 列表配置缓存key
|
||||
const cacheKey = computed(() => {
|
||||
// update-begin--author:liaozhiyang---date:20240226---for:【QQYUN-8367】online报表配置列展示保存,影响到其他页面的table字段的显示隐藏(开发环境热更新会有此问题,生产环境无问题)
|
||||
const path = route.path;
|
||||
let key = path.replace(/[\/\\]/g, '_');
|
||||
// update-end--author:liaozhiyang---date:20240226---for:【QQYUN-8367】online报表配置列展示保存,影响到其他页面的table字段的显示隐藏(开发环境热更新会有此问题,生产环境无问题)
|
||||
let cacheKey = table.getBindValues.value.tableSetting?.cacheKey;
|
||||
if (cacheKey) {
|
||||
key += ':' + cacheKey;
|
||||
}
|
||||
return 'columnCache:' + key;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
const columns = table.getColumns();
|
||||
if (columns.length) {
|
||||
init();
|
||||
}
|
||||
});
|
||||
|
||||
async function init() {
|
||||
if (isInit) {
|
||||
return;
|
||||
}
|
||||
isInit = true;
|
||||
let columnCache = $ls.get(cacheKey.value);
|
||||
if (columnCache && columnCache.checkedList) {
|
||||
const { checkedList, sortedList, sortableOrder, checkIndex } = columnCache;
|
||||
await nextTick();
|
||||
// checkbox的排序缓存
|
||||
opt.sortableOrder.value = sortableOrder;
|
||||
// checkbox的选中缓存
|
||||
opt.state.checkedList = checkedList;
|
||||
// tableColumn的排序缓存
|
||||
opt.plainSortOptions.value.sort((prev, next) => {
|
||||
return sortedList.indexOf(prev.value) - sortedList.indexOf(next.value);
|
||||
});
|
||||
// 重新排序tableColumn
|
||||
checkedList.sort((prev, next) => sortedList.indexOf(prev) - sortedList.indexOf(next));
|
||||
// 是否显示行号列
|
||||
if (checkIndex) {
|
||||
table.setProps({ showIndexColumn: true });
|
||||
}
|
||||
setColumns(checkedList);
|
||||
// 设置固定列
|
||||
setColumnFixed(columnCache);
|
||||
}
|
||||
}
|
||||
|
||||
/** 设置被固定的列 */
|
||||
async function setColumnFixed(columnCache) {
|
||||
const { fixedColumns } = columnCache;
|
||||
const columns = opt.plainOptions.value;
|
||||
for (const column of columns) {
|
||||
let fixedCol = fixedColumns.find((fc) => fc.key === (column.key || column.dataIndex));
|
||||
if (fixedCol) {
|
||||
await nextTick();
|
||||
handleColumnFixed(column, fixedCol.fixed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断列固定状态
|
||||
const fixedReg = /^(true|left|right)$/;
|
||||
|
||||
/** 获取被固定的列 */
|
||||
function getFixedColumns() {
|
||||
let fixedColumns: any[] = [];
|
||||
const columns = opt.plainOptions.value;
|
||||
for (const column of columns) {
|
||||
if (fixedReg.test((column.fixed ?? '').toString())) {
|
||||
fixedColumns.push({
|
||||
key: column.key || column.dataIndex,
|
||||
fixed: column.fixed === true ? 'left' : column.fixed,
|
||||
});
|
||||
}
|
||||
}
|
||||
return fixedColumns;
|
||||
}
|
||||
|
||||
/** 保存列配置 */
|
||||
function saveSetting() {
|
||||
const { checkedList } = opt.state;
|
||||
const sortedList = unref(opt.plainSortOptions).map((item) => item.value);
|
||||
$ls.set(cacheKey.value, {
|
||||
// 保存的列
|
||||
checkedList,
|
||||
// 排序后的列
|
||||
sortedList,
|
||||
// 是否显示行号列
|
||||
checkIndex: unref(opt.checkIndex),
|
||||
// checkbox原始排序
|
||||
sortableOrder: unref(opt.sortableOrder),
|
||||
// 固定列
|
||||
fixedColumns: getFixedColumns(),
|
||||
});
|
||||
$message.success('保存成功');
|
||||
// 保存之后直接关闭
|
||||
opt.popoverVisible.value = false;
|
||||
}
|
||||
|
||||
/** 重置(删除)列配置 */
|
||||
async function resetSetting() {
|
||||
// 重置固定列
|
||||
await resetFixedColumn();
|
||||
$ls.remove(cacheKey.value);
|
||||
$message.success('重置成功');
|
||||
}
|
||||
|
||||
async function resetFixedColumn() {
|
||||
const columns = opt.plainOptions.value;
|
||||
for (const column of columns) {
|
||||
column.fixed;
|
||||
if (fixedReg.test((column.fixed ?? '').toString())) {
|
||||
await nextTick();
|
||||
handleColumnFixed(column, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
saveSetting,
|
||||
resetSetting,
|
||||
};
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import type { ComputedRef } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { unref } from 'vue';
|
||||
import { ROW_KEY } from '../const';
|
||||
import { isString, isFunction } from '/@/utils/is';
|
||||
|
||||
interface Options {
|
||||
setSelectedRowKeys: (keys: string[]) => void;
|
||||
getSelectRowKeys: () => string[];
|
||||
clearSelectedRowKeys: () => void;
|
||||
emit: EmitType;
|
||||
getAutoCreateKey: ComputedRef<boolean | undefined>;
|
||||
}
|
||||
|
||||
function getKey(record: Recordable, rowKey: string | ((record: Record<string, any>) => string) | undefined, autoCreateKey?: boolean) {
|
||||
if (!rowKey || autoCreateKey) {
|
||||
return record[ROW_KEY];
|
||||
}
|
||||
if (isString(rowKey)) {
|
||||
return record[rowKey];
|
||||
}
|
||||
if (isFunction(rowKey)) {
|
||||
return record[rowKey(record)];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function useCustomRow(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{ setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options
|
||||
) {
|
||||
const customRow = (record: Recordable, index: number) => {
|
||||
return {
|
||||
onClick: (e: Event) => {
|
||||
e?.stopPropagation();
|
||||
function handleClick() {
|
||||
const { rowSelection, rowKey, clickToRowSelect } = unref(propsRef);
|
||||
if (!rowSelection || !clickToRowSelect) return;
|
||||
const keys = getSelectRowKeys();
|
||||
const key = getKey(record, rowKey, unref(getAutoCreateKey));
|
||||
if (!key) return;
|
||||
|
||||
const isCheckbox = rowSelection.type === 'checkbox';
|
||||
if (isCheckbox) {
|
||||
// 找到tr
|
||||
const tr: HTMLElement = (e as MouseEvent).composedPath?.().find((dom: HTMLElement) => dom.tagName === 'TR') as HTMLElement;
|
||||
if (!tr) return;
|
||||
// 找到Checkbox,检查是否为disabled
|
||||
const checkBox = tr.querySelector('input[type=checkbox]');
|
||||
if (!checkBox || checkBox.hasAttribute('disabled')) return;
|
||||
if (!keys.includes(key)) {
|
||||
setSelectedRowKeys([...keys, key]);
|
||||
return;
|
||||
}
|
||||
const keyIndex = keys.findIndex((item) => item === key);
|
||||
keys.splice(keyIndex, 1);
|
||||
setSelectedRowKeys(keys);
|
||||
return;
|
||||
}
|
||||
|
||||
const isRadio = rowSelection.type === 'radio';
|
||||
if (isRadio) {
|
||||
// update-begin--author:liaozhiyang---date:20231016---for:【QQYUN-6794】table列表增加radio禁用功能
|
||||
const rowSelection = propsRef.value.rowSelection;
|
||||
if (rowSelection.getCheckboxProps) {
|
||||
const result = rowSelection.getCheckboxProps(record);
|
||||
if (result.disabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231016---for:【QQYUN-6794】table列表增加radio禁用功能
|
||||
if (!keys.includes(key)) {
|
||||
if (keys.length) {
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
setSelectedRowKeys([key]);
|
||||
return;
|
||||
} else {
|
||||
// update-begin--author:liaozhiyang---date:20240527---for:【TV360X-359】erp主表点击已选中的选到了最后一个
|
||||
// 点击已经选中的,直接return不在做操作
|
||||
return;
|
||||
// update-end--author:liaozhiyang---date:20240527---for:【TV360X-359】erp主表点击已选中的选到了最后一个
|
||||
}
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
}
|
||||
handleClick();
|
||||
emit('row-click', record, index, e);
|
||||
},
|
||||
onDblclick: (event: Event) => {
|
||||
emit('row-dbClick', record, index, event);
|
||||
},
|
||||
onContextmenu: (event: Event) => {
|
||||
emit('row-contextmenu', record, index, event);
|
||||
},
|
||||
onMouseenter: (event: Event) => {
|
||||
emit('row-mouseenter', record, index, event);
|
||||
},
|
||||
onMouseleave: (event: Event) => {
|
||||
emit('row-mouseleave', record, index, event);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
customRow,
|
||||
};
|
||||
}
|
||||
@@ -1,636 +0,0 @@
|
||||
import type { BasicColumn } from '/@/components/Table';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import type { BasicTableProps, PaginationProps, TableRowSelection } from '/@/components/Table';
|
||||
import { computed, nextTick, onUnmounted, ref, toRaw, unref, watch, watchEffect } from 'vue';
|
||||
import { omit, isEqual } from 'lodash-es';
|
||||
import { throttle } from 'lodash-es';
|
||||
import { Checkbox, Radio } from 'ant-design-vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { findNodeAll } from '/@/utils/helper/treeHelper';
|
||||
import { ROW_KEY } from '/@/components/Table/src/const';
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { ModalFunc } from 'ant-design-vue/lib/modal/Modal';
|
||||
|
||||
// 自定义选择列的key
|
||||
export const CUS_SEL_COLUMN_KEY = 'j-custom-selected-column';
|
||||
|
||||
/**
|
||||
* 自定义选择列
|
||||
*/
|
||||
export function useCustomSelection(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
emit: EmitType,
|
||||
wrapRef: Ref<null | HTMLDivElement>,
|
||||
getPaginationRef: ComputedRef<boolean | PaginationProps>,
|
||||
tableData: Ref<Recordable[]>,
|
||||
childrenColumnName: ComputedRef<string>
|
||||
) {
|
||||
const { createConfirm } = useMessage();
|
||||
// 表格body元素
|
||||
const bodyEl = ref<HTMLDivElement>();
|
||||
// body元素高度
|
||||
const bodyHeight = ref<number>(0);
|
||||
// 表格tr高度
|
||||
const rowHeight = ref<number>(0);
|
||||
// body 滚动高度
|
||||
const scrollTop = ref(0);
|
||||
// 选择的key
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
// 选择的行
|
||||
const selectedRows = ref<Recordable[]>([]);
|
||||
// 变更的行
|
||||
let changeRows: Recordable[] = [];
|
||||
let allSelected: boolean = false;
|
||||
|
||||
// 扁平化数据,children数据也会放到一起
|
||||
const flattedData = computed(() => {
|
||||
// update-begin--author:liaozhiyang---date:20231016---for:【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
const data = flattenData(tableData.value, childrenColumnName.value);
|
||||
const rowSelection = propsRef.value.rowSelection;
|
||||
if (rowSelection?.type === 'checkbox' && rowSelection.getCheckboxProps) {
|
||||
for (let i = 0, len = data.length; i < len; i++) {
|
||||
const record = data[i];
|
||||
const result = rowSelection.getCheckboxProps(record);
|
||||
if (result.disabled) {
|
||||
data.splice(i, 1);
|
||||
i--;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
// update-end--author:liaozhiyang---date:20231016---for:【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
});
|
||||
|
||||
const getRowSelectionRef = computed((): TableRowSelection | null => {
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (!rowSelection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
preserveSelectedRowKeys: true,
|
||||
// selectedRowKeys: unref(selectedKeys),
|
||||
// onChange: (selectedRowKeys: string[]) => {
|
||||
// setSelectedRowKeys(selectedRowKeys);
|
||||
// },
|
||||
...omit(rowSelection, ['onChange', 'selectedRowKeys']),
|
||||
};
|
||||
});
|
||||
|
||||
// 是否是单选
|
||||
const isRadio = computed(() => {
|
||||
return getRowSelectionRef.value?.type === 'radio';
|
||||
});
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
||||
// 列key字段
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
});
|
||||
// 获取行的key字段数据
|
||||
const getRecordKey = (record) => {
|
||||
if (!getRowKey.value) {
|
||||
return record[ROW_KEY];
|
||||
} else if (isFunction(getRowKey.value)) {
|
||||
return getRowKey.value(record);
|
||||
} else {
|
||||
return record[getRowKey.value];
|
||||
}
|
||||
};
|
||||
|
||||
// 分页配置
|
||||
const getPagination = computed<PaginationProps>(() => {
|
||||
return typeof getPaginationRef.value === 'boolean' ? {} : getPaginationRef.value;
|
||||
});
|
||||
// 当前页条目数量
|
||||
const currentPageSize = computed(() => {
|
||||
const { pageSize = 10, total = flattedData.value.length } = getPagination.value;
|
||||
return pageSize > total ? total : pageSize;
|
||||
});
|
||||
|
||||
// 选择列表头props
|
||||
const selectHeaderProps = computed(() => {
|
||||
return {
|
||||
onSelectAll,
|
||||
isRadio: isRadio.value,
|
||||
selectedLength: flattedData.value.filter((data) => selectedKeys.value.includes(getRecordKey(data))).length,
|
||||
// update-begin--author:liaozhiyang---date:20240511---for:【QQYUN-9289】解决表格条数不足pageSize数量时行数全部勾选但是全选框不勾选
|
||||
// 【TV360X-53】为空时会报错,加强判断
|
||||
pageSize: tableData.value?.length ?? 0,
|
||||
// update-end--author:liaozhiyang---date:20240511---for:【QQYUN-9289】解决表格条数不足pageSize数量时行数全部勾选但是全选框不勾选
|
||||
// 【QQYUN-6774】解决checkbox禁用后全选仍能勾选问题
|
||||
disabled: flattedData.value.length == 0,
|
||||
hideSelectAll: unref(propsRef)?.rowSelection?.hideSelectAll,
|
||||
};
|
||||
});
|
||||
|
||||
// 监听传入的selectedRowKeys
|
||||
// update-begin--author:liaozhiyang---date:20240306---for:【QQYUN-8390】部门人员组件点击重置未清空(selectedRowKeys.value=[],watch没监听到加deep)
|
||||
watch(
|
||||
() => unref(propsRef)?.rowSelection?.selectedRowKeys,
|
||||
(val: string[]) => {
|
||||
// 解决selectedRowKeys在页面调用处使用ref失效
|
||||
const value = unref(val);
|
||||
if (Array.isArray(value) && !sameArray(value, selectedKeys.value)) {
|
||||
setSelectedRowKeys(value);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
);
|
||||
// update-end--author:liaozhiyang---date:20240306---for:【QQYUN-8390】部门人员组件点击重置未清空(selectedRowKeys.value=[],watch没监听到加deep)
|
||||
|
||||
/**
|
||||
* 2024-03-06
|
||||
* liaozhiyang
|
||||
* 判断是否同一个数组 (引用地址,长度,元素位置信息相同才是同一个数组。数组元素只有字符串)
|
||||
*/
|
||||
function sameArray(a, b) {
|
||||
if (a === b) {
|
||||
if (a.length === b.length) {
|
||||
return a.toString() === b.toString();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// update-begin--author:liaozhiyang---date:20240425---for:【QQYUN-9123】popupdict打开弹窗打开程序运行
|
||||
if (isEqual(a, b)) {
|
||||
return true;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240425---for:【QQYUN-9123】popupdict打开弹窗打开程序运行
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 当任意一个变化时,触发同步检测
|
||||
watch([selectedKeys, selectedRows], () => {
|
||||
nextTick(() => {
|
||||
syncSelectedRows();
|
||||
});
|
||||
});
|
||||
|
||||
// 监听滚动条事件
|
||||
const onScrollTopChange = throttle((e) => (scrollTop.value = e?.target?.scrollTop), 150);
|
||||
|
||||
let bodyResizeObserver: Nullable<ResizeObserver> = null;
|
||||
// 获取首行行高
|
||||
watchEffect(() => {
|
||||
if (bodyEl.value) {
|
||||
// 监听div高度变化
|
||||
bodyResizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
if (entry.target === bodyEl.value && entry.contentRect) {
|
||||
const { height } = entry.contentRect;
|
||||
bodyHeight.value = Math.ceil(height);
|
||||
}
|
||||
}
|
||||
});
|
||||
bodyResizeObserver.observe(bodyEl.value);
|
||||
const el = bodyEl.value?.querySelector('tbody.ant-table-tbody tr.ant-table-row') as HTMLDivElement;
|
||||
if (el) {
|
||||
rowHeight.value = el.offsetHeight;
|
||||
return;
|
||||
}
|
||||
}
|
||||
rowHeight.value = 50;
|
||||
// 这种写法是为了监听到 size 的变化
|
||||
propsRef.value.size && void 0;
|
||||
});
|
||||
|
||||
onMountedOrActivated(async () => {
|
||||
bodyEl.value = await getTableBody(wrapRef.value!);
|
||||
bodyEl.value.addEventListener('scroll', onScrollTopChange);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
if (bodyEl.value) {
|
||||
bodyEl.value?.removeEventListener('scroll', onScrollTopChange);
|
||||
}
|
||||
if (bodyResizeObserver != null) {
|
||||
bodyResizeObserver.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
// 选择全部
|
||||
function onSelectAll(checked: boolean) {
|
||||
// update-begin--author:liaozhiyang---date:20231122---for:【issues/5577】BasicTable组件全选和取消全选时不触发onSelectAll事件
|
||||
if (unref(propsRef)?.rowSelection?.onSelectAll) {
|
||||
allSelected = checked;
|
||||
changeRows = getInvertRows(selectedRows.value);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231122---for:【issues/5577】BasicTable组件全选和取消全选时不触发onSelectAll事件
|
||||
// 取消全选
|
||||
if (!checked) {
|
||||
// update-begin--author:liaozhiyang---date:20240510---for:【issues/1173】取消全选只是当前页面取消
|
||||
// selectedKeys.value = [];
|
||||
// selectedRows.value = [];
|
||||
// emitChange('all');
|
||||
flattedData.value.forEach((item) => {
|
||||
updateSelected(item, false);
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20240510---for:【issues/1173】取消全选只是当前页面取消
|
||||
return;
|
||||
}
|
||||
let modal: Nullable<ReturnType<ModalFunc>> = null;
|
||||
// 全选
|
||||
const checkAll = () => {
|
||||
if (modal != null) {
|
||||
modal.update({
|
||||
content: '正在分批全选,请稍后……',
|
||||
cancelButtonProps: { disabled: true },
|
||||
});
|
||||
}
|
||||
let showCount = 0;
|
||||
// 最小选中数量
|
||||
let minSelect = 100;
|
||||
const hidden: Recordable[] = [];
|
||||
flattedData.value.forEach((item, index, array) => {
|
||||
if (array.length > 120) {
|
||||
if (showCount <= minSelect && recordIsShow(index, Math.max((minSelect - 10) / 2, 3))) {
|
||||
showCount++;
|
||||
updateSelected(item, checked);
|
||||
} else {
|
||||
hidden.push(item);
|
||||
}
|
||||
} else {
|
||||
updateSelected(item, checked);
|
||||
}
|
||||
});
|
||||
if (hidden.length > 0) {
|
||||
return batchesSelectAll(hidden, checked, minSelect);
|
||||
} else {
|
||||
emitChange('all');
|
||||
}
|
||||
};
|
||||
|
||||
// 当数据量大于120条时,全选会导致页面卡顿,需进行慢速全选
|
||||
if (flattedData.value.length > 120) {
|
||||
modal = createConfirm({
|
||||
title: '全选',
|
||||
content: '当前数据量较大,全选可能会导致页面卡顿,确定要执行此操作吗?',
|
||||
iconType: 'warning',
|
||||
onOk: () => checkAll(),
|
||||
});
|
||||
} else {
|
||||
checkAll();
|
||||
}
|
||||
}
|
||||
|
||||
// 分批全选
|
||||
function batchesSelectAll(hidden: Recordable[], checked: boolean, minSelect: number) {
|
||||
return new Promise<void>((resolve) => {
|
||||
(function call() {
|
||||
// 每隔半秒钟,选择100条数据
|
||||
setTimeout(() => {
|
||||
const list = hidden.splice(0, minSelect);
|
||||
if (list.length > 0) {
|
||||
list.forEach((item) => {
|
||||
updateSelected(item, checked);
|
||||
});
|
||||
call();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
emitChange('all');
|
||||
// update-begin--author:liaozhiyang---date:20230811---for:【QQYUN-5687】批量选择,提示成功后,又来一个提示
|
||||
setTimeout(() =>resolve(), 0);
|
||||
// update-end--author:liaozhiyang---date:20230811---for:【QQYUN-5687】批量选择,提示成功后,又来一个提示
|
||||
}, 500);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// 选中单个
|
||||
function onSelect(record, checked) {
|
||||
updateSelected(record, checked);
|
||||
emitChange();
|
||||
}
|
||||
|
||||
function updateSelected(record, checked) {
|
||||
const recordKey = getRecordKey(record);
|
||||
if (isRadio.value) {
|
||||
selectedKeys.value = [recordKey];
|
||||
selectedRows.value = [record];
|
||||
return;
|
||||
}
|
||||
const index = selectedKeys.value.findIndex((key) => key === recordKey);
|
||||
if (checked) {
|
||||
if (index === -1) {
|
||||
selectedKeys.value.push(recordKey);
|
||||
selectedRows.value.push(record);
|
||||
}
|
||||
} else {
|
||||
if (index !== -1) {
|
||||
selectedKeys.value.splice(index, 1);
|
||||
selectedRows.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调用用户自定义的onChange事件
|
||||
function emitChange(mode = 'single') {
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (rowSelection) {
|
||||
const { onChange } = rowSelection;
|
||||
if (onChange && isFunction(onChange)) {
|
||||
setTimeout(() => {
|
||||
onChange(selectedKeys.value, selectedRows.value);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
emit('selection-change', {
|
||||
keys: getSelectRowKeys(),
|
||||
rows: getSelectRows(),
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20231122---for:【issues/5577】BasicTable组件全选和取消全选时不触发onSelectAll事件
|
||||
if (mode == 'all') {
|
||||
const rowSelection = unref(propsRef)?.rowSelection;
|
||||
if (rowSelection?.onSelectAll) {
|
||||
rowSelection.onSelectAll(allSelected, toRaw(getSelectRows()), toRaw(changeRows));
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231122---for:【issues/5577】BasicTable组件全选和取消全选时不触发
|
||||
}
|
||||
|
||||
// 用于判断是否是自定义选择列
|
||||
function isCustomSelection(column: BasicColumn) {
|
||||
return column.key === CUS_SEL_COLUMN_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前行是否可视,虚拟滚动用
|
||||
* @param index 行下标
|
||||
* @param threshold 前后阈值,默认可视区域前后显示3条
|
||||
*/
|
||||
function recordIsShow(index: number, threshold = 3) {
|
||||
// 只有数据量大于50条时,才会进行虚拟滚动
|
||||
const isVirtual = flattedData.value.length > 50;
|
||||
if (isVirtual) {
|
||||
// 根据 scrollTop、bodyHeight、rowHeight 计算出当前行是否可视(阈值前后3条)
|
||||
// flag1 = 判断当前行是否在可视区域上方3条
|
||||
const flag1 = scrollTop.value - rowHeight.value * threshold < index * rowHeight.value;
|
||||
// flag2 = 判断当前行是否在可视区域下方3条
|
||||
const flag2 = index * rowHeight.value < scrollTop.value + bodyHeight.value + rowHeight.value * threshold;
|
||||
// 全部条件满足时,才显示当前行
|
||||
return flag1 && flag2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 自定义渲染Body
|
||||
function bodyCustomRender(params) {
|
||||
const { index } = params;
|
||||
// update-begin--author:liaozhiyang---date:20231009--for:【issues/776】显示100条/页,复选框只能显示3个的问题
|
||||
if (propsRef.value.canResize && !recordIsShow(index)) {
|
||||
return '';
|
||||
}
|
||||
if (isRadio.value) {
|
||||
return renderRadioComponent(params);
|
||||
} else {
|
||||
return renderCheckboxComponent(params);
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231009---for:【issues/776】显示100条/页,复选框只能显示3个的问题
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染checkbox组件
|
||||
*/
|
||||
function renderCheckboxComponent({ record }) {
|
||||
const recordKey = getRecordKey(record);
|
||||
// 获取用户自定义checkboxProps
|
||||
const checkboxProps = ((getCheckboxProps) => {
|
||||
if (typeof getCheckboxProps === 'function') {
|
||||
try {
|
||||
return getCheckboxProps(record) ?? {};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
})(propsRef.value.rowSelection?.getCheckboxProps);
|
||||
return (
|
||||
<Checkbox
|
||||
{...checkboxProps}
|
||||
key={'j-select__' + recordKey}
|
||||
checked={selectedKeys.value.includes(recordKey)}
|
||||
onUpdate:checked={(checked) => onSelect(record, checked)}
|
||||
// update-begin--author:liaozhiyang---date:20230326---for:【QQYUN-8694】BasicTable在使用clickToRowSelect=true下,selection-change 事件在触发多次
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
// update-end--author:liaozhiyang---date:20230326---for:【QQYUN-8694】BasicTable在使用clickToRowSelect=true下,selection-change 事件在触发多次
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染radio组件
|
||||
*/
|
||||
function renderRadioComponent({ record }) {
|
||||
const recordKey = getRecordKey(record);
|
||||
// update-begin--author:liaozhiyang---date:20231016---for:【QQYUN-6794】table列表增加radio禁用功能
|
||||
// 获取用户自定义radioProps
|
||||
const checkboxProps = (() => {
|
||||
const rowSelection = propsRef.value.rowSelection;
|
||||
if (rowSelection?.getCheckboxProps) {
|
||||
return rowSelection.getCheckboxProps(record);
|
||||
}
|
||||
return {};
|
||||
})();
|
||||
// update-end--author:liaozhiyang---date:20231016---for:【QQYUN-6794】table列表增加radio禁用功能
|
||||
return (
|
||||
<Radio
|
||||
{...checkboxProps}
|
||||
key={'j-select__' + recordKey}
|
||||
checked={selectedKeys.value.includes(recordKey)}
|
||||
onUpdate:checked={(checked) => onSelect(record, checked)}
|
||||
// update-begin--author:liaozhiyang---date:20230326---for:【QQYUN-8694】BasicTable在使用clickToRowSelect=true下,selection-change 事件在触发多次
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
// update-end--author:liaozhiyang---date:20230326---for:【QQYUN-8694】BasicTable在使用clickToRowSelect=true下,selection-change 事件在触发多次
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// 创建选择列
|
||||
function handleCustomSelectColumn(columns: BasicColumn[]) {
|
||||
// update-begin--author:liaozhiyang---date:20230919---for:【issues/757】JPopup表格的选择列固定配置不生效
|
||||
const rowSelection = propsRef.value.rowSelection;
|
||||
if (!rowSelection) {
|
||||
return;
|
||||
}
|
||||
const isFixedLeft = rowSelection.fixed || columns.some((item) => item.fixed === 'left');
|
||||
// update-begin--author:liaozhiyang---date:20230919---for:【issues/757】JPopup表格的选择列固定配置不生效
|
||||
columns.unshift({
|
||||
title: '选择列',
|
||||
flag: 'CHECKBOX',
|
||||
key: CUS_SEL_COLUMN_KEY,
|
||||
width: 50,
|
||||
minWidth: 50,
|
||||
maxWidth: 50,
|
||||
align: 'center',
|
||||
...(isFixedLeft ? { fixed: 'left' } : {}),
|
||||
customRender: bodyCustomRender,
|
||||
});
|
||||
}
|
||||
|
||||
// 清空所有选择
|
||||
function clearSelectedRowKeys() {
|
||||
onSelectAll(false);
|
||||
}
|
||||
|
||||
// 通过 selectedKeys 同步 selectedRows
|
||||
function syncSelectedRows() {
|
||||
if (selectedKeys.value.length !== selectedRows.value.length) {
|
||||
setSelectedRowKeys(selectedKeys.value);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选择的key
|
||||
function setSelectedRowKeys(rowKeys: string[]) {
|
||||
const isSomeRowKeys = selectedKeys.value === rowKeys;
|
||||
selectedKeys.value = rowKeys;
|
||||
const allSelectedRows = findNodeAll(
|
||||
toRaw(unref(flattedData)).concat(toRaw(unref(selectedRows))),
|
||||
(item) => rowKeys.includes(getRecordKey(item)),
|
||||
{
|
||||
children: propsRef.value.childrenColumnName ?? 'children',
|
||||
}
|
||||
);
|
||||
const trueSelectedRows: any[] = [];
|
||||
rowKeys.forEach((key: string) => {
|
||||
const found = allSelectedRows.find((item) => getRecordKey(item) === key);
|
||||
found && trueSelectedRows.push(found);
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20231103---for:【issues/828】解决卡死问题
|
||||
if (!(isSomeRowKeys && equal(selectedRows.value, trueSelectedRows))) {
|
||||
selectedRows.value = trueSelectedRows;
|
||||
emitChange();
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20231103---for:【issues/828】解决卡死问题
|
||||
}
|
||||
/**
|
||||
*2023-11-03
|
||||
*廖志阳
|
||||
*检测selectedRows.value和trueSelectedRows是否相等,防止死循环
|
||||
*/
|
||||
function equal(oldVal, newVal) {
|
||||
let oldKeys = [],
|
||||
newKeys = [];
|
||||
if (oldVal.length === newVal.length) {
|
||||
oldKeys = oldVal.map((item) => getRecordKey(item));
|
||||
newKeys = newVal.map((item) => getRecordKey(item));
|
||||
for (let i = 0, len = oldKeys.length; i < len; i++) {
|
||||
const findItem = newKeys.find((item) => item === oldKeys[i]);
|
||||
if (!findItem) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
*2023-11-22
|
||||
*廖志阳
|
||||
*根据全选或者反选返回源数据中这次需要变更的数据
|
||||
*/
|
||||
function getInvertRows(rows: any): any {
|
||||
const allRows = findNodeAll(toRaw(unref(flattedData)), () => true, {
|
||||
children: propsRef.value.childrenColumnName ?? 'children',
|
||||
});
|
||||
if (rows.length === 0 || rows.length === allRows.length) {
|
||||
return allRows;
|
||||
} else {
|
||||
const allRowsKey = allRows.map((item) => getRecordKey(item));
|
||||
rows.forEach((rItem) => {
|
||||
const rItemKey = getRecordKey(rItem);
|
||||
const findIndex = allRowsKey.findIndex((item) => rItemKey === item);
|
||||
if (findIndex != -1) {
|
||||
allRowsKey.splice(findIndex, 1);
|
||||
allRows.splice(findIndex, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
return allRows;
|
||||
}
|
||||
function getSelectRows<T = Recordable>() {
|
||||
return unref(selectedRows) as T[];
|
||||
}
|
||||
|
||||
function getSelectRowKeys() {
|
||||
return unref(selectedKeys);
|
||||
}
|
||||
|
||||
function getRowSelection() {
|
||||
return unref(getRowSelectionRef)!;
|
||||
}
|
||||
|
||||
function deleteSelectRowByKey(key: string) {
|
||||
const index = selectedKeys.value.findIndex((item) => item === key);
|
||||
if (index !== -1) {
|
||||
selectedKeys.value.splice(index, 1);
|
||||
selectedRows.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 【QQYUN-5837】动态计算 expandIconColumnIndex
|
||||
const getExpandIconColumnIndex = computed(() => {
|
||||
const { expandIconColumnIndex } = unref(propsRef);
|
||||
// 未设置选择列,则保持不变
|
||||
if (getRowSelectionRef.value == null) {
|
||||
return expandIconColumnIndex;
|
||||
}
|
||||
// 设置了选择列,并且未传入 index 参数,则返回 1
|
||||
if (expandIconColumnIndex == null) {
|
||||
return 1;
|
||||
}
|
||||
return expandIconColumnIndex;
|
||||
});
|
||||
|
||||
return {
|
||||
getRowSelection,
|
||||
getRowSelectionRef,
|
||||
getSelectRows,
|
||||
getSelectRowKeys,
|
||||
setSelectedRowKeys,
|
||||
deleteSelectRowByKey,
|
||||
selectHeaderProps,
|
||||
isCustomSelection,
|
||||
handleCustomSelectColumn,
|
||||
clearSelectedRowKeys,
|
||||
getExpandIconColumnIndex,
|
||||
};
|
||||
}
|
||||
|
||||
function getTableBody(wrap: HTMLDivElement) {
|
||||
return new Promise<HTMLDivElement>((resolve) => {
|
||||
(function fn() {
|
||||
const bodyEl = wrap.querySelector('.ant-table-wrapper .ant-table-body') as HTMLDivElement;
|
||||
if (bodyEl) {
|
||||
resolve(bodyEl);
|
||||
} else {
|
||||
setTimeout(fn, 100);
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
function flattenData<RecordType>(data: RecordType[] | undefined, childrenColumnName: string): RecordType[] {
|
||||
let list: RecordType[] = [];
|
||||
(data || []).forEach((record) => {
|
||||
list.push(record);
|
||||
|
||||
if (record && typeof record === 'object' && childrenColumnName in record) {
|
||||
list = [...list, ...flattenData<RecordType>((record as any)[childrenColumnName], childrenColumnName)];
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
import type { BasicTableProps, FetchParams, SorterResult } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import { ref, unref, ComputedRef, computed, onMounted, watch, reactive, Ref, watchEffect } from 'vue';
|
||||
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
|
||||
import { buildUUID } from '/@/utils/uuid';
|
||||
import { isFunction, isBoolean } from '/@/utils/is';
|
||||
import { get, cloneDeep } from 'lodash-es';
|
||||
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
|
||||
|
||||
interface ActionType {
|
||||
getPaginationInfo: ComputedRef<boolean | PaginationProps>;
|
||||
setPagination: (info: Partial<PaginationProps>) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
// update-begin--author:sunjianlei---date:220220419---for:由于 getFieldsValue 返回的不是逗号分割的数据,所以改用 validate
|
||||
validate: () => Recordable;
|
||||
// update-end--author:sunjianlei---date:220220419---for:由于 getFieldsValue 返回的不是逗号分割的数据,所以改用 validate
|
||||
clearSelectedRowKeys: () => void;
|
||||
tableData: Ref<Recordable[]>;
|
||||
}
|
||||
|
||||
interface SearchState {
|
||||
sortInfo: Recordable;
|
||||
filterInfo: Record<string, string[]>;
|
||||
}
|
||||
export function useDataSource(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
{ getPaginationInfo, setPagination, setLoading, validate, clearSelectedRowKeys, tableData }: ActionType,
|
||||
emit: EmitType
|
||||
) {
|
||||
const searchState = reactive<SearchState>({
|
||||
sortInfo: {},
|
||||
filterInfo: {},
|
||||
});
|
||||
const dataSourceRef = ref<Recordable[]>([]);
|
||||
const rawDataSourceRef = ref<Recordable>({});
|
||||
|
||||
watchEffect(() => {
|
||||
tableData.value = unref(dataSourceRef);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).dataSource,
|
||||
() => {
|
||||
const { dataSource, api } = unref(propsRef);
|
||||
!api && dataSource && (dataSourceRef.value = dataSource);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
function handleTableChange(pagination: PaginationProps, filters: Partial<Recordable<string[]>>, sorter: SorterResult) {
|
||||
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
|
||||
if (clearSelectOnPageChange) {
|
||||
clearSelectedRowKeys();
|
||||
}
|
||||
setPagination(pagination);
|
||||
|
||||
const params: Recordable = {};
|
||||
if (sorter && isFunction(sortFn)) {
|
||||
const sortInfo = sortFn(sorter);
|
||||
searchState.sortInfo = sortInfo;
|
||||
params.sortInfo = sortInfo;
|
||||
}
|
||||
|
||||
if (filters && isFunction(filterFn)) {
|
||||
const filterInfo = filterFn(filters);
|
||||
searchState.filterInfo = filterInfo;
|
||||
params.filterInfo = filterInfo;
|
||||
}
|
||||
fetch(params);
|
||||
}
|
||||
|
||||
function setTableKey(items: any[]) {
|
||||
if (!items || !Array.isArray(items)) return;
|
||||
items.forEach((item) => {
|
||||
if (!item[ROW_KEY]) {
|
||||
item[ROW_KEY] = buildUUID();
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
setTableKey(item.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
});
|
||||
|
||||
const getDataSourceRef = computed(() => {
|
||||
const dataSource = unref(dataSourceRef);
|
||||
if (!dataSource || dataSource.length === 0) {
|
||||
return unref(dataSourceRef);
|
||||
}
|
||||
if (unref(getAutoCreateKey)) {
|
||||
const firstItem = dataSource[0];
|
||||
const lastItem = dataSource[dataSource.length - 1];
|
||||
|
||||
if (firstItem && lastItem) {
|
||||
if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
|
||||
const data = cloneDeep(unref(dataSourceRef));
|
||||
data.forEach((item) => {
|
||||
if (!item[ROW_KEY]) {
|
||||
item[ROW_KEY] = buildUUID();
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
setTableKey(item.children);
|
||||
}
|
||||
});
|
||||
dataSourceRef.value = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unref(dataSourceRef);
|
||||
});
|
||||
|
||||
async function updateTableData(index: number, key: string, value: any) {
|
||||
const record = dataSourceRef.value[index];
|
||||
if (record) {
|
||||
dataSourceRef.value[index][key] = value;
|
||||
}
|
||||
return dataSourceRef.value[index];
|
||||
}
|
||||
|
||||
function updateTableDataRecord(rowKey: string | number, record: Recordable): Recordable | undefined {
|
||||
const row = findTableDataRecord(rowKey);
|
||||
|
||||
if (row) {
|
||||
for (const field in row) {
|
||||
if (Reflect.has(record, field)) row[field] = record[field];
|
||||
//update-begin---author:wangshuai---date:2024-06-11---for:【TV360X-437】树表 部分组件编辑完后,列表未刷新---
|
||||
if (Reflect.has(record, field + '_dictText')) {
|
||||
row[field + '_dictText'] = record[field + '_dictText'];
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-06-11---for:【TV360X-437】树表 部分组件编辑完后,列表未刷新---
|
||||
}
|
||||
return row;
|
||||
}
|
||||
}
|
||||
function deleteTableDataRecord(rowKey: string | number | string[] | number[]) {
|
||||
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
||||
const rowKeyName = unref(getRowKey);
|
||||
if (!rowKeyName) return;
|
||||
const rowKeys = !Array.isArray(rowKey) ? [rowKey] : rowKey;
|
||||
for (const key of rowKeys) {
|
||||
let index: number | undefined = dataSourceRef.value.findIndex((row) => {
|
||||
let targetKeyName: string;
|
||||
if (typeof rowKeyName === 'function') {
|
||||
targetKeyName = rowKeyName(row);
|
||||
} else {
|
||||
targetKeyName = rowKeyName as string;
|
||||
}
|
||||
return row[targetKeyName] === key;
|
||||
});
|
||||
if (index >= 0) {
|
||||
dataSourceRef.value.splice(index, 1);
|
||||
}
|
||||
index = unref(propsRef).dataSource?.findIndex((row) => {
|
||||
let targetKeyName: string;
|
||||
if (typeof rowKeyName === 'function') {
|
||||
targetKeyName = rowKeyName(row);
|
||||
} else {
|
||||
targetKeyName = rowKeyName as string;
|
||||
}
|
||||
return row[targetKeyName] === key;
|
||||
});
|
||||
if (typeof index !== 'undefined' && index !== -1) unref(propsRef).dataSource?.splice(index, 1);
|
||||
}
|
||||
setPagination({
|
||||
total: unref(propsRef).dataSource?.length,
|
||||
});
|
||||
}
|
||||
|
||||
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
|
||||
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
||||
index = index ?? dataSourceRef.value?.length;
|
||||
unref(dataSourceRef).splice(index, 0, record);
|
||||
return unref(dataSourceRef);
|
||||
}
|
||||
function findTableDataRecord(rowKey: string | number) {
|
||||
if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
||||
|
||||
const rowKeyName = unref(getRowKey);
|
||||
if (!rowKeyName) return;
|
||||
|
||||
const { childrenColumnName = 'children' } = unref(propsRef);
|
||||
|
||||
const findRow = (array: any[]) => {
|
||||
let ret;
|
||||
array.some(function iter(r) {
|
||||
if (typeof rowKeyName === 'function') {
|
||||
if ((rowKeyName(r) as string) === rowKey) {
|
||||
ret = r;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey) {
|
||||
ret = r;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return r[childrenColumnName] && r[childrenColumnName].some(iter);
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
// const row = dataSourceRef.value.find(r => {
|
||||
// if (typeof rowKeyName === 'function') {
|
||||
// return (rowKeyName(r) as string) === rowKey
|
||||
// } else {
|
||||
// return Reflect.has(r, rowKeyName) && r[rowKeyName] === rowKey
|
||||
// }
|
||||
// })
|
||||
return findRow(dataSourceRef.value);
|
||||
}
|
||||
|
||||
async function fetch(opt?: FetchParams) {
|
||||
const { api, searchInfo, defSort, fetchSetting, beforeFetch, afterFetch, useSearchForm, pagination } = unref(propsRef);
|
||||
if (!api || !isFunction(api)) return;
|
||||
try {
|
||||
setLoading(true);
|
||||
const { pageField, sizeField, listField, totalField } = Object.assign({}, FETCH_SETTING, fetchSetting);
|
||||
let pageParams: Recordable = {};
|
||||
|
||||
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps;
|
||||
|
||||
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
|
||||
pageParams = {};
|
||||
} else {
|
||||
pageParams[pageField] = (opt && opt.page) || current;
|
||||
pageParams[sizeField] = pageSize;
|
||||
}
|
||||
|
||||
const { sortInfo = {}, filterInfo } = searchState;
|
||||
|
||||
let params: Recordable = {
|
||||
...pageParams,
|
||||
// 由于 getFieldsValue 返回的不是逗号分割的数据,所以改用 validate
|
||||
...(useSearchForm ? await validate() : {}),
|
||||
...searchInfo,
|
||||
...defSort,
|
||||
...(opt?.searchInfo ?? {}),
|
||||
...sortInfo,
|
||||
...filterInfo,
|
||||
...(opt?.sortInfo ?? {}),
|
||||
...(opt?.filterInfo ?? {}),
|
||||
};
|
||||
if (beforeFetch && isFunction(beforeFetch)) {
|
||||
params = (await beforeFetch(params)) || params;
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20240227---for:【QQYUN-8316】table查询条件,请求剔除空字符串字段
|
||||
for (let item of Object.entries(params)) {
|
||||
const [key, val] = item;
|
||||
if (val === '') {
|
||||
delete params[key];
|
||||
};
|
||||
};
|
||||
// update-end--author:liaozhiyang---date:20240227---for:【QQYUN-8316】table查询条件,请求剔除空字符串字段
|
||||
const res = await api(params);
|
||||
rawDataSourceRef.value = res;
|
||||
|
||||
const isArrayResult = Array.isArray(res);
|
||||
|
||||
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
|
||||
const resultTotal: number = isArrayResult ? 0 : get(res, totalField);
|
||||
|
||||
// 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
|
||||
if (resultTotal) {
|
||||
const currentTotalPage = Math.ceil(Number(resultTotal) / pageSize);
|
||||
if (current > currentTotalPage) {
|
||||
setPagination({
|
||||
current: currentTotalPage,
|
||||
});
|
||||
return await fetch(opt);
|
||||
}
|
||||
}
|
||||
|
||||
if (afterFetch && isFunction(afterFetch)) {
|
||||
resultItems = (await afterFetch(resultItems)) || resultItems;
|
||||
}
|
||||
dataSourceRef.value = resultItems;
|
||||
setPagination({
|
||||
total: Number(resultTotal) || 0,
|
||||
});
|
||||
if (opt && opt.page) {
|
||||
setPagination({
|
||||
current: opt.page || 1,
|
||||
});
|
||||
}
|
||||
emit('fetch-success', {
|
||||
items: unref(resultItems),
|
||||
total: Number(resultTotal),
|
||||
});
|
||||
return resultItems;
|
||||
} catch (error) {
|
||||
emit('fetch-error', error);
|
||||
dataSourceRef.value = [];
|
||||
setPagination({
|
||||
total: 0,
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function setTableData<T = Recordable>(values: T[]) {
|
||||
dataSourceRef.value = values;
|
||||
}
|
||||
|
||||
function getDataSource<T = Recordable>() {
|
||||
return getDataSourceRef.value as T[];
|
||||
}
|
||||
|
||||
function getRawDataSource<T = Recordable>() {
|
||||
return rawDataSourceRef.value as T;
|
||||
}
|
||||
|
||||
async function reload(opt?: FetchParams) {
|
||||
return await fetch(opt);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
useTimeoutFn(() => {
|
||||
unref(propsRef).immediate && fetch();
|
||||
}, 16);
|
||||
});
|
||||
|
||||
return {
|
||||
getDataSourceRef,
|
||||
getDataSource,
|
||||
getRawDataSource,
|
||||
getRowKey,
|
||||
setTableData,
|
||||
getAutoCreateKey,
|
||||
fetch,
|
||||
reload,
|
||||
updateTableData,
|
||||
updateTableDataRecord,
|
||||
deleteTableDataRecord,
|
||||
insertTableDataRecord,
|
||||
findTableDataRecord,
|
||||
handleTableChange,
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { ref, ComputedRef, unref, computed, watch } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
|
||||
export function useLoading(props: ComputedRef<BasicTableProps>) {
|
||||
const loadingRef = ref(unref(props).loading);
|
||||
|
||||
watch(
|
||||
() => unref(props).loading,
|
||||
(loading) => {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
);
|
||||
|
||||
const getLoading = computed(() => unref(loadingRef));
|
||||
|
||||
function setLoading(loading: boolean) {
|
||||
loadingRef.value = loading;
|
||||
}
|
||||
|
||||
return { getLoading, setLoading };
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { computed, unref, ref, ComputedRef, watch } from 'vue';
|
||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||
import { isBoolean } from '/@/utils/is';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '../const';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
interface ItemRender {
|
||||
page: number;
|
||||
type: 'page' | 'prev' | 'next';
|
||||
originalElement: any;
|
||||
}
|
||||
|
||||
function itemRender({ page, type, originalElement }: ItemRender) {
|
||||
if (type === 'prev') {
|
||||
return page === 0 ? null : <LeftOutlined />;
|
||||
} else if (type === 'next') {
|
||||
return page === 1 ? null : <RightOutlined />;
|
||||
}
|
||||
return originalElement;
|
||||
}
|
||||
|
||||
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const configRef = ref<PaginationProps>({});
|
||||
const show = ref(true);
|
||||
|
||||
watch(
|
||||
() => unref(refProps).pagination,
|
||||
(pagination) => {
|
||||
if (!isBoolean(pagination) && pagination) {
|
||||
configRef.value = {
|
||||
...unref(configRef),
|
||||
...(pagination ?? {}),
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const getPaginationInfo = computed((): PaginationProps | boolean => {
|
||||
const { pagination } = unref(refProps);
|
||||
|
||||
if (!unref(show) || (isBoolean(pagination) && !pagination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
current: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
size: 'small',
|
||||
defaultPageSize: PAGE_SIZE,
|
||||
showTotal: (total) => t('component.table.total', { total }),
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: PAGE_SIZE_OPTIONS,
|
||||
itemRender: itemRender,
|
||||
showQuickJumper: true,
|
||||
...(isBoolean(pagination) ? {} : pagination),
|
||||
...unref(configRef),
|
||||
};
|
||||
});
|
||||
|
||||
function setPagination(info: Partial<PaginationProps>) {
|
||||
const paginationInfo = unref(getPaginationInfo);
|
||||
configRef.value = {
|
||||
...(!isBoolean(paginationInfo) ? paginationInfo : {}),
|
||||
...info,
|
||||
};
|
||||
}
|
||||
|
||||
function getPagination() {
|
||||
return unref(getPaginationInfo);
|
||||
}
|
||||
|
||||
function getShowPagination() {
|
||||
return unref(show);
|
||||
}
|
||||
|
||||
async function setShowPagination(flag: boolean) {
|
||||
show.value = flag;
|
||||
}
|
||||
|
||||
return { getPagination, getPaginationInfo, setShowPagination, getShowPagination, setPagination };
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import type { BasicTableProps, TableRowSelection } from '../types/table';
|
||||
import { computed, ComputedRef, nextTick, Ref, ref, toRaw, unref, watch } from 'vue';
|
||||
import { ROW_KEY } from '../const';
|
||||
import { omit } from 'lodash-es';
|
||||
import { findNodeAll } from '/@/utils/helper/treeHelper';
|
||||
|
||||
export function useRowSelection(propsRef: ComputedRef<BasicTableProps>, tableData: Ref<Recordable[]>, emit: EmitType) {
|
||||
const selectedRowKeysRef = ref<string[]>([]);
|
||||
const selectedRowRef = ref<Recordable[]>([]);
|
||||
|
||||
const getRowSelectionRef = computed((): TableRowSelection | null => {
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (!rowSelection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
// AntDV3.0 之后使用远程加载数据进行分页时,
|
||||
// 默认会清空上一页选择的行数据(导致无法跨页选择),
|
||||
// 将此属性设置为 true 即可解决。
|
||||
preserveSelectedRowKeys: true,
|
||||
selectedRowKeys: unref(selectedRowKeysRef),
|
||||
onChange: (selectedRowKeys: string[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys);
|
||||
},
|
||||
...omit(rowSelection, ['onChange']),
|
||||
};
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(propsRef).rowSelection?.selectedRowKeys,
|
||||
(v: string[]) => {
|
||||
setSelectedRowKeys(v);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => unref(selectedRowKeysRef),
|
||||
() => {
|
||||
nextTick(() => {
|
||||
const { rowSelection } = unref(propsRef);
|
||||
if (rowSelection) {
|
||||
const { onChange } = rowSelection;
|
||||
if (onChange && isFunction(onChange)) onChange(getSelectRowKeys(), getSelectRows());
|
||||
}
|
||||
//update-begin---author:scott ---date:2023-06-19 for:【issues/503】table行选择时卡顿明显 #503---
|
||||
//table行选择时卡顿明显 #503
|
||||
if (unref(tableData).length > 0) {
|
||||
emit('selection-change', {
|
||||
keys: getSelectRowKeys(),
|
||||
rows: getSelectRows(),
|
||||
});
|
||||
}
|
||||
//update-end---author:scott ---date::2023-06-19 for:【issues/503】table行选择时卡顿明显 #503---
|
||||
});
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
});
|
||||
|
||||
function setSelectedRowKeys(rowKeys: string[]) {
|
||||
selectedRowKeysRef.value = rowKeys;
|
||||
const allSelectedRows = findNodeAll(
|
||||
toRaw(unref(tableData)).concat(toRaw(unref(selectedRowRef))),
|
||||
(item) => rowKeys.includes(item[unref(getRowKey) as string]),
|
||||
{
|
||||
children: propsRef.value.childrenColumnName ?? 'children',
|
||||
}
|
||||
);
|
||||
const trueSelectedRows: any[] = [];
|
||||
rowKeys.forEach((key: string) => {
|
||||
const found = allSelectedRows.find((item) => item[unref(getRowKey) as string] === key);
|
||||
found && trueSelectedRows.push(found);
|
||||
});
|
||||
selectedRowRef.value = trueSelectedRows;
|
||||
}
|
||||
|
||||
function setSelectedRows(rows: Recordable[]) {
|
||||
selectedRowRef.value = rows;
|
||||
}
|
||||
|
||||
function clearSelectedRowKeys() {
|
||||
selectedRowRef.value = [];
|
||||
selectedRowKeysRef.value = [];
|
||||
}
|
||||
|
||||
function deleteSelectRowByKey(key: string) {
|
||||
const selectedRowKeys = unref(selectedRowKeysRef);
|
||||
const index = selectedRowKeys.findIndex((item) => item === key);
|
||||
if (index !== -1) {
|
||||
unref(selectedRowKeysRef).splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectRowKeys() {
|
||||
return unref(selectedRowKeysRef);
|
||||
}
|
||||
|
||||
function getSelectRows<T = Recordable>() {
|
||||
// const ret = toRaw(unref(selectedRowRef)).map((item) => toRaw(item));
|
||||
return unref(selectedRowRef) as T[];
|
||||
}
|
||||
|
||||
function getRowSelection() {
|
||||
return unref(getRowSelectionRef)!;
|
||||
}
|
||||
|
||||
return {
|
||||
getRowSelection,
|
||||
getRowSelectionRef,
|
||||
getSelectRows,
|
||||
getSelectRowKeys,
|
||||
setSelectedRowKeys,
|
||||
clearSelectedRowKeys,
|
||||
deleteSelectRowByKey,
|
||||
setSelectedRows,
|
||||
};
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
import type { BasicTableProps, TableActionType, FetchParams, BasicColumn } from '../types/table';
|
||||
import type { PaginationProps } from '../types/pagination';
|
||||
import type { DynamicProps } from '/#/utils';
|
||||
import type { FormActionType } from '/@/components/Form';
|
||||
import type { WatchStopHandle } from 'vue';
|
||||
import { getDynamicProps } from '/@/utils';
|
||||
import { ref, onUnmounted, unref, watch, toRaw } from 'vue';
|
||||
import { isProdMode } from '/@/utils/env';
|
||||
import { error } from '/@/utils/log';
|
||||
|
||||
type Props = Partial<DynamicProps<BasicTableProps>>;
|
||||
|
||||
type UseTableMethod = TableActionType & {
|
||||
getForm: () => FormActionType;
|
||||
};
|
||||
|
||||
export function useTable(tableProps?: Props): [
|
||||
(instance: TableActionType, formInstance: UseTableMethod) => void,
|
||||
TableActionType & {
|
||||
getForm: () => FormActionType;
|
||||
}
|
||||
] {
|
||||
const tableRef = ref<Nullable<TableActionType>>(null);
|
||||
const loadedRef = ref<Nullable<boolean>>(false);
|
||||
const formRef = ref<Nullable<UseTableMethod>>(null);
|
||||
|
||||
let stopWatch: WatchStopHandle;
|
||||
|
||||
function register(instance: TableActionType, formInstance: UseTableMethod) {
|
||||
isProdMode() &&
|
||||
onUnmounted(() => {
|
||||
tableRef.value = null;
|
||||
loadedRef.value = null;
|
||||
});
|
||||
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(tableRef)) return;
|
||||
|
||||
tableRef.value = instance;
|
||||
formRef.value = formInstance;
|
||||
tableProps && instance.setProps(getDynamicProps(tableProps));
|
||||
loadedRef.value = true;
|
||||
|
||||
stopWatch?.();
|
||||
|
||||
stopWatch = watch(
|
||||
() => tableProps,
|
||||
() => {
|
||||
tableProps && instance.setProps(getDynamicProps(tableProps));
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function getTableInstance(): TableActionType {
|
||||
const table = unref(tableRef);
|
||||
if (!table) {
|
||||
error('The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!');
|
||||
}
|
||||
return table as TableActionType;
|
||||
}
|
||||
|
||||
function getTableRef(){
|
||||
return tableRef;
|
||||
}
|
||||
|
||||
const methods: TableActionType & {
|
||||
getForm: () => FormActionType;
|
||||
} & {
|
||||
getTableRef: () => any;
|
||||
} = {
|
||||
reload: async (opt?: FetchParams) => {
|
||||
return await getTableInstance().reload(opt);
|
||||
},
|
||||
setProps: (props: Partial<BasicTableProps>) => {
|
||||
getTableInstance().setProps(props);
|
||||
},
|
||||
redoHeight: () => {
|
||||
getTableInstance().redoHeight();
|
||||
},
|
||||
setLoading: (loading: boolean) => {
|
||||
getTableInstance().setLoading(loading);
|
||||
},
|
||||
getDataSource: () => {
|
||||
return getTableInstance().getDataSource();
|
||||
},
|
||||
getRawDataSource: () => {
|
||||
return getTableInstance().getRawDataSource();
|
||||
},
|
||||
getColumns: ({ ignoreIndex = false }: { ignoreIndex?: boolean } = {}) => {
|
||||
const columns = getTableInstance().getColumns({ ignoreIndex }) || [];
|
||||
return toRaw(columns);
|
||||
},
|
||||
setColumns: (columns: BasicColumn[]) => {
|
||||
getTableInstance().setColumns(columns);
|
||||
},
|
||||
setTableData: (values: any[]) => {
|
||||
return getTableInstance().setTableData(values);
|
||||
},
|
||||
setPagination: (info: Partial<PaginationProps>) => {
|
||||
return getTableInstance().setPagination(info);
|
||||
},
|
||||
deleteSelectRowByKey: (key: string) => {
|
||||
getTableInstance().deleteSelectRowByKey(key);
|
||||
},
|
||||
getSelectRowKeys: () => {
|
||||
return toRaw(getTableInstance().getSelectRowKeys());
|
||||
},
|
||||
getSelectRows: () => {
|
||||
return toRaw(getTableInstance().getSelectRows());
|
||||
},
|
||||
clearSelectedRowKeys: () => {
|
||||
getTableInstance().clearSelectedRowKeys();
|
||||
},
|
||||
setSelectedRowKeys: (keys: string[] | number[]) => {
|
||||
getTableInstance().setSelectedRowKeys(keys);
|
||||
},
|
||||
getPaginationRef: () => {
|
||||
return getTableInstance().getPaginationRef();
|
||||
},
|
||||
getSize: () => {
|
||||
return toRaw(getTableInstance().getSize());
|
||||
},
|
||||
updateTableData: (index: number, key: string, value: any) => {
|
||||
return getTableInstance().updateTableData(index, key, value);
|
||||
},
|
||||
deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => {
|
||||
return getTableInstance().deleteTableDataRecord(rowKey);
|
||||
},
|
||||
insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => {
|
||||
return getTableInstance().insertTableDataRecord(record, index);
|
||||
},
|
||||
updateTableDataRecord: (rowKey: string | number, record: Recordable) => {
|
||||
return getTableInstance().updateTableDataRecord(rowKey, record);
|
||||
},
|
||||
findTableDataRecord: (rowKey: string | number) => {
|
||||
return getTableInstance().findTableDataRecord(rowKey);
|
||||
},
|
||||
getRowSelection: () => {
|
||||
return toRaw(getTableInstance().getRowSelection());
|
||||
},
|
||||
getCacheColumns: () => {
|
||||
return toRaw(getTableInstance().getCacheColumns());
|
||||
},
|
||||
getForm: () => {
|
||||
return unref(formRef) as unknown as FormActionType;
|
||||
},
|
||||
setShowPagination: async (show: boolean) => {
|
||||
getTableInstance().setShowPagination(show);
|
||||
},
|
||||
getShowPagination: () => {
|
||||
return toRaw(getTableInstance().getShowPagination());
|
||||
},
|
||||
expandAll: () => {
|
||||
getTableInstance().expandAll();
|
||||
},
|
||||
collapseAll: () => {
|
||||
getTableInstance().collapseAll();
|
||||
},
|
||||
getTableRef: () => {
|
||||
return getTableRef();
|
||||
}
|
||||
};
|
||||
|
||||
return [register, methods];
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import type { Ref } from 'vue';
|
||||
import type { BasicTableProps, TableActionType } from '../types/table';
|
||||
import { provide, inject, ComputedRef } from 'vue';
|
||||
|
||||
const key = Symbol('basic-table');
|
||||
|
||||
type Instance = TableActionType & {
|
||||
wrapRef: Ref<Nullable<HTMLElement>>;
|
||||
getBindValues: ComputedRef<Recordable>;
|
||||
};
|
||||
|
||||
type RetInstance = Omit<Instance, 'getBindValues'> & {
|
||||
getBindValues: ComputedRef<BasicTableProps>;
|
||||
};
|
||||
|
||||
export function createTableContext(instance: Instance) {
|
||||
provide(key, instance);
|
||||
}
|
||||
|
||||
export function useTableContext(): RetInstance {
|
||||
return inject(key) as RetInstance;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import type { ComputedRef, Ref } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { computed, unref, ref, toRaw } from 'vue';
|
||||
import { ROW_KEY } from '../const';
|
||||
|
||||
export function useTableExpand(propsRef: ComputedRef<BasicTableProps>, tableData: Ref<Recordable[]>, emit: EmitType) {
|
||||
const expandedRowKeys = ref<string[]>([]);
|
||||
|
||||
const getAutoCreateKey = computed(() => {
|
||||
return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
|
||||
});
|
||||
|
||||
const getRowKey = computed(() => {
|
||||
const { rowKey } = unref(propsRef);
|
||||
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
|
||||
});
|
||||
|
||||
const getExpandOption = computed(() => {
|
||||
const { isTreeTable } = unref(propsRef);
|
||||
if (!isTreeTable) return {};
|
||||
|
||||
return {
|
||||
expandedRowKeys: unref(expandedRowKeys),
|
||||
onExpandedRowsChange: (keys: string[]) => {
|
||||
expandedRowKeys.value = keys;
|
||||
emit('expanded-rows-change', keys);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
function expandAll() {
|
||||
const keys = getAllKeys();
|
||||
expandedRowKeys.value = keys;
|
||||
}
|
||||
|
||||
function getAllKeys(data?: Recordable[]) {
|
||||
const keys: string[] = [];
|
||||
const { childrenColumnName } = unref(propsRef);
|
||||
toRaw(data || unref(tableData)).forEach((item) => {
|
||||
keys.push(item[unref(getRowKey) as string]);
|
||||
const children = item[childrenColumnName || 'children'];
|
||||
if (children?.length) {
|
||||
keys.push(...getAllKeys(children));
|
||||
}
|
||||
});
|
||||
return keys;
|
||||
}
|
||||
|
||||
function collapseAll() {
|
||||
expandedRowKeys.value = [];
|
||||
}
|
||||
|
||||
return { getExpandOption, expandAll, collapseAll };
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import type { ComputedRef, Ref, Slots } from 'vue';
|
||||
import type { BasicTableProps } from '../types/table';
|
||||
import { unref, computed, h, nextTick, watchEffect } from 'vue';
|
||||
import TableFooter from '../components/TableFooter.vue';
|
||||
import { useEventListener } from '/@/hooks/event/useEventListener';
|
||||
|
||||
export function useTableFooter(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
slots: Slots,
|
||||
scrollRef: ComputedRef<{
|
||||
x: string | number | true;
|
||||
y: Nullable<number>;
|
||||
scrollToFirstRowOnChange: boolean;
|
||||
}>,
|
||||
tableElRef: Ref<ComponentRef>,
|
||||
getDataSourceRef: ComputedRef<Recordable>
|
||||
) {
|
||||
const getIsEmptyData = computed(() => {
|
||||
return (unref(getDataSourceRef) || []).length === 0;
|
||||
});
|
||||
|
||||
// 是否有展开行
|
||||
const hasExpandedRow = computed(() => Object.keys(slots).includes('expandedRowRender'))
|
||||
|
||||
const getFooterProps = computed((): Recordable | undefined => {
|
||||
const { summaryFunc, showSummary, summaryData, bordered } = unref(propsRef);
|
||||
return showSummary && !unref(getIsEmptyData) ? () => h(TableFooter, {
|
||||
bordered,
|
||||
summaryFunc,
|
||||
summaryData,
|
||||
scroll: unref(scrollRef),
|
||||
hasExpandedRow: hasExpandedRow.value
|
||||
}) : undefined;
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
handleSummary();
|
||||
});
|
||||
|
||||
function handleSummary() {
|
||||
const { showSummary } = unref(propsRef);
|
||||
if (!showSummary || unref(getIsEmptyData)) return;
|
||||
|
||||
nextTick(() => {
|
||||
const tableEl = unref(tableElRef);
|
||||
if (!tableEl) return;
|
||||
const bodyDom = tableEl.$el.querySelector('.ant-table-content');
|
||||
useEventListener({
|
||||
el: bodyDom,
|
||||
name: 'scroll',
|
||||
listener: () => {
|
||||
const footerBodyDom = tableEl.$el.querySelector('.ant-table-footer .ant-table-content') as HTMLDivElement;
|
||||
if (!footerBodyDom || !bodyDom) return;
|
||||
footerBodyDom.scrollLeft = bodyDom.scrollLeft;
|
||||
},
|
||||
wait: 0,
|
||||
options: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
return { getFooterProps };
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { ComputedRef, Slots } from 'vue';
|
||||
import type { BasicTableProps, FetchParams } from '../types/table';
|
||||
import { unref, computed } from 'vue';
|
||||
import type { FormProps } from '/@/components/Form';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
export function useTableForm(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
slots: Slots,
|
||||
fetch: (opt?: FetchParams | undefined) => Promise<void>,
|
||||
getLoading: ComputedRef<boolean | undefined>
|
||||
) {
|
||||
const getFormProps = computed((): Partial<FormProps> => {
|
||||
const { formConfig } = unref(propsRef);
|
||||
const { submitButtonOptions, autoSubmitOnEnter} = formConfig || {};
|
||||
return {
|
||||
showAdvancedButton: true,
|
||||
...formConfig,
|
||||
submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions },
|
||||
compact: true,
|
||||
//update-begin-author:liusq---date:20230605--for: [issues/568]设置 autoSubmitOnEnter: false 不生效 ---
|
||||
autoSubmitOnEnter: autoSubmitOnEnter,
|
||||
//update-end-author:liusq---date:20230605--for: [issues/568]设置 autoSubmitOnEnter: false 不生效 ---
|
||||
};
|
||||
});
|
||||
|
||||
const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
|
||||
const keys = Object.keys(slots);
|
||||
return keys.map((item) => (item.startsWith('form-') ? item : null)).filter((item) => !!item) as string[];
|
||||
});
|
||||
|
||||
function replaceFormSlotKey(key: string) {
|
||||
if (!key) return '';
|
||||
return key?.replace?.(/form\-/, '') ?? '';
|
||||
}
|
||||
|
||||
function handleSearchInfoChange(info: Recordable) {
|
||||
const { handleSearchInfoFn } = unref(propsRef);
|
||||
if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) {
|
||||
info = handleSearchInfoFn(info) || info;
|
||||
}
|
||||
fetch({ searchInfo: info, page: 1 });
|
||||
}
|
||||
|
||||
return {
|
||||
getFormProps,
|
||||
replaceFormSlotKey,
|
||||
getFormSlotKeys,
|
||||
handleSearchInfoChange,
|
||||
};
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import type { ComputedRef, Slots } from 'vue';
|
||||
import type { BasicTableProps, InnerHandlers } from '../types/table';
|
||||
import { unref, computed, h } from 'vue';
|
||||
import TableHeader from '../components/TableHeader.vue';
|
||||
import { isString } from '/@/utils/is';
|
||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||
|
||||
export function useTableHeader(propsRef: ComputedRef<BasicTableProps>, slots: Slots, handlers: InnerHandlers) {
|
||||
const getHeaderProps = computed((): Recordable => {
|
||||
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef);
|
||||
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting;
|
||||
if (hideTitle && !isString(title)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
title: hideTitle
|
||||
? null
|
||||
: () =>
|
||||
h(
|
||||
TableHeader,
|
||||
{
|
||||
title,
|
||||
titleHelpMessage,
|
||||
showTableSetting,
|
||||
tableSetting,
|
||||
onColumnsChange: handlers.onColumnsChange,
|
||||
} as Recordable,
|
||||
{
|
||||
...(slots.toolbar
|
||||
? {
|
||||
toolbar: () => getSlot(slots, 'toolbar'),
|
||||
}
|
||||
: {}),
|
||||
...(slots.tableTitle
|
||||
? {
|
||||
tableTitle: () => getSlot(slots, 'tableTitle'),
|
||||
}
|
||||
: {}),
|
||||
...(slots.headerTop
|
||||
? {
|
||||
headerTop: () => getSlot(slots, 'headerTop'),
|
||||
}
|
||||
: {}),
|
||||
//添加tableTop插槽
|
||||
...(slots.tableTop
|
||||
? {
|
||||
tableTop: () => getSlot(slots, 'tableTop'),
|
||||
}
|
||||
: {}),
|
||||
// 添加alertAfter插槽
|
||||
...(slots.alertAfter ? { alertAfter: () => getSlot(slots, 'alertAfter') } : {}),
|
||||
}
|
||||
),
|
||||
};
|
||||
});
|
||||
return { getHeaderProps };
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
import type { BasicTableProps, TableRowSelection, BasicColumn } from '../types/table';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import { computed, unref, ref, nextTick, watch } from 'vue';
|
||||
import { getViewportOffset } from '/@/utils/domUtils';
|
||||
import { isBoolean } from '/@/utils/is';
|
||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||
import { useModalContext } from '/@/components/Modal';
|
||||
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import componentSetting from '/@/settings/componentSetting';
|
||||
|
||||
export function useTableScroll(
|
||||
propsRef: ComputedRef<BasicTableProps>,
|
||||
tableElRef: Ref<ComponentRef>,
|
||||
columnsRef: ComputedRef<BasicColumn[]>,
|
||||
rowSelectionRef: ComputedRef<TableRowSelection<any> | null>,
|
||||
getDataSourceRef: ComputedRef<Recordable[]>
|
||||
) {
|
||||
const tableHeightRef: Ref<Nullable<number>> = ref(null);
|
||||
|
||||
const modalFn = useModalContext();
|
||||
|
||||
// Greater than animation time 280
|
||||
const debounceRedoHeight = useDebounceFn(redoHeight, 100);
|
||||
|
||||
const getCanResize = computed(() => {
|
||||
const { canResize, scroll } = unref(propsRef);
|
||||
return canResize && !(scroll || {}).y;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => [unref(getCanResize), unref(getDataSourceRef)?.length],
|
||||
() => {
|
||||
debounceRedoHeight();
|
||||
},
|
||||
{
|
||||
flush: 'post',
|
||||
}
|
||||
);
|
||||
|
||||
function redoHeight() {
|
||||
nextTick(() => {
|
||||
calcTableHeight();
|
||||
});
|
||||
}
|
||||
|
||||
function setHeight(heigh: number) {
|
||||
tableHeightRef.value = heigh;
|
||||
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
||||
modalFn?.redoModalHeight?.();
|
||||
}
|
||||
|
||||
// No need to repeat queries
|
||||
let paginationEl: HTMLElement | null;
|
||||
let footerEl: HTMLElement | null;
|
||||
let bodyEl: HTMLElement | null;
|
||||
|
||||
async function calcTableHeight() {
|
||||
const { resizeHeightOffset, pagination, maxHeight, minHeight } = unref(propsRef);
|
||||
const tableData = unref(getDataSourceRef);
|
||||
|
||||
const table = unref(tableElRef);
|
||||
if (!table) return;
|
||||
|
||||
const tableEl: Element = table.$el;
|
||||
if (!tableEl) return;
|
||||
|
||||
if (!bodyEl) {
|
||||
//update-begin-author:taoyan date:2023-2-11 for: issues/355 前端-jeecgboot-vue3 3.4.4版本,BasicTable高度自适应功能失效,设置BasicTable组件maxHeight失效; 原因已找到,请看详情
|
||||
bodyEl = tableEl.querySelector('.ant-table-tbody');
|
||||
//update-end-author:taoyan date:2023-2-11 for: issues/355 前端-jeecgboot-vue3 3.4.4版本,BasicTable高度自适应功能失效,设置BasicTable组件maxHeight失效; 原因已找到,请看详情
|
||||
if (!bodyEl) return;
|
||||
}
|
||||
|
||||
const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight;
|
||||
const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth;
|
||||
|
||||
if (hasScrollBarY) {
|
||||
tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.remove('hide-scrollbar-y');
|
||||
} else {
|
||||
!tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.add('hide-scrollbar-y');
|
||||
}
|
||||
|
||||
if (hasScrollBarX) {
|
||||
tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.remove('hide-scrollbar-x');
|
||||
} else {
|
||||
!tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.add('hide-scrollbar-x');
|
||||
}
|
||||
|
||||
bodyEl!.style.height = 'unset';
|
||||
|
||||
if (!unref(getCanResize) || ( !tableData || tableData.length === 0)) return;
|
||||
|
||||
await nextTick();
|
||||
//Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
|
||||
|
||||
const headEl = tableEl.querySelector('.ant-table-thead');
|
||||
|
||||
if (!headEl) return;
|
||||
|
||||
// Table height from bottom
|
||||
const { bottomIncludeBody } = getViewportOffset(headEl);
|
||||
// Table height from bottom height-custom offset
|
||||
|
||||
const paddingHeight = 32;
|
||||
// Pager height
|
||||
let paginationHeight = 2;
|
||||
if (!isBoolean(pagination)) {
|
||||
paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement;
|
||||
if (paginationEl) {
|
||||
const offsetHeight = paginationEl.offsetHeight;
|
||||
paginationHeight += offsetHeight || 0;
|
||||
} else {
|
||||
// TODO First fix 24
|
||||
paginationHeight += 24;
|
||||
}
|
||||
} else {
|
||||
paginationHeight = -8;
|
||||
}
|
||||
|
||||
let footerHeight = 0;
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1137】BasicTable自适应高度计算没有减去尾部高度
|
||||
footerEl = tableEl.querySelector('.ant-table-footer');
|
||||
if (footerEl) {
|
||||
const offsetHeight = footerEl.offsetHeight;
|
||||
footerHeight = offsetHeight || 0;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1137】BasicTable自适应高度计算没有减去尾部高度
|
||||
|
||||
let headerHeight = 0;
|
||||
if (headEl) {
|
||||
headerHeight = (headEl as HTMLElement).offsetHeight;
|
||||
}
|
||||
|
||||
let height = bottomIncludeBody - (resizeHeightOffset || 0) - paddingHeight - paginationHeight - footerHeight - headerHeight;
|
||||
// update-begin--author:liaozhiyang---date:20240603---for【TV360X-861】列表查询区域不可往上滚动
|
||||
// 10+6(外层边距padding:10 + 内层padding-bottom:6)
|
||||
height -= 16;
|
||||
// update-end--author:liaozhiyang---date:20240603---for:【TV360X-861】列表查询区域不可往上滚动
|
||||
|
||||
height = (height < minHeight! ? (minHeight as number) : height) ?? height;
|
||||
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
|
||||
setHeight(height);
|
||||
|
||||
bodyEl!.style.height = `${height}px`;
|
||||
}
|
||||
useWindowSizeFn(calcTableHeight, 280);
|
||||
onMountedOrActivated(() => {
|
||||
calcTableHeight();
|
||||
nextTick(() => {
|
||||
debounceRedoHeight();
|
||||
});
|
||||
});
|
||||
|
||||
const getScrollX = computed(() => {
|
||||
let width = 0;
|
||||
// update-begin--author:liaozhiyang---date:20230922---for:【QQYUN-6391】在线表单列表字段过多时,列头和数据对不齐
|
||||
// if (unref(rowSelectionRef)) {
|
||||
// width += 60;
|
||||
// }
|
||||
// update-end--author:liaozhiyang---date:20230922---for:【QQYUN-6391】在线表单列表字段过多时,列头和数据对不齐
|
||||
// update-begin--author:liaozhiyang---date:20230925---for:【issues/5411】BasicTable 配置maxColumnWidth 未生效
|
||||
const { maxColumnWidth } = unref(propsRef);
|
||||
// TODO props ?? 0;
|
||||
const NORMAL_WIDTH = maxColumnWidth ?? 150;
|
||||
// update-end--author:liaozhiyang---date:20230925---for:【issues/5411】BasicTable 配置maxColumnWidth 未生效
|
||||
|
||||
const columns = unref(columnsRef).filter((item) => !item.defaultHidden);
|
||||
columns.forEach((item) => {
|
||||
width += Number.parseInt(item.width as string) || 0;
|
||||
});
|
||||
const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width'));
|
||||
|
||||
const len = unsetWidthColumns.length;
|
||||
if (len !== 0) {
|
||||
width += len * NORMAL_WIDTH;
|
||||
}
|
||||
|
||||
const table = unref(tableElRef);
|
||||
const tableWidth = table?.$el?.offsetWidth ?? 0;
|
||||
return tableWidth > width ? '100%' : width;
|
||||
});
|
||||
|
||||
const getScrollRef = computed(() => {
|
||||
const tableHeight = unref(tableHeightRef);
|
||||
const { canResize, scroll } = unref(propsRef);
|
||||
const { table } = componentSetting;
|
||||
return {
|
||||
x: unref(getScrollX),
|
||||
y: canResize ? tableHeight : null,
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
scrollToFirstRowOnChange: table.scrollToFirstRowOnChange,
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
...scroll,
|
||||
};
|
||||
});
|
||||
|
||||
return { getScrollRef, redoHeight };
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { ComputedRef } from 'vue';
|
||||
import type { BasicTableProps, TableCustomRecord } from '../types/table';
|
||||
import { unref } from 'vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
export function useTableStyle(propsRef: ComputedRef<BasicTableProps>, prefixCls: string) {
|
||||
function getRowClassName(record: TableCustomRecord, index: number) {
|
||||
const { striped, rowClassName } = unref(propsRef);
|
||||
const classNames: string[] = [];
|
||||
if (striped) {
|
||||
classNames.push((index || 0) % 2 === 1 ? `${prefixCls}-row__striped` : '');
|
||||
}
|
||||
if (rowClassName && isFunction(rowClassName)) {
|
||||
classNames.push(rowClassName(record, index));
|
||||
}
|
||||
return classNames.filter((cls) => !!cls).join(' ');
|
||||
}
|
||||
|
||||
return { getRowClassName };
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
import type { PropType } from 'vue';
|
||||
import type { PaginationProps } from './types/pagination';
|
||||
import type { BasicColumn, FetchSetting, TableSetting, SorterResult, TableCustomRecord, TableRowSelection, SizeType } from './types/table';
|
||||
import type { FormProps } from '/@/components/Form';
|
||||
import { DEFAULT_FILTER_FN, DEFAULT_SORT_FN, FETCH_SETTING, DEFAULT_SIZE } from './const';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export const basicProps = {
|
||||
clickToRowSelect: propTypes.bool.def(true),
|
||||
isTreeTable: propTypes.bool.def(false),
|
||||
tableSetting: propTypes.shape<TableSetting>({}),
|
||||
inset: propTypes.bool,
|
||||
sortFn: {
|
||||
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
||||
default: DEFAULT_SORT_FN,
|
||||
},
|
||||
filterFn: {
|
||||
type: Function as PropType<(data: Partial<Recordable<string[]>>) => any>,
|
||||
default: DEFAULT_FILTER_FN,
|
||||
},
|
||||
showTableSetting: propTypes.bool,
|
||||
autoCreateKey: propTypes.bool.def(true),
|
||||
striped: propTypes.bool.def(false),
|
||||
showSummary: propTypes.bool,
|
||||
summaryFunc: {
|
||||
type: [Function, Array] as PropType<(...arg: any[]) => any[]>,
|
||||
default: null,
|
||||
},
|
||||
summaryData: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
default: null,
|
||||
},
|
||||
indentSize: propTypes.number.def(24),
|
||||
canColDrag: propTypes.bool.def(true),
|
||||
api: {
|
||||
type: Function as PropType<(...arg: any[]) => Promise<any>>,
|
||||
default: null,
|
||||
},
|
||||
beforeFetch: {
|
||||
type: Function as PropType<Fn>,
|
||||
default: null,
|
||||
},
|
||||
afterFetch: {
|
||||
type: Function as PropType<Fn>,
|
||||
default: null,
|
||||
},
|
||||
handleSearchInfoFn: {
|
||||
type: Function as PropType<Fn>,
|
||||
default: null,
|
||||
},
|
||||
fetchSetting: {
|
||||
type: Object as PropType<FetchSetting>,
|
||||
default: () => {
|
||||
return FETCH_SETTING;
|
||||
},
|
||||
},
|
||||
// 立即请求接口
|
||||
immediate: propTypes.bool.def(true),
|
||||
emptyDataIsShowTable: propTypes.bool.def(true),
|
||||
// 额外的请求参数
|
||||
searchInfo: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: null,
|
||||
},
|
||||
// 默认的排序参数
|
||||
defSort: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: null,
|
||||
},
|
||||
// 使用搜索表单
|
||||
useSearchForm: propTypes.bool,
|
||||
// 表单配置
|
||||
formConfig: {
|
||||
type: Object as PropType<Partial<FormProps>>,
|
||||
default: null,
|
||||
},
|
||||
columns: {
|
||||
type: [Array] as PropType<BasicColumn[]>,
|
||||
default: () => [],
|
||||
},
|
||||
showIndexColumn: propTypes.bool.def(true),
|
||||
indexColumnProps: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: null,
|
||||
},
|
||||
showActionColumn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
actionColumn: {
|
||||
type: Object as PropType<BasicColumn>,
|
||||
default: null,
|
||||
},
|
||||
ellipsis: propTypes.bool.def(true),
|
||||
canResize: propTypes.bool.def(true),
|
||||
clearSelectOnPageChange: propTypes.bool,
|
||||
resizeHeightOffset: propTypes.number.def(0),
|
||||
rowSelection: {
|
||||
type: Object as PropType<TableRowSelection | null>,
|
||||
default: null,
|
||||
},
|
||||
title: {
|
||||
type: [String, Function] as PropType<string | ((data: Recordable) => string)>,
|
||||
default: null,
|
||||
},
|
||||
titleHelpMessage: {
|
||||
type: [String, Array] as PropType<string | string[]>,
|
||||
},
|
||||
minHeight: propTypes.number,
|
||||
maxHeight: propTypes.number,
|
||||
// 统一设置列最大宽度
|
||||
maxColumnWidth: propTypes.number,
|
||||
dataSource: {
|
||||
type: Array as PropType<Recordable[]>,
|
||||
default: null,
|
||||
},
|
||||
rowKey: {
|
||||
type: [String, Function] as PropType<string | ((record: Recordable) => string)>,
|
||||
default: '',
|
||||
},
|
||||
bordered: propTypes.bool,
|
||||
pagination: {
|
||||
type: [Object, Boolean] as PropType<PaginationProps | boolean>,
|
||||
default: null,
|
||||
},
|
||||
loading: propTypes.bool,
|
||||
rowClassName: {
|
||||
type: Function as PropType<(record: TableCustomRecord<any>, index: number) => string>,
|
||||
},
|
||||
scroll: {
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
type: Object as PropType<{ x?: number | true; y?: number; scrollToFirstRowOnChange?: boolean }>,
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
default: null,
|
||||
},
|
||||
beforeEditSubmit: {
|
||||
type: Function as PropType<(data: { record: Recordable; index: number; key: string | number; value: any }) => Promise<any>>,
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<SizeType>,
|
||||
default: DEFAULT_SIZE,
|
||||
},
|
||||
expandedRowKeys: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
import { VNodeChild } from 'vue';
|
||||
|
||||
export interface ColumnFilterItem {
|
||||
text?: string;
|
||||
value?: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export declare type SortOrder = 'ascend' | 'descend';
|
||||
|
||||
export interface RecordProps<T> {
|
||||
text: any;
|
||||
record: T;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface FilterDropdownProps {
|
||||
prefixCls?: string;
|
||||
setSelectedKeys?: (selectedKeys: string[]) => void;
|
||||
selectedKeys?: string[];
|
||||
confirm?: () => void;
|
||||
clearFilters?: () => void;
|
||||
filters?: ColumnFilterItem[];
|
||||
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
export declare type CustomRenderFunction<T> = (record: RecordProps<T>) => VNodeChild | JSX.Element;
|
||||
|
||||
export interface ColumnProps<T> {
|
||||
/**
|
||||
* specify how content is aligned
|
||||
* @default 'left'
|
||||
* @type string
|
||||
*/
|
||||
align?: 'left' | 'right' | 'center';
|
||||
|
||||
/**
|
||||
* ellipsize cell content, not working with sorter and filters for now.
|
||||
* tableLayout would be fixed when ellipsis is true.
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
ellipsis?: boolean;
|
||||
|
||||
/**
|
||||
* Span of this column's title
|
||||
* @type number
|
||||
*/
|
||||
colSpan?: number;
|
||||
|
||||
/**
|
||||
* Display field of the data record, could be set like a.b.c
|
||||
* @type string
|
||||
*/
|
||||
dataIndex?: string;
|
||||
|
||||
/**
|
||||
* Default filtered values
|
||||
* @type string[]
|
||||
*/
|
||||
defaultFilteredValue?: string[];
|
||||
|
||||
/**
|
||||
* Default order of sorted values: 'ascend' 'descend' null
|
||||
* @type string
|
||||
*/
|
||||
defaultSortOrder?: SortOrder;
|
||||
|
||||
/**
|
||||
* Customized filter overlay
|
||||
* @type any (slot)
|
||||
*/
|
||||
filterDropdown?: VNodeChild | JSX.Element | ((props: FilterDropdownProps) => VNodeChild | JSX.Element);
|
||||
|
||||
/**
|
||||
* Whether filterDropdown is visible
|
||||
* @type boolean
|
||||
*/
|
||||
filterDropdownOpen?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the dataSource is filtered
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
filtered?: boolean;
|
||||
|
||||
/**
|
||||
* Controlled filtered value, filter icon will highlight
|
||||
* @type string[]
|
||||
*/
|
||||
filteredValue?: string[];
|
||||
|
||||
/**
|
||||
* Customized filter icon
|
||||
* @default false
|
||||
* @type any
|
||||
*/
|
||||
filterIcon?: boolean | VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Whether multiple filters can be selected
|
||||
* @default true
|
||||
* @type boolean
|
||||
*/
|
||||
filterMultiple?: boolean;
|
||||
|
||||
/**
|
||||
* Filter menu config
|
||||
* @type object[]
|
||||
*/
|
||||
filters?: ColumnFilterItem[];
|
||||
|
||||
/**
|
||||
* Set column to be fixed: true(same as left) 'left' 'right'
|
||||
* @default false
|
||||
* @type boolean | string
|
||||
*/
|
||||
fixed?: boolean | 'left' | 'right';
|
||||
|
||||
/**
|
||||
* Unique key of this column, you can ignore this prop if you've set a unique dataIndex
|
||||
* @type string
|
||||
*/
|
||||
key?: string;
|
||||
|
||||
/**
|
||||
* Renderer of the table cell. The return value should be a VNode, or an object for colSpan/rowSpan config
|
||||
* @type Function | ScopedSlot
|
||||
*/
|
||||
customRender?: CustomRenderFunction<T> | VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Sort function for local sort, see Array.sort's compareFunction. If you need sort buttons only, set to true
|
||||
* @type boolean | Function
|
||||
*/
|
||||
sorter?: boolean | Function;
|
||||
|
||||
/**
|
||||
* Order of sorted values: 'ascend' 'descend' false
|
||||
* @type boolean | string
|
||||
*/
|
||||
sortOrder?: boolean | SortOrder;
|
||||
|
||||
/**
|
||||
* supported sort way, could be 'ascend', 'descend'
|
||||
* @default ['ascend', 'descend']
|
||||
* @type string[]
|
||||
*/
|
||||
sortDirections?: SortOrder[];
|
||||
|
||||
/**
|
||||
* Title of this column
|
||||
* @type any (string | slot)
|
||||
*/
|
||||
title?: VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Width of this column
|
||||
* @type string | number
|
||||
*/
|
||||
width?: string | number;
|
||||
|
||||
/**
|
||||
* Set props on per cell
|
||||
* @type Function
|
||||
*/
|
||||
customCell?: (record: T, rowIndex: number) => object;
|
||||
|
||||
/**
|
||||
* Set props on per header cell
|
||||
* @type object
|
||||
*/
|
||||
customHeaderCell?: (column: ColumnProps<T>) => object;
|
||||
// update-begin--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
customSummaryRender?: CustomRenderFunction<T> | VNodeChild | JSX.Element;
|
||||
// update-end--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
|
||||
/**
|
||||
* Callback executed when the confirm filter button is clicked, Use as a filter event when using template or jsx
|
||||
* @type Function
|
||||
*/
|
||||
onFilter?: (value: any, record: T) => boolean;
|
||||
|
||||
/**
|
||||
* Callback executed when filterDropdownOpen is changed, Use as a filterDropdownVisible event when using template or jsx
|
||||
* @type Function
|
||||
*/
|
||||
onFilterDropdownVisibleChange?: (visible: boolean) => void;
|
||||
|
||||
/**
|
||||
* When using columns, you can setting this property to configure the properties that support the slot,
|
||||
* such as slots: { filterIcon: 'XXX'}
|
||||
* @type object
|
||||
*/
|
||||
slots?: Recordable<string>;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export type ComponentType = 'Input' | 'InputNumber' | 'Select' | 'ApiSelect' | 'ApiTreeSelect' | 'Checkbox' | 'Switch' | 'DatePicker' | 'TimePicker';
|
||||
@@ -1,99 +0,0 @@
|
||||
import Pagination from 'ant-design-vue/lib/pagination';
|
||||
import { VNodeChild } from 'vue';
|
||||
|
||||
interface PaginationRenderProps {
|
||||
page: number;
|
||||
type: 'page' | 'prev' | 'next';
|
||||
originalElement: any;
|
||||
}
|
||||
|
||||
export declare class PaginationConfig extends Pagination {
|
||||
position?: 'top' | 'bottom' | 'both';
|
||||
}
|
||||
export interface PaginationProps {
|
||||
/**
|
||||
* total number of data items
|
||||
* @default 0
|
||||
* @type number
|
||||
*/
|
||||
total?: number;
|
||||
|
||||
/**
|
||||
* default initial page number
|
||||
* @default 1
|
||||
* @type number
|
||||
*/
|
||||
defaultCurrent?: number;
|
||||
|
||||
/**
|
||||
* current page number
|
||||
* @type number
|
||||
*/
|
||||
current?: number;
|
||||
|
||||
/**
|
||||
* default number of data items per page
|
||||
* @default 10
|
||||
* @type number
|
||||
*/
|
||||
defaultPageSize?: number;
|
||||
|
||||
/**
|
||||
* number of data items per page
|
||||
* @type number
|
||||
*/
|
||||
pageSize?: number;
|
||||
|
||||
/**
|
||||
* Whether to hide pager on single page
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
hideOnSinglePage?: boolean;
|
||||
|
||||
/**
|
||||
* determine whether pageSize can be changed
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
showSizeChanger?: boolean;
|
||||
|
||||
/**
|
||||
* specify the sizeChanger options
|
||||
* @default ['10', '20', '30', '40']
|
||||
* @type string[]
|
||||
*/
|
||||
pageSizeOptions?: string[];
|
||||
|
||||
/**
|
||||
* determine whether you can jump to pages directly
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
showQuickJumper?: boolean | object;
|
||||
|
||||
/**
|
||||
* to display the total number and range
|
||||
* @type Function
|
||||
*/
|
||||
showTotal?: (total: number, range: [number, number]) => any;
|
||||
|
||||
/**
|
||||
* specify the size of Pagination, can be set to small
|
||||
* @default ''
|
||||
* @type string
|
||||
*/
|
||||
size?: string;
|
||||
|
||||
/**
|
||||
* whether to setting simple mode
|
||||
* @type boolean
|
||||
*/
|
||||
simple?: boolean;
|
||||
|
||||
/**
|
||||
* to customize item innerHTML
|
||||
* @type Function
|
||||
*/
|
||||
itemRender?: (props: PaginationRenderProps) => VNodeChild | JSX.Element;
|
||||
}
|
||||
@@ -1,478 +0,0 @@
|
||||
import type { VNodeChild } from 'vue';
|
||||
import type { PaginationProps } from './pagination';
|
||||
import type { FormProps } from '/@/components/Form';
|
||||
import type { TableRowSelection as ITableRowSelection } from 'ant-design-vue/lib/table/interface';
|
||||
import type { ColumnProps } from 'ant-design-vue/lib/table';
|
||||
|
||||
import { ComponentType } from './componentType';
|
||||
import { VueNode } from '/@/utils/propTypes';
|
||||
import { RoleEnum } from '/@/enums/roleEnum';
|
||||
|
||||
export declare type SortOrder = 'ascend' | 'descend';
|
||||
|
||||
export interface TableCurrentDataSource<T = Recordable> {
|
||||
currentDataSource: T[];
|
||||
}
|
||||
|
||||
export interface TableRowSelection<T = any> extends ITableRowSelection {
|
||||
/**
|
||||
* Callback executed when selected rows change
|
||||
* @type Function
|
||||
*/
|
||||
onChange?: (selectedRowKeys: string[] | number[], selectedRows: T[]) => any;
|
||||
|
||||
/**
|
||||
* Callback executed when select/deselect one row
|
||||
* @type Function
|
||||
*/
|
||||
onSelect?: (record: T, selected: boolean, selectedRows: Object[], nativeEvent: Event) => any;
|
||||
|
||||
/**
|
||||
* Callback executed when select/deselect all rows
|
||||
* @type Function
|
||||
*/
|
||||
onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => any;
|
||||
|
||||
/**
|
||||
* Callback executed when row selection is inverted
|
||||
* @type Function
|
||||
*/
|
||||
onSelectInvert?: (selectedRows: string[] | number[]) => any;
|
||||
}
|
||||
|
||||
export interface TableCustomRecord<T> {
|
||||
record?: T;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export interface ExpandedRowRenderRecord<T> extends TableCustomRecord<T> {
|
||||
indent?: number;
|
||||
expanded?: boolean;
|
||||
}
|
||||
|
||||
export interface ColumnFilterItem {
|
||||
text?: string;
|
||||
value?: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export interface TableCustomRecord<T = Recordable> {
|
||||
record?: T;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export interface SorterResult {
|
||||
column: ColumnProps;
|
||||
order: SortOrder;
|
||||
field: string;
|
||||
columnKey: string;
|
||||
}
|
||||
|
||||
export interface FetchParams {
|
||||
searchInfo?: Recordable;
|
||||
page?: number;
|
||||
sortInfo?: Recordable;
|
||||
filterInfo?: Recordable;
|
||||
}
|
||||
|
||||
export interface GetColumnsParams {
|
||||
ignoreIndex?: boolean;
|
||||
ignoreAction?: boolean;
|
||||
sort?: boolean;
|
||||
}
|
||||
|
||||
export type SizeType = 'middle' | 'small' | 'large';
|
||||
|
||||
export interface TableActionType {
|
||||
reload: (opt?: FetchParams) => Promise<void>;
|
||||
getSelectRows: <T = Recordable>() => T[];
|
||||
clearSelectedRowKeys: () => void;
|
||||
expandAll: () => void;
|
||||
collapseAll: () => void;
|
||||
getSelectRowKeys: () => string[];
|
||||
deleteSelectRowByKey: (key: string) => void;
|
||||
setPagination: (info: Partial<PaginationProps>) => void;
|
||||
setTableData: <T = Recordable>(values: T[]) => void;
|
||||
updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void;
|
||||
deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void;
|
||||
insertTableDataRecord: (record: Recordable, index?: number) => Recordable | void;
|
||||
findTableDataRecord: (rowKey: string | number) => Recordable | void;
|
||||
getColumns: (opt?: GetColumnsParams) => BasicColumn[];
|
||||
setColumns: (columns: BasicColumn[] | string[]) => void;
|
||||
getDataSource: <T = Recordable>() => T[];
|
||||
getRawDataSource: <T = Recordable>() => T;
|
||||
setLoading: (loading: boolean) => void;
|
||||
setProps: (props: Partial<BasicTableProps>) => void;
|
||||
redoHeight: () => void;
|
||||
setSelectedRowKeys: (rowKeys: string[] | number[]) => void;
|
||||
getPaginationRef: () => PaginationProps | boolean;
|
||||
getSize: () => SizeType;
|
||||
getRowSelection: () => TableRowSelection<Recordable>;
|
||||
getCacheColumns: () => BasicColumn[];
|
||||
emit?: EmitType;
|
||||
updateTableData: (index: number, key: string, value: any) => Recordable;
|
||||
setShowPagination: (show: boolean) => Promise<void>;
|
||||
getShowPagination: () => boolean;
|
||||
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
|
||||
}
|
||||
|
||||
export interface FetchSetting {
|
||||
// 请求接口当前页数
|
||||
pageField: string;
|
||||
// 每页显示多少条
|
||||
sizeField: string;
|
||||
// 请求结果列表字段 支持 a.b.c
|
||||
listField: string;
|
||||
// 请求结果总数字段 支持 a.b.c
|
||||
totalField: string;
|
||||
}
|
||||
|
||||
export interface TableSetting {
|
||||
// 是否显示刷新按钮
|
||||
redo?: boolean;
|
||||
// 是否显示尺寸调整按钮
|
||||
size?: boolean;
|
||||
// 是否显示字段调整按钮
|
||||
setting?: boolean;
|
||||
// 缓存“字段调整”配置的key,用于页面上有多个表格需要区分的情况
|
||||
cacheKey?: string;
|
||||
// 是否显示全屏按钮
|
||||
fullScreen?: boolean;
|
||||
}
|
||||
|
||||
export interface BasicTableProps<T = any> {
|
||||
// 点击行选中
|
||||
clickToRowSelect?: boolean;
|
||||
isTreeTable?: boolean;
|
||||
// 自定义排序方法
|
||||
sortFn?: (sortInfo: SorterResult) => any;
|
||||
// 排序方法
|
||||
filterFn?: (data: Partial<Recordable<string[]>>) => any;
|
||||
// 取消表格的默认padding
|
||||
inset?: boolean;
|
||||
// 显示表格设置
|
||||
showTableSetting?: boolean;
|
||||
// 表格上方操作按钮设置
|
||||
tableSetting?: TableSetting;
|
||||
// 斑马纹
|
||||
striped?: boolean;
|
||||
// 是否自动生成key
|
||||
autoCreateKey?: boolean;
|
||||
// 计算合计行的方法
|
||||
summaryFunc?: (...arg: any) => Recordable[];
|
||||
// 自定义合计表格内容
|
||||
summaryData?: Recordable[];
|
||||
// 是否显示合计行
|
||||
showSummary?: boolean;
|
||||
// 是否可拖拽列
|
||||
canColDrag?: boolean;
|
||||
// 接口请求对象
|
||||
api?: (...arg: any) => Promise<any>;
|
||||
// 请求之前处理参数
|
||||
beforeFetch?: Fn;
|
||||
// 自定义处理接口返回参数
|
||||
afterFetch?: Fn;
|
||||
// 查询条件请求之前处理
|
||||
handleSearchInfoFn?: Fn;
|
||||
// 请求接口配置
|
||||
fetchSetting?: Partial<FetchSetting>;
|
||||
// 立即请求接口
|
||||
immediate?: boolean;
|
||||
// 在开起搜索表单的时候,如果没有数据是否显示表格
|
||||
emptyDataIsShowTable?: boolean;
|
||||
// 额外的请求参数
|
||||
searchInfo?: Recordable;
|
||||
// 默认的排序参数
|
||||
defSort?: Recordable;
|
||||
// 使用搜索表单
|
||||
useSearchForm?: boolean;
|
||||
// 表单配置
|
||||
formConfig?: Partial<FormProps>;
|
||||
// 列配置
|
||||
columns: BasicColumn[];
|
||||
// 统一设置列最大宽度
|
||||
maxColumnWidth?: number;
|
||||
// 是否显示序号列
|
||||
showIndexColumn?: boolean;
|
||||
// 序号列配置
|
||||
indexColumnProps?: BasicColumn;
|
||||
// 是否显示操作列
|
||||
showActionColumn?: boolean;
|
||||
// 操作列配置
|
||||
actionColumn?: BasicColumn;
|
||||
// 文本超过宽度是否显示。。。
|
||||
ellipsis?: boolean;
|
||||
// 是否可以自适应高度
|
||||
canResize?: boolean;
|
||||
// 自适应高度偏移, 计算结果-偏移量
|
||||
resizeHeightOffset?: number;
|
||||
// 在分页改变的时候清空选项
|
||||
clearSelectOnPageChange?: boolean;
|
||||
//
|
||||
rowKey?: string | ((record: Recordable) => string);
|
||||
// 数据
|
||||
dataSource?: Recordable[];
|
||||
// 标题右侧提示
|
||||
titleHelpMessage?: string | string[];
|
||||
// 表格最小高度
|
||||
minHeight?: number;
|
||||
// 表格滚动最大高度
|
||||
maxHeight?: number;
|
||||
// 是否显示边框
|
||||
bordered?: boolean;
|
||||
// 分页配置
|
||||
pagination?: PaginationProps | boolean;
|
||||
// loading加载
|
||||
loading?: boolean;
|
||||
|
||||
/**
|
||||
* The column contains children to display
|
||||
* @default 'children'
|
||||
* @type string | string[]
|
||||
*/
|
||||
childrenColumnName?: string;
|
||||
|
||||
/**
|
||||
* Override default table elements
|
||||
* @type object
|
||||
*/
|
||||
components?: object;
|
||||
|
||||
/**
|
||||
* Expand all rows initially
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
defaultExpandAllRows?: boolean;
|
||||
|
||||
/**
|
||||
* Initial expanded row keys
|
||||
* @type string[]
|
||||
*/
|
||||
defaultExpandedRowKeys?: string[];
|
||||
|
||||
/**
|
||||
* Current expanded row keys
|
||||
* @type string[]
|
||||
*/
|
||||
expandedRowKeys?: string[];
|
||||
|
||||
/**
|
||||
* Expanded container render for each row
|
||||
* @type Function
|
||||
*/
|
||||
expandedRowRender?: (record?: ExpandedRowRenderRecord<T>) => VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Customize row expand Icon.
|
||||
* @type Function | VNodeChild
|
||||
*/
|
||||
expandIcon?: Function | VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Whether to expand row by clicking anywhere in the whole row
|
||||
* @default false
|
||||
* @type boolean
|
||||
*/
|
||||
expandRowByClick?: boolean;
|
||||
|
||||
/**
|
||||
* The index of `expandIcon` which column will be inserted when `expandIconAsCell` is false. default 0
|
||||
*/
|
||||
expandIconColumnIndex?: number;
|
||||
|
||||
/**
|
||||
* Table footer renderer
|
||||
* @type Function | VNodeChild
|
||||
*/
|
||||
footer?: Function | VNodeChild | JSX.Element;
|
||||
|
||||
/**
|
||||
* Indent size in pixels of tree data
|
||||
* @default 15
|
||||
* @type number
|
||||
*/
|
||||
indentSize?: number;
|
||||
|
||||
/**
|
||||
* i18n text including filter, sort, empty text, etc
|
||||
* @default { filterConfirm: 'Ok', filterReset: 'Reset', emptyText: 'No Data' }
|
||||
* @type object
|
||||
*/
|
||||
locale?: object;
|
||||
|
||||
/**
|
||||
* Row's className
|
||||
* @type Function
|
||||
*/
|
||||
rowClassName?: (record: TableCustomRecord<T>, index: number) => string;
|
||||
|
||||
/**
|
||||
* Row selection config
|
||||
* @type object
|
||||
*/
|
||||
rowSelection?: TableRowSelection;
|
||||
|
||||
/**
|
||||
* Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area.
|
||||
* It is recommended to set a number for x, if you want to set it to true,
|
||||
* you need to add style .ant-table td { white-space: nowrap; }.
|
||||
* @type object
|
||||
*/
|
||||
// update-begin--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
scroll?: { x?: number | true | 'max-content'; y?: number; scrollToFirstRowOnChange?: boolean };
|
||||
// update-end--author:liaozhiyang---date:20240424---for:【issues/1188】BasicTable加上scrollToFirstRowOnChange类型定义
|
||||
|
||||
/**
|
||||
* Whether to show table header
|
||||
* @default true
|
||||
* @type boolean
|
||||
*/
|
||||
showHeader?: boolean;
|
||||
|
||||
/**
|
||||
* Size of table
|
||||
* @default 'default'
|
||||
* @type string
|
||||
*/
|
||||
size?: SizeType;
|
||||
|
||||
/**
|
||||
* Table title renderer
|
||||
* @type Function | ScopedSlot
|
||||
*/
|
||||
title?: VNodeChild | JSX.Element | string | ((data: Recordable) => string);
|
||||
|
||||
/**
|
||||
* Set props on per header row
|
||||
* @type Function
|
||||
*/
|
||||
customHeaderRow?: (column: ColumnProps, index: number) => object;
|
||||
|
||||
/**
|
||||
* Set props on per row
|
||||
* @type Function
|
||||
*/
|
||||
customRow?: (record: T, index: number) => object;
|
||||
|
||||
/**
|
||||
* `table-layout` attribute of table element
|
||||
* `fixed` when header/columns are fixed, or using `column.ellipsis`
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
|
||||
* @version 1.5.0
|
||||
*/
|
||||
tableLayout?: 'auto' | 'fixed' | string;
|
||||
|
||||
/**
|
||||
* the render container of dropdowns in table
|
||||
* @param triggerNode
|
||||
* @version 1.5.0
|
||||
*/
|
||||
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
|
||||
|
||||
/**
|
||||
* Data can be changed again before rendering.
|
||||
* The default configuration of general user empty data.
|
||||
* You can configured globally through [ConfigProvider](https://antdv.com/components/config-provider-cn/)
|
||||
*
|
||||
* @version 1.5.4
|
||||
*/
|
||||
transformCellText?: Function;
|
||||
|
||||
/**
|
||||
* Callback executed before editable cell submit value, not for row-editor
|
||||
*
|
||||
* The cell will not submit data while callback return false
|
||||
*/
|
||||
beforeEditSubmit?: (data: { record: Recordable; index: number; key: string | number; value: any }) => Promise<any>;
|
||||
|
||||
/**
|
||||
* Callback executed when pagination, filters or sorter is changed
|
||||
* @param pagination
|
||||
* @param filters
|
||||
* @param sorter
|
||||
* @param currentDataSource
|
||||
*/
|
||||
onChange?: (pagination: any, filters: any, sorter: any, extra: any) => void;
|
||||
|
||||
/**
|
||||
* Callback executed when the row expand icon is clicked
|
||||
*
|
||||
* @param expanded
|
||||
* @param record
|
||||
*/
|
||||
onExpand?: (expande: boolean, record: T) => void;
|
||||
|
||||
/**
|
||||
* Callback executed when the expanded rows change
|
||||
* @param expandedRows
|
||||
*/
|
||||
onExpandedRowsChange?: (expandedRows: string[] | number[]) => void;
|
||||
|
||||
onColumnsChange?: (data: ColumnChangeParam[]) => void;
|
||||
}
|
||||
|
||||
export type CellFormat = string | ((text: string, record: Recordable, index: number) => string | number) | Map<string | number, any>;
|
||||
|
||||
// @ts-ignore
|
||||
export interface BasicColumn extends ColumnProps<Recordable> {
|
||||
children?: BasicColumn[];
|
||||
filters?: {
|
||||
text: string;
|
||||
value: string;
|
||||
children?: unknown[] | (((props: Record<string, unknown>) => unknown[]) & (() => unknown[]) & (() => unknown[]));
|
||||
}[];
|
||||
|
||||
//
|
||||
flag?: 'INDEX' | 'DEFAULT' | 'CHECKBOX' | 'RADIO' | 'ACTION';
|
||||
customTitle?: VueNode;
|
||||
|
||||
slots?: Recordable;
|
||||
// slots的备份,兼容老的写法,转成新写法避免控制台警告
|
||||
slotsBak?: Recordable;
|
||||
|
||||
// Whether to hide the column by default, it can be displayed in the column configuration
|
||||
defaultHidden?: boolean;
|
||||
|
||||
// Help text for table column header
|
||||
helpMessage?: string | string[];
|
||||
|
||||
format?: CellFormat;
|
||||
|
||||
// Editable
|
||||
edit?: boolean;
|
||||
editRow?: boolean;
|
||||
editable?: boolean;
|
||||
editComponent?: ComponentType;
|
||||
editComponentProps?: Recordable;
|
||||
editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
|
||||
editValueMap?: (value: any) => string;
|
||||
onEditRow?: () => void;
|
||||
// 权限编码控制是否显示
|
||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||
// 业务控制是否显示
|
||||
ifShow?: boolean | ((column: BasicColumn) => boolean);
|
||||
//compType-用于记录类型
|
||||
compType?: string;
|
||||
// update-begin--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
customSummaryRender?: (opt: {
|
||||
value: any;
|
||||
text: any;
|
||||
record: Recordable;
|
||||
index: number;
|
||||
renderIndex?: number;
|
||||
column: BasicColumn;
|
||||
}) => any | VNodeChild | JSX.Element;
|
||||
// update-end--author:liaozhiyang---date:20240425---for:【pull/1201】添加antd的TableSummary功能兼容老的summary(表尾合计)
|
||||
}
|
||||
|
||||
export type ColumnChangeParam = {
|
||||
dataIndex: string;
|
||||
fixed: boolean | 'left' | 'right' | undefined;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
export interface InnerHandlers {
|
||||
onColumnsChange: (data: ColumnChangeParam[]) => void;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||
import { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip';
|
||||
import { RoleEnum } from '/@/enums/roleEnum';
|
||||
export interface ActionItem extends ButtonProps {
|
||||
onClick?: Fn;
|
||||
label?: string;
|
||||
color?: 'success' | 'error' | 'warning';
|
||||
icon?: string;
|
||||
popConfirm?: PopConfirm;
|
||||
disabled?: boolean;
|
||||
divider?: boolean;
|
||||
// 权限编码控制是否显示
|
||||
auth?: RoleEnum | RoleEnum[] | string | string[];
|
||||
// 业务控制是否显示
|
||||
ifShow?: boolean | ((action: ActionItem) => boolean);
|
||||
tooltip?: string | TooltipProps;
|
||||
// 自定义类名
|
||||
class?: string | Record<string, boolean> | any[];
|
||||
// 自定义图标颜色
|
||||
iconColor?: string;
|
||||
}
|
||||
|
||||
export interface PopConfirm {
|
||||
title: string;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
confirm: Fn;
|
||||
cancel?: Fn;
|
||||
icon?: string;
|
||||
placement?: string;
|
||||
overlayClassName?: string;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<template>
|
||||
<a-modal :bodyStyle="{ padding: '24px'}" :visible="iconOpen" :width="800" @ok="iconHandleOk(iconChecked)" @cancel="closeOpenIcon" title="选择图标">
|
||||
<a-input
|
||||
v-model:value="searchValue"
|
||||
placeholder="请输入英文关键词进行搜索"
|
||||
@change="filterIcon"
|
||||
/>
|
||||
<div class="icon-box">
|
||||
<div
|
||||
v-for="(item,index) in iconArr"
|
||||
:key="index"
|
||||
@click="sendData(item)"
|
||||
class="icon-content"
|
||||
:style="{ background: iconChecked === item ? '#1890ff' : ''}"
|
||||
>
|
||||
<component :is="$icons[item]" />
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch,defineProps} from 'vue';
|
||||
import { NsMessage } from '/nerv-lib/saas';
|
||||
import icons from './icons.json';
|
||||
const props = defineProps(['iconHandleOk']);
|
||||
const iconArr = ref<string[]>(icons);
|
||||
const searchValue = ref('');
|
||||
const iconOpen = ref<boolean>(false);
|
||||
const iconChecked =ref('');//选中数据
|
||||
/**
|
||||
* 进行搜索过滤
|
||||
*/
|
||||
const filterIcon = () => {
|
||||
if (searchValue.value){
|
||||
iconArr.value = icons.filter(item => item.toLowerCase().includes(searchValue.value.toLowerCase()) )
|
||||
}else{
|
||||
iconArr.value = icons;
|
||||
}
|
||||
}
|
||||
watch(iconOpen,()=>{
|
||||
searchValue.value = ''
|
||||
iconArr.value = icons;
|
||||
})
|
||||
const sendData = (data:any) => {
|
||||
iconChecked.value = data;
|
||||
}
|
||||
const iconHandleOk = (e: MouseEvent) => {
|
||||
if(!iconChecked.value){
|
||||
NsMessage.error('请选择图标');
|
||||
return;
|
||||
}else{
|
||||
props.iconHandleOk(iconChecked.value);//调用父组件传递来的函数
|
||||
iconOpen.value = false;
|
||||
iconChecked.value = '';
|
||||
}
|
||||
};
|
||||
// 关闭图标选择弹窗
|
||||
const closeOpenIcon = () => {
|
||||
iconOpen.value = false;
|
||||
iconChecked.value = '';
|
||||
};
|
||||
// 暴露给父组件
|
||||
const isIconOpenToggle = (data:any)=>{
|
||||
if(data){
|
||||
iconChecked.value = data;//记住上一次选择的数据
|
||||
}
|
||||
iconOpen.value = true;
|
||||
}
|
||||
const isIconData = ()=>{
|
||||
if(!iconChecked.value){
|
||||
NsMessage.warn('请先选择图标');
|
||||
iconOpen.value = true;
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
isIconOpenToggle,
|
||||
isIconData
|
||||
})
|
||||
|
||||
</script>
|
||||
<style lang="less">
|
||||
.icon-box{
|
||||
overflow: auto;
|
||||
font-size: 20px;
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
padding-top:10px;
|
||||
}
|
||||
|
||||
.icon-content{
|
||||
width: 45px;
|
||||
height: 40px;
|
||||
margin: 6px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ccc;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.icon-content:hover{
|
||||
background: rgba(26, 144, 255,.3);
|
||||
}
|
||||
</style>
|
||||
@@ -1,790 +0,0 @@
|
||||
[
|
||||
"AccountBookFilled",
|
||||
"AccountBookOutlined",
|
||||
"AccountBookTwoTone",
|
||||
"AimOutlined",
|
||||
"AlertFilled",
|
||||
"AlertOutlined",
|
||||
"AlertTwoTone",
|
||||
"AlibabaOutlined",
|
||||
"AlignCenterOutlined",
|
||||
"AlignLeftOutlined",
|
||||
"AlignRightOutlined",
|
||||
"AlipayCircleFilled",
|
||||
"AlipayCircleOutlined",
|
||||
"AlipayOutlined",
|
||||
"AlipaySquareFilled",
|
||||
"AliwangwangFilled",
|
||||
"AliwangwangOutlined",
|
||||
"AliyunOutlined",
|
||||
"AmazonCircleFilled",
|
||||
"AmazonOutlined",
|
||||
"AmazonSquareFilled",
|
||||
"AndroidFilled",
|
||||
"AndroidOutlined",
|
||||
"AntCloudOutlined",
|
||||
"AntDesignOutlined",
|
||||
"ApartmentOutlined",
|
||||
"ApiFilled",
|
||||
"ApiOutlined",
|
||||
"ApiTwoTone",
|
||||
"AppleFilled",
|
||||
"AppleOutlined",
|
||||
"AppstoreAddOutlined",
|
||||
"AppstoreFilled",
|
||||
"AppstoreOutlined",
|
||||
"AppstoreTwoTone",
|
||||
"AreaChartOutlined",
|
||||
"ArrowDownOutlined",
|
||||
"ArrowLeftOutlined",
|
||||
"ArrowRightOutlined",
|
||||
"ArrowUpOutlined",
|
||||
"ArrowsAltOutlined",
|
||||
"AudioFilled",
|
||||
"AudioMutedOutlined",
|
||||
"AudioOutlined",
|
||||
"AudioTwoTone",
|
||||
"AuditOutlined",
|
||||
"BackwardFilled",
|
||||
"BackwardOutlined",
|
||||
"BankFilled",
|
||||
"BankOutlined",
|
||||
"BankTwoTone",
|
||||
"BarChartOutlined",
|
||||
"BarcodeOutlined",
|
||||
"BarsOutlined",
|
||||
"BehanceCircleFilled",
|
||||
"BehanceOutlined",
|
||||
"BehanceSquareFilled",
|
||||
"BehanceSquareOutlined",
|
||||
"BellFilled",
|
||||
"BellOutlined",
|
||||
"BellTwoTone",
|
||||
"BgColorsOutlined",
|
||||
"BlockOutlined",
|
||||
"BoldOutlined",
|
||||
"BookFilled",
|
||||
"BookOutlined",
|
||||
"BookTwoTone",
|
||||
"BorderBottomOutlined",
|
||||
"BorderHorizontalOutlined",
|
||||
"BorderInnerOutlined",
|
||||
"BorderLeftOutlined",
|
||||
"BorderOuterOutlined",
|
||||
"BorderOutlined",
|
||||
"BorderRightOutlined",
|
||||
"BorderTopOutlined",
|
||||
"BorderVerticleOutlined",
|
||||
"BorderlessTableOutlined",
|
||||
"BoxPlotFilled",
|
||||
"BoxPlotOutlined",
|
||||
"BoxPlotTwoTone",
|
||||
"BranchesOutlined",
|
||||
"BugFilled",
|
||||
"BugOutlined",
|
||||
"BugTwoTone",
|
||||
"BuildFilled",
|
||||
"BuildOutlined",
|
||||
"BuildTwoTone",
|
||||
"BulbFilled",
|
||||
"BulbOutlined",
|
||||
"BulbTwoTone",
|
||||
"CalculatorFilled",
|
||||
"CalculatorOutlined",
|
||||
"CalculatorTwoTone",
|
||||
"CalendarFilled",
|
||||
"CalendarOutlined",
|
||||
"CalendarTwoTone",
|
||||
"CameraFilled",
|
||||
"CameraOutlined",
|
||||
"CameraTwoTone",
|
||||
"CarFilled",
|
||||
"CarOutlined",
|
||||
"CarTwoTone",
|
||||
"CaretDownFilled",
|
||||
"CaretDownOutlined",
|
||||
"CaretLeftFilled",
|
||||
"CaretLeftOutlined",
|
||||
"CaretRightFilled",
|
||||
"CaretRightOutlined",
|
||||
"CaretUpFilled",
|
||||
"CaretUpOutlined",
|
||||
"CarryOutFilled",
|
||||
"CarryOutOutlined",
|
||||
"CarryOutTwoTone",
|
||||
"CheckCircleFilled",
|
||||
"CheckCircleOutlined",
|
||||
"CheckCircleTwoTone",
|
||||
"CheckOutlined",
|
||||
"CheckSquareFilled",
|
||||
"CheckSquareOutlined",
|
||||
"CheckSquareTwoTone",
|
||||
"ChromeFilled",
|
||||
"ChromeOutlined",
|
||||
"CiCircleFilled",
|
||||
"CiCircleOutlined",
|
||||
"CiCircleTwoTone",
|
||||
"CiOutlined",
|
||||
"CiTwoTone",
|
||||
"ClearOutlined",
|
||||
"ClockCircleFilled",
|
||||
"ClockCircleOutlined",
|
||||
"ClockCircleTwoTone",
|
||||
"CloseCircleFilled",
|
||||
"CloseCircleOutlined",
|
||||
"CloseCircleTwoTone",
|
||||
"CloseOutlined",
|
||||
"CloseSquareFilled",
|
||||
"CloseSquareOutlined",
|
||||
"CloseSquareTwoTone",
|
||||
"CloudDownloadOutlined",
|
||||
"CloudFilled",
|
||||
"CloudOutlined",
|
||||
"CloudServerOutlined",
|
||||
"CloudSyncOutlined",
|
||||
"CloudTwoTone",
|
||||
"CloudUploadOutlined",
|
||||
"ClusterOutlined",
|
||||
"CodeFilled",
|
||||
"CodeOutlined",
|
||||
"CodeSandboxCircleFilled",
|
||||
"CodeSandboxOutlined",
|
||||
"CodeSandboxSquareFilled",
|
||||
"CodeTwoTone",
|
||||
"CodepenCircleFilled",
|
||||
"CodepenCircleOutlined",
|
||||
"CodepenOutlined",
|
||||
"CodepenSquareFilled",
|
||||
"CoffeeOutlined",
|
||||
"ColumnHeightOutlined",
|
||||
"ColumnWidthOutlined",
|
||||
"CommentOutlined",
|
||||
"CompassFilled",
|
||||
"CompassOutlined",
|
||||
"CompassTwoTone",
|
||||
"CompressOutlined",
|
||||
"ConsoleSqlOutlined",
|
||||
"ContactsFilled",
|
||||
"ContactsOutlined",
|
||||
"ContactsTwoTone",
|
||||
"ContainerFilled",
|
||||
"ContainerOutlined",
|
||||
"ContainerTwoTone",
|
||||
"ControlFilled",
|
||||
"ControlOutlined",
|
||||
"ControlTwoTone",
|
||||
"CopyFilled",
|
||||
"CopyOutlined",
|
||||
"CopyTwoTone",
|
||||
"CopyrightCircleFilled",
|
||||
"CopyrightCircleOutlined",
|
||||
"CopyrightCircleTwoTone",
|
||||
"CopyrightOutlined",
|
||||
"CopyrightTwoTone",
|
||||
"CreditCardFilled",
|
||||
"CreditCardOutlined",
|
||||
"CreditCardTwoTone",
|
||||
"CrownFilled",
|
||||
"CrownOutlined",
|
||||
"CrownTwoTone",
|
||||
"CustomerServiceFilled",
|
||||
"CustomerServiceOutlined",
|
||||
"CustomerServiceTwoTone",
|
||||
"DashOutlined",
|
||||
"DashboardFilled",
|
||||
"DashboardOutlined",
|
||||
"DashboardTwoTone",
|
||||
"DatabaseFilled",
|
||||
"DatabaseOutlined",
|
||||
"DatabaseTwoTone",
|
||||
"DeleteColumnOutlined",
|
||||
"DeleteFilled",
|
||||
"DeleteOutlined",
|
||||
"DeleteRowOutlined",
|
||||
"DeleteTwoTone",
|
||||
"DeliveredProcedureOutlined",
|
||||
"DeploymentUnitOutlined",
|
||||
"DesktopOutlined",
|
||||
"DiffFilled",
|
||||
"DiffOutlined",
|
||||
"DiffTwoTone",
|
||||
"DingdingOutlined",
|
||||
"DingtalkCircleFilled",
|
||||
"DingtalkOutlined",
|
||||
"DingtalkSquareFilled",
|
||||
"DisconnectOutlined",
|
||||
"DislikeFilled",
|
||||
"DislikeOutlined",
|
||||
"DislikeTwoTone",
|
||||
"DollarCircleFilled",
|
||||
"DollarCircleOutlined",
|
||||
"DollarCircleTwoTone",
|
||||
"DollarOutlined",
|
||||
"DollarTwoTone",
|
||||
"DotChartOutlined",
|
||||
"DoubleLeftOutlined",
|
||||
"DoubleRightOutlined",
|
||||
"DownCircleFilled",
|
||||
"DownCircleOutlined",
|
||||
"DownCircleTwoTone",
|
||||
"DownOutlined",
|
||||
"DownSquareFilled",
|
||||
"DownSquareOutlined",
|
||||
"DownSquareTwoTone",
|
||||
"DownloadOutlined",
|
||||
"DragOutlined",
|
||||
"DribbbleCircleFilled",
|
||||
"DribbbleOutlined",
|
||||
"DribbbleSquareFilled",
|
||||
"DribbbleSquareOutlined",
|
||||
"DropboxCircleFilled",
|
||||
"DropboxOutlined",
|
||||
"DropboxSquareFilled",
|
||||
"EditFilled",
|
||||
"EditOutlined",
|
||||
"EditTwoTone",
|
||||
"EllipsisOutlined",
|
||||
"EnterOutlined",
|
||||
"EnvironmentFilled",
|
||||
"EnvironmentOutlined",
|
||||
"EnvironmentTwoTone",
|
||||
"EuroCircleFilled",
|
||||
"EuroCircleOutlined",
|
||||
"EuroCircleTwoTone",
|
||||
"EuroOutlined",
|
||||
"EuroTwoTone",
|
||||
"ExceptionOutlined",
|
||||
"ExclamationCircleFilled",
|
||||
"ExclamationCircleOutlined",
|
||||
"ExclamationCircleTwoTone",
|
||||
"ExclamationOutlined",
|
||||
"ExpandAltOutlined",
|
||||
"ExpandOutlined",
|
||||
"ExperimentFilled",
|
||||
"ExperimentOutlined",
|
||||
"ExperimentTwoTone",
|
||||
"ExportOutlined",
|
||||
"EyeFilled",
|
||||
"EyeInvisibleFilled",
|
||||
"EyeInvisibleOutlined",
|
||||
"EyeInvisibleTwoTone",
|
||||
"EyeOutlined",
|
||||
"EyeTwoTone",
|
||||
"FacebookFilled",
|
||||
"FacebookOutlined",
|
||||
"FallOutlined",
|
||||
"FastBackwardFilled",
|
||||
"FastBackwardOutlined",
|
||||
"FastForwardFilled",
|
||||
"FastForwardOutlined",
|
||||
"FieldBinaryOutlined",
|
||||
"FieldNumberOutlined",
|
||||
"FieldStringOutlined",
|
||||
"FieldTimeOutlined",
|
||||
"FileAddFilled",
|
||||
"FileAddOutlined",
|
||||
"FileAddTwoTone",
|
||||
"FileDoneOutlined",
|
||||
"FileExcelFilled",
|
||||
"FileExcelOutlined",
|
||||
"FileExcelTwoTone",
|
||||
"FileExclamationFilled",
|
||||
"FileExclamationOutlined",
|
||||
"FileExclamationTwoTone",
|
||||
"FileFilled",
|
||||
"FileGifOutlined",
|
||||
"FileImageFilled",
|
||||
"FileImageOutlined",
|
||||
"FileImageTwoTone",
|
||||
"FileJpgOutlined",
|
||||
"FileMarkdownFilled",
|
||||
"FileMarkdownOutlined",
|
||||
"FileMarkdownTwoTone",
|
||||
"FileOutlined",
|
||||
"FilePdfFilled",
|
||||
"FilePdfOutlined",
|
||||
"FilePdfTwoTone",
|
||||
"FilePptFilled",
|
||||
"FilePptOutlined",
|
||||
"FilePptTwoTone",
|
||||
"FileProtectOutlined",
|
||||
"FileSearchOutlined",
|
||||
"FileSyncOutlined",
|
||||
"FileTextFilled",
|
||||
"FileTextOutlined",
|
||||
"FileTextTwoTone",
|
||||
"FileTwoTone",
|
||||
"FileUnknownFilled",
|
||||
"FileUnknownOutlined",
|
||||
"FileUnknownTwoTone",
|
||||
"FileWordFilled",
|
||||
"FileWordOutlined",
|
||||
"FileWordTwoTone",
|
||||
"FileZipFilled",
|
||||
"FileZipOutlined",
|
||||
"FileZipTwoTone",
|
||||
"FilterFilled",
|
||||
"FilterOutlined",
|
||||
"FilterTwoTone",
|
||||
"FireFilled",
|
||||
"FireOutlined",
|
||||
"FireTwoTone",
|
||||
"FlagFilled",
|
||||
"FlagOutlined",
|
||||
"FlagTwoTone",
|
||||
"FolderAddFilled",
|
||||
"FolderAddOutlined",
|
||||
"FolderAddTwoTone",
|
||||
"FolderFilled",
|
||||
"FolderOpenFilled",
|
||||
"FolderOpenOutlined",
|
||||
"FolderOpenTwoTone",
|
||||
"FolderOutlined",
|
||||
"FolderTwoTone",
|
||||
"FolderViewOutlined",
|
||||
"FontColorsOutlined",
|
||||
"FontSizeOutlined",
|
||||
"ForkOutlined",
|
||||
"FormOutlined",
|
||||
"FormatPainterFilled",
|
||||
"FormatPainterOutlined",
|
||||
"ForwardFilled",
|
||||
"ForwardOutlined",
|
||||
"FrownFilled",
|
||||
"FrownOutlined",
|
||||
"FrownTwoTone",
|
||||
"FullscreenExitOutlined",
|
||||
"FullscreenOutlined",
|
||||
"FunctionOutlined",
|
||||
"FundFilled",
|
||||
"FundOutlined",
|
||||
"FundProjectionScreenOutlined",
|
||||
"FundTwoTone",
|
||||
"FundViewOutlined",
|
||||
"FunnelPlotFilled",
|
||||
"FunnelPlotOutlined",
|
||||
"FunnelPlotTwoTone",
|
||||
"GatewayOutlined",
|
||||
"GifOutlined",
|
||||
"GiftFilled",
|
||||
"GiftOutlined",
|
||||
"GiftTwoTone",
|
||||
"GithubFilled",
|
||||
"GithubOutlined",
|
||||
"GitlabFilled",
|
||||
"GitlabOutlined",
|
||||
"GlobalOutlined",
|
||||
"GoldFilled",
|
||||
"GoldOutlined",
|
||||
"GoldTwoTone",
|
||||
"GoldenFilled",
|
||||
"GoogleCircleFilled",
|
||||
"GoogleOutlined",
|
||||
"GooglePlusCircleFilled",
|
||||
"GooglePlusOutlined",
|
||||
"GooglePlusSquareFilled",
|
||||
"GoogleSquareFilled",
|
||||
"GroupOutlined",
|
||||
"HddFilled",
|
||||
"HddOutlined",
|
||||
"HddTwoTone",
|
||||
"HeartFilled",
|
||||
"HeartOutlined",
|
||||
"HeartTwoTone",
|
||||
"HeatMapOutlined",
|
||||
"HighlightFilled",
|
||||
"HighlightOutlined",
|
||||
"HighlightTwoTone",
|
||||
"HistoryOutlined",
|
||||
"HomeFilled",
|
||||
"HomeOutlined",
|
||||
"HomeTwoTone",
|
||||
"HourglassFilled",
|
||||
"HourglassOutlined",
|
||||
"HourglassTwoTone",
|
||||
"Html5Filled",
|
||||
"Html5Outlined",
|
||||
"Html5TwoTone",
|
||||
"IdcardFilled",
|
||||
"IdcardOutlined",
|
||||
"IdcardTwoTone",
|
||||
"IeCircleFilled",
|
||||
"IeOutlined",
|
||||
"IeSquareFilled",
|
||||
"ImportOutlined",
|
||||
"InboxOutlined",
|
||||
"InfoCircleFilled",
|
||||
"InfoCircleOutlined",
|
||||
"InfoCircleTwoTone",
|
||||
"InfoOutlined",
|
||||
"InsertRowAboveOutlined",
|
||||
"InsertRowBelowOutlined",
|
||||
"InsertRowLeftOutlined",
|
||||
"InsertRowRightOutlined",
|
||||
"InstagramFilled",
|
||||
"InstagramOutlined",
|
||||
"InsuranceFilled",
|
||||
"InsuranceOutlined",
|
||||
"InsuranceTwoTone",
|
||||
"InteractionFilled",
|
||||
"InteractionOutlined",
|
||||
"InteractionTwoTone",
|
||||
"IssuesCloseOutlined",
|
||||
"ItalicOutlined",
|
||||
"KeyOutlined",
|
||||
"LaptopOutlined",
|
||||
"LayoutFilled",
|
||||
"LayoutOutlined",
|
||||
"LayoutTwoTone",
|
||||
"LeftCircleFilled",
|
||||
"LeftCircleOutlined",
|
||||
"LeftCircleTwoTone",
|
||||
"LeftOutlined",
|
||||
"LeftSquareFilled",
|
||||
"LeftSquareOutlined",
|
||||
"LeftSquareTwoTone",
|
||||
"LikeFilled",
|
||||
"LikeOutlined",
|
||||
"LikeTwoTone",
|
||||
"LineChartOutlined",
|
||||
"LineHeightOutlined",
|
||||
"LineOutlined",
|
||||
"LinkOutlined",
|
||||
"LinkedinFilled",
|
||||
"LinkedinOutlined",
|
||||
"Loading3QuartersOutlined",
|
||||
"LoadingOutlined",
|
||||
"LockFilled",
|
||||
"LockOutlined",
|
||||
"LockTwoTone",
|
||||
"LoginOutlined",
|
||||
"LogoutOutlined",
|
||||
"MacCommandFilled",
|
||||
"MacCommandOutlined",
|
||||
"MailFilled",
|
||||
"MailOutlined",
|
||||
"MailTwoTone",
|
||||
"ManOutlined",
|
||||
"MedicineBoxFilled",
|
||||
"MedicineBoxOutlined",
|
||||
"MedicineBoxTwoTone",
|
||||
"MediumCircleFilled",
|
||||
"MediumOutlined",
|
||||
"MediumSquareFilled",
|
||||
"MediumWorkmarkOutlined",
|
||||
"MehFilled",
|
||||
"MehOutlined",
|
||||
"MehTwoTone",
|
||||
"MenuFoldOutlined",
|
||||
"MenuOutlined",
|
||||
"MenuUnfoldOutlined",
|
||||
"MergeCellsOutlined",
|
||||
"MessageFilled",
|
||||
"MessageOutlined",
|
||||
"MessageTwoTone",
|
||||
"MinusCircleFilled",
|
||||
"MinusCircleOutlined",
|
||||
"MinusCircleTwoTone",
|
||||
"MinusOutlined",
|
||||
"MinusSquareFilled",
|
||||
"MinusSquareOutlined",
|
||||
"MinusSquareTwoTone",
|
||||
"MobileFilled",
|
||||
"MobileOutlined",
|
||||
"MobileTwoTone",
|
||||
"MoneyCollectFilled",
|
||||
"MoneyCollectOutlined",
|
||||
"MoneyCollectTwoTone",
|
||||
"MonitorOutlined",
|
||||
"MoreOutlined",
|
||||
"NodeCollapseOutlined",
|
||||
"NodeExpandOutlined",
|
||||
"NodeIndexOutlined",
|
||||
"NotificationFilled",
|
||||
"NotificationOutlined",
|
||||
"NotificationTwoTone",
|
||||
"NumberOutlined",
|
||||
"OneToOneOutlined",
|
||||
"OrderedListOutlined",
|
||||
"PaperClipOutlined",
|
||||
"PartitionOutlined",
|
||||
"PauseCircleFilled",
|
||||
"PauseCircleOutlined",
|
||||
"PauseCircleTwoTone",
|
||||
"PauseOutlined",
|
||||
"PayCircleFilled",
|
||||
"PayCircleOutlined",
|
||||
"PercentageOutlined",
|
||||
"PhoneFilled",
|
||||
"PhoneOutlined",
|
||||
"PhoneTwoTone",
|
||||
"PicCenterOutlined",
|
||||
"PicLeftOutlined",
|
||||
"PicRightOutlined",
|
||||
"PictureFilled",
|
||||
"PictureOutlined",
|
||||
"PictureTwoTone",
|
||||
"PieChartFilled",
|
||||
"PieChartOutlined",
|
||||
"PieChartTwoTone",
|
||||
"PlayCircleFilled",
|
||||
"PlayCircleOutlined",
|
||||
"PlayCircleTwoTone",
|
||||
"PlaySquareFilled",
|
||||
"PlaySquareOutlined",
|
||||
"PlaySquareTwoTone",
|
||||
"PlusCircleFilled",
|
||||
"PlusCircleOutlined",
|
||||
"PlusCircleTwoTone",
|
||||
"PlusOutlined",
|
||||
"PlusSquareFilled",
|
||||
"PlusSquareOutlined",
|
||||
"PlusSquareTwoTone",
|
||||
"PoundCircleFilled",
|
||||
"PoundCircleOutlined",
|
||||
"PoundCircleTwoTone",
|
||||
"PoundOutlined",
|
||||
"PoweroffOutlined",
|
||||
"PrinterFilled",
|
||||
"PrinterOutlined",
|
||||
"PrinterTwoTone",
|
||||
"ProfileFilled",
|
||||
"ProfileOutlined",
|
||||
"ProfileTwoTone",
|
||||
"ProjectFilled",
|
||||
"ProjectOutlined",
|
||||
"ProjectTwoTone",
|
||||
"PropertySafetyFilled",
|
||||
"PropertySafetyOutlined",
|
||||
"PropertySafetyTwoTone",
|
||||
"PullRequestOutlined",
|
||||
"PushpinFilled",
|
||||
"PushpinOutlined",
|
||||
"PushpinTwoTone",
|
||||
"QqCircleFilled",
|
||||
"QqOutlined",
|
||||
"QqSquareFilled",
|
||||
"QrcodeOutlined",
|
||||
"QuestionCircleFilled",
|
||||
"QuestionCircleOutlined",
|
||||
"QuestionCircleTwoTone",
|
||||
"QuestionOutlined",
|
||||
"RadarChartOutlined",
|
||||
"RadiusBottomleftOutlined",
|
||||
"RadiusBottomrightOutlined",
|
||||
"RadiusSettingOutlined",
|
||||
"RadiusUpleftOutlined",
|
||||
"RadiusUprightOutlined",
|
||||
"ReadFilled",
|
||||
"ReadOutlined",
|
||||
"ReconciliationFilled",
|
||||
"ReconciliationOutlined",
|
||||
"ReconciliationTwoTone",
|
||||
"RedEnvelopeFilled",
|
||||
"RedEnvelopeOutlined",
|
||||
"RedEnvelopeTwoTone",
|
||||
"RedditCircleFilled",
|
||||
"RedditOutlined",
|
||||
"RedditSquareFilled",
|
||||
"RedoOutlined",
|
||||
"ReloadOutlined",
|
||||
"RestFilled",
|
||||
"RestOutlined",
|
||||
"RestTwoTone",
|
||||
"RetweetOutlined",
|
||||
"RightCircleFilled",
|
||||
"RightCircleOutlined",
|
||||
"RightCircleTwoTone",
|
||||
"RightOutlined",
|
||||
"RightSquareFilled",
|
||||
"RightSquareOutlined",
|
||||
"RightSquareTwoTone",
|
||||
"RiseOutlined",
|
||||
"RobotFilled",
|
||||
"RobotOutlined",
|
||||
"RocketFilled",
|
||||
"RocketOutlined",
|
||||
"RocketTwoTone",
|
||||
"RollbackOutlined",
|
||||
"RotateLeftOutlined",
|
||||
"RotateRightOutlined",
|
||||
"SafetyCertificateFilled",
|
||||
"SafetyCertificateOutlined",
|
||||
"SafetyCertificateTwoTone",
|
||||
"SafetyOutlined",
|
||||
"SaveFilled",
|
||||
"SaveOutlined",
|
||||
"SaveTwoTone",
|
||||
"ScanOutlined",
|
||||
"ScheduleFilled",
|
||||
"ScheduleOutlined",
|
||||
"ScheduleTwoTone",
|
||||
"ScissorOutlined",
|
||||
"SearchOutlined",
|
||||
"SecurityScanFilled",
|
||||
"SecurityScanOutlined",
|
||||
"SecurityScanTwoTone",
|
||||
"SelectOutlined",
|
||||
"SendOutlined",
|
||||
"SettingFilled",
|
||||
"SettingOutlined",
|
||||
"SettingTwoTone",
|
||||
"ShakeOutlined",
|
||||
"ShareAltOutlined",
|
||||
"ShopFilled",
|
||||
"ShopOutlined",
|
||||
"ShopTwoTone",
|
||||
"ShoppingCartOutlined",
|
||||
"ShoppingFilled",
|
||||
"ShoppingOutlined",
|
||||
"ShoppingTwoTone",
|
||||
"ShrinkOutlined",
|
||||
"SignalFilled",
|
||||
"SisternodeOutlined",
|
||||
"SketchCircleFilled",
|
||||
"SketchOutlined",
|
||||
"SketchSquareFilled",
|
||||
"SkinFilled",
|
||||
"SkinOutlined",
|
||||
"SkinTwoTone",
|
||||
"SkypeFilled",
|
||||
"SkypeOutlined",
|
||||
"SlackCircleFilled",
|
||||
"SlackOutlined",
|
||||
"SlackSquareFilled",
|
||||
"SlackSquareOutlined",
|
||||
"SlidersFilled",
|
||||
"SlidersOutlined",
|
||||
"SlidersTwoTone",
|
||||
"SmallDashOutlined",
|
||||
"SmileFilled",
|
||||
"SmileOutlined",
|
||||
"SmileTwoTone",
|
||||
"SnippetsFilled",
|
||||
"SnippetsOutlined",
|
||||
"SnippetsTwoTone",
|
||||
"SolutionOutlined",
|
||||
"SortAscendingOutlined",
|
||||
"SortDescendingOutlined",
|
||||
"SoundFilled",
|
||||
"SoundOutlined",
|
||||
"SoundTwoTone",
|
||||
"SplitCellsOutlined",
|
||||
"StarFilled",
|
||||
"StarOutlined",
|
||||
"StarTwoTone",
|
||||
"StepBackwardFilled",
|
||||
"StepBackwardOutlined",
|
||||
"StepForwardFilled",
|
||||
"StepForwardOutlined",
|
||||
"StockOutlined",
|
||||
"StopFilled",
|
||||
"StopOutlined",
|
||||
"StopTwoTone",
|
||||
"StrikethroughOutlined",
|
||||
"SubnodeOutlined",
|
||||
"SwapLeftOutlined",
|
||||
"SwapOutlined",
|
||||
"SwapRightOutlined",
|
||||
"SwitcherFilled",
|
||||
"SwitcherOutlined",
|
||||
"SwitcherTwoTone",
|
||||
"SyncOutlined",
|
||||
"TableOutlined",
|
||||
"TabletFilled",
|
||||
"TabletOutlined",
|
||||
"TabletTwoTone",
|
||||
"TagFilled",
|
||||
"TagOutlined",
|
||||
"TagTwoTone",
|
||||
"TagsFilled",
|
||||
"TagsOutlined",
|
||||
"TagsTwoTone",
|
||||
"TaobaoCircleFilled",
|
||||
"TaobaoCircleOutlined",
|
||||
"TaobaoOutlined",
|
||||
"TaobaoSquareFilled",
|
||||
"TeamOutlined",
|
||||
"ThunderboltFilled",
|
||||
"ThunderboltOutlined",
|
||||
"ThunderboltTwoTone",
|
||||
"ToTopOutlined",
|
||||
"ToolFilled",
|
||||
"ToolOutlined",
|
||||
"ToolTwoTone",
|
||||
"TrademarkCircleFilled",
|
||||
"TrademarkCircleOutlined",
|
||||
"TrademarkCircleTwoTone",
|
||||
"TrademarkOutlined",
|
||||
"TransactionOutlined",
|
||||
"TranslationOutlined",
|
||||
"TrophyFilled",
|
||||
"TrophyOutlined",
|
||||
"TrophyTwoTone",
|
||||
"TwitterCircleFilled",
|
||||
"TwitterOutlined",
|
||||
"TwitterSquareFilled",
|
||||
"UnderlineOutlined",
|
||||
"UndoOutlined",
|
||||
"UngroupOutlined",
|
||||
"UnlockFilled",
|
||||
"UnlockOutlined",
|
||||
"UnlockTwoTone",
|
||||
"UnorderedListOutlined",
|
||||
"UpCircleFilled",
|
||||
"UpCircleOutlined",
|
||||
"UpCircleTwoTone",
|
||||
"UpOutlined",
|
||||
"UpSquareFilled",
|
||||
"UpSquareOutlined",
|
||||
"UpSquareTwoTone",
|
||||
"UploadOutlined",
|
||||
"UsbFilled",
|
||||
"UsbOutlined",
|
||||
"UsbTwoTone",
|
||||
"UserAddOutlined",
|
||||
"UserDeleteOutlined",
|
||||
"UserOutlined",
|
||||
"UserSwitchOutlined",
|
||||
"UsergroupAddOutlined",
|
||||
"UsergroupDeleteOutlined",
|
||||
"VerifiedOutlined",
|
||||
"VerticalAlignBottomOutlined",
|
||||
"VerticalAlignMiddleOutlined",
|
||||
"VerticalAlignTopOutlined",
|
||||
"VerticalLeftOutlined",
|
||||
"VerticalRightOutlined",
|
||||
"VideoCameraAddOutlined",
|
||||
"VideoCameraFilled",
|
||||
"VideoCameraOutlined",
|
||||
"VideoCameraTwoTone",
|
||||
"WalletFilled",
|
||||
"WalletOutlined",
|
||||
"WalletTwoTone",
|
||||
"WarningFilled",
|
||||
"WarningOutlined",
|
||||
"WarningTwoTone",
|
||||
"WechatFilled",
|
||||
"WechatOutlined",
|
||||
"WeiboCircleFilled",
|
||||
"WeiboCircleOutlined",
|
||||
"WeiboOutlined",
|
||||
"WeiboSquareFilled",
|
||||
"WeiboSquareOutlined",
|
||||
"WhatsAppOutlined",
|
||||
"WifiOutlined",
|
||||
"WindowsFilled",
|
||||
"WindowsOutlined",
|
||||
"WomanOutlined",
|
||||
"YahooFilled",
|
||||
"YahooOutlined",
|
||||
"YoutubeFilled",
|
||||
"YoutubeOutlined",
|
||||
"YuqueFilled",
|
||||
"YuqueOutlined",
|
||||
"ZhihuCircleFilled",
|
||||
"ZhihuOutlined",
|
||||
"ZhihuSquareFilled",
|
||||
"ZoomInOutlined",
|
||||
"ZoomOutOutlined"
|
||||
]
|
||||
@@ -66,14 +66,10 @@
|
||||
|
||||
httpRequest({ api, params: data, pathParams: params, requestConfig })
|
||||
.then((res) => {
|
||||
if (res.msg === 'success') {
|
||||
NsMessage.success('操作成功', 1, () => {
|
||||
toggle();
|
||||
success && success(res);
|
||||
});
|
||||
} else {
|
||||
NsMessage.error(res.msg);
|
||||
}
|
||||
NsMessage.success('操作成功', 1, () => {
|
||||
toggle();
|
||||
success && success(res);
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
|
||||
@@ -1,33 +1,18 @@
|
||||
<template>
|
||||
<a-steps direction="vertical" :current="size">
|
||||
<template v-for="(item, index) in dataSource" :key="index">
|
||||
<a-step title="">
|
||||
<a-step>
|
||||
<template #icon>
|
||||
<ns-icon size="24" :name="item.src" />
|
||||
<ns-icon size="20" :name="item.src" />
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
<a-tag class="card-title-tag" :color="item.color">{{ item.stateName }}</a-tag>
|
||||
<div class="name">{{ item.realName }}</div>
|
||||
<a-tag
|
||||
class="card-title-tag"
|
||||
:style="{
|
||||
'background-color': item.bgColor,
|
||||
border: '1px solid ' + item.color,
|
||||
color: item.color,
|
||||
}"
|
||||
>{{ item.stateName }}
|
||||
</a-tag>
|
||||
<div class="time">{{ item.createTime }}</div>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
max-height: 35px;
|
||||
overflow-y: scroll;
|
||||
padding: 7px 0px;
|
||||
">
|
||||
<div style="width: 100%; color: #3a3a3a; height: 25px; overflow: auto">
|
||||
{{ item.remarks }}</div
|
||||
>
|
||||
</div>
|
||||
@@ -56,45 +41,43 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
.card {
|
||||
width: 450px;
|
||||
height: 90px;
|
||||
background: rgba(191, 205, 226, 0.1);
|
||||
width: 400px;
|
||||
min-height: 0px;
|
||||
background-color: #f8fafc;
|
||||
margin-left: 20px;
|
||||
border-radius: 4px; /* 设置圆角半径 */
|
||||
padding: 12px;
|
||||
margin-left: 8px;
|
||||
.card-title {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
.card-title-tag {
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
width: 60px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
margin-left: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.name {
|
||||
left: 12px;
|
||||
position: absolute;
|
||||
left: 35%;
|
||||
top: -2px;
|
||||
font-size: 16px;
|
||||
color: rgba(153, 153, 153, 1);
|
||||
transform: translateX(-50%);
|
||||
color: #3a3a3a;
|
||||
}
|
||||
.time {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: -2px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
color: #ff7602;
|
||||
}
|
||||
:deep(.ant-steps-item-tail) {
|
||||
position: absolute !important;
|
||||
// top: -10px !important;
|
||||
top: -10px !important;
|
||||
left: 16px !important;
|
||||
width: 1px !important;
|
||||
height: 120% !important;
|
||||
height: 150% !important;
|
||||
}
|
||||
:deep(.ant-steps-item) {
|
||||
margin-top: 20px !important;
|
||||
|
||||
@@ -3,19 +3,14 @@ import { permission } from '/@/api/origanizemanage';
|
||||
import { appConfigStore } from '/nerv-lib/saas/store/modules/app-config';
|
||||
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||||
import { get } from 'lodash-es';
|
||||
import { computed, ref, toRef} from 'vue';
|
||||
import { computed, ref, toRef } from 'vue';
|
||||
|
||||
import { router } from '/nerv-lib/saas/router';
|
||||
import { replyRoutesButton } from '/@/util/dynamicRoutes';
|
||||
import { replyDynamRoutesPath } from '/nerv-lib/util/dynamicRoutesss';
|
||||
import { useTags } from '/nerv-base/store/modules/tags';
|
||||
|
||||
const ROLEID = sessionStorage.getItem('ROLEID') ? Number(sessionStorage.getItem('ROLEID')) : '';
|
||||
// const isAdmin = sessionStorage.getItem('ISADMIN')
|
||||
// ? Boolean(sessionStorage.getItem('ISADMIN'))
|
||||
// : false;
|
||||
const selectDefaultValue = ref(ROLEID);
|
||||
// const selectDefaultDisabled = ref(isAdmin);
|
||||
const ORGID = sessionStorage.getItem('ORGID') ? Number(sessionStorage.getItem('ORGID')) : '';
|
||||
const isAdmin = sessionStorage.getItem('ISADMIN')
|
||||
? Boolean(sessionStorage.getItem('ISADMIN'))
|
||||
: false;
|
||||
const selectDefaultValue = ref(ORGID);
|
||||
const selectDefaultDisabled = ref(isAdmin);
|
||||
const transform = (data, map) => {
|
||||
return Object.keys(map).reduce((pre, cur) => {
|
||||
pre[cur] = data[map[cur]];
|
||||
@@ -27,7 +22,7 @@ export const appConfig = {
|
||||
projectType: 'web',
|
||||
baseApi: '/api',
|
||||
projectName: '济阳站_AI智能BAS系统',
|
||||
enablePermissions: false,
|
||||
enablePermissions: true,
|
||||
// themeColor: '#eee',
|
||||
siderPosition: 'left',
|
||||
baseHeader: '/parkingManage',
|
||||
@@ -51,25 +46,22 @@ export const appConfig = {
|
||||
api: '/carbon-smart/user/login/logInInfo',
|
||||
size: 'large',
|
||||
defaultValue: selectDefaultValue,
|
||||
disabled:false,
|
||||
// disabled: selectDefaultDisabled,
|
||||
disabled: selectDefaultDisabled,
|
||||
// autoSelectFirst: true,
|
||||
placeholder: '请选择',
|
||||
onSelect: async (cur:any, record:any) => {
|
||||
onSelect: async (cur, record) => {
|
||||
console.log(cur, record);
|
||||
const configStore = appConfigStore();
|
||||
const useAuthorization = authorizationService();
|
||||
sessionStorage.setItem('ORGID', record.orgId);
|
||||
sessionStorage.setItem('ROLEID', record.roleId);
|
||||
const res = await configStore.userResource({ data: record });
|
||||
useAuthorization.updateUserResource(res.data);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 200);
|
||||
window.location.reload();
|
||||
// value.value = cur;
|
||||
},
|
||||
resultField: 'data.userRoles',
|
||||
resultField: 'data.linkList',
|
||||
labelField: 'orgName',
|
||||
valueField: 'roleId',
|
||||
valueField: 'orgId',
|
||||
immediate: true,
|
||||
dropdownReload: true,
|
||||
},
|
||||
@@ -79,33 +71,15 @@ export const appConfig = {
|
||||
return http.post('/carbon-smart/user/login', { ...params });
|
||||
},
|
||||
userResourceApi: (params) => {
|
||||
const { roleId } = get(params, 'data') || { roleId: '' };
|
||||
const finalId = roleId || ROLEID;
|
||||
const { orgId } = get(params, 'data') || { orgId: '' };
|
||||
const finalId = orgId || ORGID;
|
||||
// 解决初始化登录select无初始值的问题
|
||||
selectDefaultValue.value = finalId;
|
||||
|
||||
// const userInfo = JSON.parse(sessionStorage.getItem(import.meta.env.VITE_PUBLIC_PATH)!);
|
||||
// const ownOrgInfo = userInfo.userRoles?.filter(({ roleId: id }) => id === finalId)[0];
|
||||
// return http.post('/carbon-smart/user/login/logInPermission', ownOrgInfo).then((res) => {
|
||||
// return res;
|
||||
// });
|
||||
// 切换角色时获取新的权限菜单
|
||||
return http.post('/carbon-smart/user/login/role/permission/'+finalId).then((res) => {
|
||||
//切换后重新处理动态菜单数据
|
||||
let resetDynamicRouteList = replyRoutesButton(res.data);
|
||||
sessionStorage.setItem("dynamicRouteList",JSON.stringify(resetDynamicRouteList));
|
||||
if(resetDynamicRouteList && resetDynamicRouteList.length>0){
|
||||
let addDynamicRoutes = replyDynamRoutesPath(resetDynamicRouteList);
|
||||
addDynamicRoutes.forEach(item => {
|
||||
if (item.children && !item.component) {
|
||||
item.component = () => import('/nerv-lib/saas/view/system/application.vue');//hx-ai-intelligent项目下的首页
|
||||
}
|
||||
router.addRoute(item);
|
||||
})
|
||||
}
|
||||
//删除所有已经打开的tag标签
|
||||
useTags().clearTags();
|
||||
router.replace({ name: 'home' });
|
||||
const userInfo = JSON.parse(sessionStorage.getItem(import.meta.env.VITE_PUBLIC_PATH)!);
|
||||
const ownOrgInfo = userInfo.linkList?.filter(({ orgId: id }) => id === finalId)[0];
|
||||
|
||||
return http.post('/carbon-smart/user/login/logInPermission', ownOrgInfo).then((res) => {
|
||||
return res;
|
||||
});
|
||||
},
|
||||
@@ -122,25 +96,15 @@ export const appConfig = {
|
||||
linkList: 'linkList',
|
||||
permissionVos: 'permissionVos',
|
||||
adminFlag: 'adminFlag',
|
||||
userRoles:'userRoles',
|
||||
});
|
||||
sessionStorage.setItem('ORGID', info.orgId);
|
||||
sessionStorage.setItem('LINKLIST', JSON.stringify(info.linkList));
|
||||
// 头部“企业角色”切换暂不需要以下屏蔽的两个参数
|
||||
// sessionStorage.setItem('ISADMIN', trD?.adminFlag === '1');
|
||||
// selectDefaultDisabled.value = info?.adminFlag === '1';
|
||||
if(info.userRoles && info.userRoles.length>0){
|
||||
sessionStorage.setItem('ROLEID', info.userRoles[0].roleId);
|
||||
sessionStorage.setItem('USERROLES', JSON.stringify(info.userRoles));
|
||||
selectDefaultValue.value = info.userRoles[0].roleId;
|
||||
//路由接口数据暂时组装
|
||||
let getRoutesList = replyRoutesButton(info.userRoles[0].routes);
|
||||
sessionStorage.setItem("dynamicRouteList",JSON.stringify(getRoutesList))
|
||||
sessionStorage.setItem("isRefrech",'1')
|
||||
}
|
||||
return { data: { ...trD } };
|
||||
});
|
||||
sessionStorage.setItem('ISADMIN', trD?.adminFlag === '1');
|
||||
selectDefaultDisabled.value = info?.adminFlag === '1';
|
||||
selectDefaultValue.value = info.orgId;
|
||||
return { data: { ...trD } };
|
||||
});
|
||||
},
|
||||
|
||||
useHistoryTag: false,
|
||||
// 修改密码配置
|
||||
updatePassWordInfo: {
|
||||
|
||||
|
Before Width: | Height: | Size: 356 B |
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="20px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -320 -9 )">
|
||||
<path d="M 5.72142857421875 4.29571427734375 L 5.72142857421875 0.0171428515625 L 10 0.0171428515625 L 10 4.29571427734375 L 5.72142857421875 4.29571427734375 Z M 14.564285722656251 0.3028571484375 L 19.84 5.57857142578125 C 19.9828571484375 5.57857142578125 19.9828571484375 5.864285703125001 20 6.0071428515625005 L 20 19.27 C 19.9828571484375 19.69857142578125 19.697142871093753 19.98428572265625 19.27 20 L 0.73 20 C 0.30142857421874997 19.98428572265625 0.015714277343749916 19.6985714453125 0 19.27 L 0 0.73 C 0.015714277343749916 0.30142857421874997 0.30142855468749996 0.015714277343749916 0.73 0.015714277343749916 L 4.29571427734375 0.015714277343749916 L 4.29571427734375 5.72142857421875 L 11.42571427734375 5.72142857421875 L 11.42571427734375 0.0171428515625 L 13.992857148437501 0.0171428515625 C 14.135714296875001 0.0171428515625 14.421428574218751 0.16 14.564285722656251 0.3028571484375 Z M 4.29571427734375 15.70428572265625 L 15.70428572265625 15.704285722656248 L 15.70428572265625 10 L 4.29571427734375 10 L 4.29571427734375 15.70428572265625 Z " fill-rule="nonzero" fill="rgba(67, 136, 251, 1)" stroke="none" transform="matrix(1 0 0 1 320 9 )" />
|
||||
<path d="M 5.72142857421875 4.29571427734375 L 5.72142857421875 0.0171428515625 L 10 0.0171428515625 L 10 4.29571427734375 L 5.72142857421875 4.29571427734375 Z M 14.564285722656251 0.3028571484375 L 19.84 5.57857142578125 C 19.9828571484375 5.57857142578125 19.9828571484375 5.864285703125001 20 6.0071428515625005 L 20 19.27 C 19.9828571484375 19.69857142578125 19.697142871093753 19.98428572265625 19.27 20 L 0.73 20 C 0.30142857421874997 19.98428572265625 0.015714277343749916 19.6985714453125 0 19.27 L 0 0.73 C 0.015714277343749916 0.30142857421874997 0.30142855468749996 0.015714277343749916 0.73 0.015714277343749916 L 4.29571427734375 0.015714277343749916 L 4.29571427734375 5.72142857421875 L 11.42571427734375 5.72142857421875 L 11.42571427734375 0.0171428515625 L 13.992857148437501 0.0171428515625 C 14.135714296875001 0.0171428515625 14.421428574218751 0.16 14.564285722656251 0.3028571484375 Z M 4.29571427734375 15.70428572265625 L 15.70428572265625 15.704285722656248 L 15.70428572265625 10 L 4.29571427734375 10 L 4.29571427734375 15.70428572265625 Z " fill-rule="nonzero" fill="#ff7602" stroke="none" transform="matrix(1 0 0 1 320 9 )" />
|
||||
</g>
|
||||
</svg>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="20px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -320 -9 )">
|
||||
<path d="M 17.482232142857143 6.05310267857143 L 7.481830357142856 16.053526785714283 L 3.946339285714287 12.518035714285713 L 13.946741071428567 2.5176116071428565 L 17.482232142857143 6.05310267857143 Z M 2.8571428571428568 17.142857142857142 L 2.8571428571428568 13.607142857142856 L 6.392857142857144 17.142857142857142 L 2.8571428571428568 17.142857142857142 Z M 18.013392857142858 0.4017857142857143 L 19.598214285714285 1.9866071428571428 C 20.133928571428573 2.5223214285714284 20.133928571428573 3.3995535714285703 19.598214285714285 3.937500000000002 L 18.55357142857143 4.982142857142853 L 15.017857142857142 1.4464285714285705 L 16.062499999999996 0.4017857142857143 C 16.598214285714285 -0.13392857142857142 17.47544642857143 -0.13392857142857142 18.013392857142858 0.4017857142857143 Z M 0 15.714285714285714 L 1.4285714285714284 15.714285714285714 L 1.4285714285714284 18.571428571424978 L 1.4285714285714284 20 L 0 20 L 0 15.714285714285714 Z M 18.571428571428573 20 L 1.4285714285714284 20 L 1.4285714285714284 18.571428571428573 L 18.571428571428573 18.571428571428573 L 18.571428571428573 20 Z M 20 15.714285714285714 L 20 20 L 18.571428571428573 20 L 18.571428571428573 15.714285714285714 L 20 15.714285714285714 Z " fill-rule="nonzero" fill="rgba(67, 136, 251, 1)" stroke="none" transform="matrix(1 0 0 1 320 9 )" />
|
||||
<path d="M 17.482232142857143 6.05310267857143 L 7.481830357142856 16.053526785714283 L 3.946339285714287 12.518035714285713 L 13.946741071428567 2.5176116071428565 L 17.482232142857143 6.05310267857143 Z M 2.8571428571428568 17.142857142857142 L 2.8571428571428568 13.607142857142856 L 6.392857142857144 17.142857142857142 L 2.8571428571428568 17.142857142857142 Z M 18.013392857142858 0.4017857142857143 L 19.598214285714285 1.9866071428571428 C 20.133928571428573 2.5223214285714284 20.133928571428573 3.3995535714285703 19.598214285714285 3.937500000000002 L 18.55357142857143 4.982142857142853 L 15.017857142857142 1.4464285714285705 L 16.062499999999996 0.4017857142857143 C 16.598214285714285 -0.13392857142857142 17.47544642857143 -0.13392857142857142 18.013392857142858 0.4017857142857143 Z M 0 15.714285714285714 L 1.4285714285714284 15.714285714285714 L 1.4285714285714284 18.571428571424978 L 1.4285714285714284 20 L 0 20 L 0 15.714285714285714 Z M 18.571428571428573 20 L 1.4285714285714284 20 L 1.4285714285714284 18.571428571428573 L 18.571428571428573 18.571428571428573 L 18.571428571428573 20 Z M 20 15.714285714285714 L 20 20 L 18.571428571428573 20 L 18.571428571428573 15.714285714285714 L 20 15.714285714285714 Z " fill-rule="nonzero" fill="#ff7602" stroke="none" transform="matrix(1 0 0 1 320 9 )" />
|
||||
</g>
|
||||
</svg>
|
||||
@@ -1,4 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.56231689453125" height="15.345458984375" viewBox="0 0 16.56231689453125 15.345458984375" fill="none">
|
||||
<path d="M2.26283 0C2.61778 0 2.91885 0.120438 3.16605 0.36129C3.41325 0.60215 3.53685 0.900055 3.53685 1.25501L3.53685 2.22479C3.53685 2.57975 3.41325 2.88082 3.16605 3.12801C2.91885 3.37522 2.61778 3.49882 2.26283 3.49882L1.25501 3.49882C0.912735 3.49882 0.618004 3.37522 0.370804 3.12801C0.123596 2.88082 0 2.57975 0 2.22479L0 1.25501C0 0.900055 0.123596 0.60215 0.370804 0.36129C0.618004 0.120438 0.912743 0 1.25501 0L2.26283 0ZM15.3073 0C15.6496 0 15.9443 0.120438 16.1915 0.36129C16.4387 0.60215 16.5623 0.900055 16.5623 1.25501L16.5623 2.22479C16.5623 2.57975 16.4387 2.88082 16.1915 3.12801C15.9443 3.37522 15.6496 3.49882 15.3073 3.49882L7.18778 3.49882C6.83284 3.49882 6.53176 3.37522 6.28456 3.12801C6.03737 2.88082 5.91376 2.57975 5.91376 2.22479L5.91376 1.25501C5.91376 0.900055 6.03737 0.60215 6.28456 0.36129C6.53176 0.120438 6.83284 0 7.18778 0L15.3073 0ZM2.26283 5.91376C2.61778 5.91376 2.91885 6.03737 3.16605 6.28456C3.41325 6.53176 3.53685 6.83284 3.53685 7.18778L3.53685 8.15757C3.53685 8.49984 3.41325 8.79458 3.16605 9.04179C2.91885 9.28898 2.61778 9.41258 2.26283 9.41258L1.25501 9.41258C0.912735 9.41258 0.618004 9.28898 0.370804 9.04179C0.123596 8.79458 0 8.49984 0 8.15757L0 7.18778C0 6.83284 0.123596 6.53176 0.370804 6.28456C0.618004 6.03737 0.912743 5.91376 1.25501 5.91376L2.26283 5.91376ZM15.3073 5.91376C15.6496 5.91376 15.9443 6.03737 16.1915 6.28456C16.4387 6.53176 16.5623 6.83284 16.5623 7.18778L16.5623 8.15757C16.5623 8.49984 16.4387 8.79458 16.1915 9.04179C15.9443 9.28898 15.6496 9.41258 15.3073 9.41258L7.18778 9.41258C6.83284 9.41258 6.53176 9.28898 6.28456 9.04179C6.03737 8.79458 5.91376 8.49984 5.91376 8.15757L5.91376 7.18778C5.91376 6.83284 6.03737 6.53176 6.28456 6.28456C6.53176 6.03737 6.83284 5.91376 7.18778 5.91376L15.3073 5.91376ZM2.26283 11.8465C2.61778 11.8465 2.91885 11.9701 3.16605 12.2173C3.41325 12.4645 3.53685 12.7593 3.53685 13.1016L3.53685 14.0713C3.53685 14.4263 3.41325 14.7274 3.16605 14.9746C2.91885 15.2218 2.61778 15.3454 2.26283 15.3454L1.25501 15.3454C0.912735 15.3454 0.618004 15.2218 0.370804 14.9746C0.123596 14.7274 0 14.4263 0 14.0713L0 13.1016C0 12.7593 0.123596 12.4645 0.370804 12.2173C0.618004 11.9701 0.912743 11.8465 1.25501 11.8465L2.26283 11.8465ZM15.3073 11.8465C15.6496 11.8465 15.9443 11.9701 16.1915 12.2173C16.4387 12.4645 16.5623 12.7593 16.5623 13.1016L16.5623 14.0713C16.5623 14.4263 16.4387 14.7274 16.1915 14.9746C15.9443 15.2218 15.6496 15.3454 15.3073 15.3454L7.18778 15.3454C6.83284 15.3454 6.53176 15.2218 6.28456 14.9746C6.03737 14.7274 5.91376 14.4263 5.91376 14.0713L5.91376 13.1016C5.91376 12.7593 6.03737 12.4645 6.28456 12.2173C6.53176 11.9701 6.83284 11.8465 7.18778 11.8465L15.3073 11.8465Z" fill="#2778FF" >
|
||||
</path>
|
||||
</svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720144479404" class="icon" viewBox="0 0 1142 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2572" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.84375" height="16"><path d="M1102.769231 39.384615v945.23077H39.384615V39.384615h1063.384616m0-39.384615H39.384615a39.384615 39.384615 0 0 0-39.384615 39.384615v945.23077a39.384615 39.384615 0 0 0 39.384615 39.384615h1063.384616a39.384615 39.384615 0 0 0 39.384615-39.384615V39.384615a39.384615 39.384615 0 0 0-39.384615-39.384615z" fill="#4D4D4D" p-id="2573"></path><path d="M39.384615 393.846154h1063.384616v39.384615H39.384615zM39.384615 590.769231h1063.384616v39.384615H39.384615zM39.384615 787.692308h1063.384616v39.384615H39.384615zM39.384615 196.923077h1063.384616v39.384615H39.384615z" fill="#B3B3B3" p-id="2574"></path><path d="M315.076923 196.923077v787.692308H275.692308V196.923077zM590.769231 196.923077v787.692308h-39.384616V196.923077zM866.461538 196.923077v787.692308h-39.384615V196.923077z" fill="#B3B3B3" p-id="2575"></path><path d="M39.384615 39.384615h1063.384616v157.538462H39.384615z" fill="#05AFC8" p-id="2576"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,8 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<g id="组_22740" data-name="组 22740" transform="translate(-1845.881 -208.881)">
|
||||
<g id="组_24427" data-name="组 24427">
|
||||
<rect id="矩形_16486" data-name="矩形 16486" width="20" height="20" transform="translate(1845.881 208.881)" fill="none"/>
|
||||
<path id="路径_31099" data-name="路径 31099" d="M63.9,114.958h4.606v3.835H63.9Zm5.862,5.122h4.774V124.3H69.762Zm0-5.122h4.774v3.835H69.762Zm6.284,5.122H80.4V124.3H75.793v-3.964A.255.255,0,0,1,76.046,120.08Zm-12.146,0h4.606V124.3H63.9Zm0-10.98H80.4v4.571H63.9Zm12.146,5.858H80.4v3.835H75.793v-3.577A.255.255,0,0,1,76.046,114.958Z" transform="translate(1783.72 101.781)" fill="#2778ff"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 765 B |
@@ -1 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720145764410" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4680" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M495.611479 159.364238C285.562631 159.364238 115.284768 329.642102 115.284768 539.690949S285.562631 920.01766 495.611479 920.01766 875.93819 749.739797 875.93819 539.690949H518.216336c-12.484662 0-22.604857-10.120194-22.604857-22.604856V159.364238z" fill="#2778FF" p-id="4681"></path><path d="M562.860927 495.046358h368.459161c0-215.978102-175.085916-391.064018-391.064017-391.064018v368.459161c0 12.484662 10.120194 22.604857 22.604856 22.604857z" fill="#2778FF" p-id="4682"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720145764410" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4680" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M495.611479 159.364238C285.562631 159.364238 115.284768 329.642102 115.284768 539.690949S285.562631 920.01766 495.611479 920.01766 875.93819 749.739797 875.93819 539.690949H518.216336c-12.484662 0-22.604857-10.120194-22.604857-22.604856V159.364238z" fill="#839BFB" p-id="4681"></path><path d="M562.860927 495.046358h368.459161c0-215.978102-175.085916-391.064018-391.064017-391.064018v368.459161c0 12.484662 10.120194 22.604857 22.604856 22.604857z" fill="#839BFB" fill-opacity=".6" p-id="4682"></path></svg>
|
||||
|
Before Width: | Height: | Size: 821 B After Width: | Height: | Size: 838 B |