| | |
| | | max-height: calc(100vh - 110px); |
| | | text-align: center; |
| | | } |
| | | .ant-tabs-tabpane { |
| | | >.box404 { |
| | | padding-top: 40px; |
| | | } |
| | | } |
| | |
| | | |
| | | const Home = asyncComponent(() => import('@/tabviews/home')) |
| | | const CommonTable = asyncComponent(() => import('@/tabviews/commontable')) |
| | | const CalendarPage = asyncComponent(() => import('@/tabviews/calendar')) |
| | | const TreePage = asyncComponent(() => import('@/tabviews/treepage')) |
| | | const VerupTable = asyncComponent(() => import('@/tabviews/verupmanage')) |
| | | const ScriptTable = asyncComponent(() => import('@/tabviews/scriptmanage')) |
| | |
| | | return (<CommonTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>) |
| | | } else if (view.type === 'TreePage') { |
| | | return (<TreePage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>) |
| | | } else if (view.type === 'CalendarPage') { |
| | | return (<CalendarPage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>) |
| | | } else if (view.type === 'VerupTable') { |
| | | return (<VerupTable MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>) |
| | | } else if (view.type === 'ScriptTable') { |
| | |
| | | <Tabs.TabPane |
| | | tab={ |
| | | <span className="tab-control"> |
| | | {['CommonTable', 'FormTab', 'TreePage'].includes(view.type) ? |
| | | {['CommonTable', 'FormTab', 'TreePage', 'CalendarPage'].includes(view.type) ? |
| | | <Icon type="redo" onClick={(e) => {this.refreshTabview(e, view)}}/> : null |
| | | } |
| | | <span className="tab-name" onClick={(e) => {this.changeTab(e, view)}}> |
| | |
| | | key={view.MenuID} |
| | | > |
| | | {this.selectcomponent(view)} |
| | | {options.sysType !== 'cloud' && !['CommonTable', 'TreePage', 'ManageTable'].includes(view.type) ? |
| | | {options.sysType !== 'cloud' && !['CommonTable', 'TreePage', 'ManageTable', 'CalendarPage'].includes(view.type) ? |
| | | <Button |
| | | icon="copy" |
| | | shape="circle" |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { notification, Spin, Modal, Button, message, Tree, Typography } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | import Api from '@/api' |
| | | import options from '@/store/options.js' |
| | | import zhCN from '@/locales/zh-CN/main.js' |
| | | import enUS from '@/locales/en-US/main.js' |
| | | import Utils from '@/utils/utils.js' |
| | | import asyncSpinComponent from '@/utils/asyncSpinComponent' |
| | | import { refreshTabView } from '@/store/action' |
| | | |
| | | import MainSearch from '@/tabviews/zshare/topSearch' |
| | | import NotFount from '@/components/404' |
| | | import './index.scss' |
| | | |
| | | // 通用组件 |
| | | const CalendarComponent = asyncSpinComponent(() => import('@/tabviews/zshare/calendar')) |
| | | const SubTabTable = asyncSpinComponent(() => import('@/tabviews/subtabtable')) |
| | | |
| | | const { TreeNode } = Tree |
| | | const { Paragraph } = Typography |
| | | |
| | | class NormalTable extends Component { |
| | | static propTpyes = { |
| | | param: PropTypes.any, // 其他页面传递的搜索条件等参数 |
| | | MenuID: PropTypes.string, // 菜单Id |
| | | MenuNo: PropTypes.string, // 菜单参数 |
| | | MenuName: PropTypes.string // 菜单名称 |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | ContainerId: Utils.getuuid(), // 菜单外层html Id |
| | | BID: null, // 页面跳转时携带ID |
| | | loadingview: true, // 页面加载中 |
| | | viewlost: false, // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用 |
| | | lostmsg: '', // 页面丢失时的提示信息 |
| | | config: {}, // 页面配置信息,包括按钮、搜索、显示列、标签等 |
| | | userConfig: null, // 用户自定义设置 |
| | | searchlist: null, // 搜索条件 |
| | | arr_field: '', // 使用 sPC_Get_TableData 时的查询字段集 |
| | | setting: null, // 页面全局设置:数据源、按钮及显示列固定、主键等 |
| | | data: null, // 列表数据集 |
| | | loading: false, // 列表数据加载中 |
| | | search: '', // 搜索条件数组,使用时需分场景处理 |
| | | visible: false, // 标签页控制 |
| | | triggerTime: '', // 点击时间 |
| | | treevisible: false, // 菜单结构树弹框显示隐藏控制 |
| | | calendarYear: moment().format('YYYY') // 日历年份 |
| | | } |
| | | |
| | | /** |
| | | * @description 获取页面配置信息 |
| | | */ |
| | | async loadconfig () { |
| | | const { permAction, param } = this.props |
| | | |
| | | let _param = { |
| | | func: 'sPC_Get_LongParam', |
| | | MenuID: this.props.MenuID |
| | | } |
| | | let result = await Api.getCacheConfig(_param) |
| | | |
| | | if (result.status) { |
| | | let config = '' |
| | | let userConfig = null |
| | | let _curUserConfig = '' |
| | | |
| | | try { // 配置信息解析 |
| | | config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) |
| | | } catch (e) { |
| | | console.warn('Parse Failure') |
| | | config = '' |
| | | } |
| | | |
| | | // HS不使用自定义设置 |
| | | if (result.LongParamUser && this.props.menuType !== 'HS') { |
| | | try { // 配置信息解析 |
| | | userConfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParamUser))) |
| | | _curUserConfig = userConfig[this.props.MenuID] |
| | | } catch (e) { |
| | | console.warn('Parse Failure') |
| | | userConfig = null |
| | | } |
| | | } |
| | | |
| | | // 页面配置解析错误时提示 |
| | | if (!config) { |
| | | this.setState({ |
| | | loadingview: false, |
| | | viewlost: true |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 页面未启用时,显示未启用页面 |
| | | if (!config.enabled) { |
| | | this.setState({ |
| | | loadingview: false, |
| | | viewlost: true, |
| | | lostmsg: this.state.dict['main.view.unenabled'] |
| | | }) |
| | | return |
| | | } |
| | | |
| | | // 权限过滤 |
| | | if (this.props.menuType !== 'HS') { |
| | | if (config.tab && !permAction[config.tab.linkTab]) { |
| | | config.tab = null |
| | | } |
| | | } |
| | | |
| | | // 字段权限黑名单 |
| | | config.search = config.search.map(item => { |
| | | item.oriInitval = item.initval |
| | | if (['text', 'select', 'link'].includes(item.type) && param) { |
| | | if (param.searchkey === item.field) { |
| | | item.initval = param.searchval |
| | | } else if (param.BID && item.field === 'BID') { |
| | | item.initval = param.BID |
| | | } |
| | | } |
| | | |
| | | if (!item.blacklist || item.blacklist.length === 0) return item |
| | | |
| | | let _black = item.blacklist.filter(v => { |
| | | return this.props.permRoles.indexOf(v) !== -1 |
| | | }) |
| | | |
| | | if (_black.length > 0) { |
| | | item.Hide = 'true' |
| | | } |
| | | |
| | | return item |
| | | }) |
| | | |
| | | if (_curUserConfig) { |
| | | config.setting = {...config.setting, ..._curUserConfig.setting} |
| | | config.easyCode = _curUserConfig.easyCode || config.easyCode || '' |
| | | } |
| | | |
| | | // 透视字段处理,初始化处理 |
| | | let valid = true |
| | | config.search = config.search.map(item => { |
| | | item.oriInitval = item.initval |
| | | if (['text', 'select', 'link'].includes(item.type) && param) { |
| | | if (param.searchkey === item.field) { |
| | | item.initval = param.searchval |
| | | } else if (param.BID && item.field === 'BID') { |
| | | item.initval = param.BID |
| | | } |
| | | } |
| | | |
| | | if (item.required === 'true' && !item.initval) { |
| | | valid = false |
| | | } |
| | | |
| | | return item |
| | | }) |
| | | |
| | | this.setState({ |
| | | BID: param && param.BID ? param.BID : '', |
| | | loadingview: false, |
| | | config: config, |
| | | userConfig: userConfig, |
| | | setting: config.setting, |
| | | searchlist: config.search, |
| | | arr_field: config.columns.map(item => item.field).join(','), |
| | | search: Utils.initMainSearch(config.search) // 搜索条件初始化(含有时间格式,需要转化) |
| | | }, () => { |
| | | if (config.setting.onload !== 'false' && valid) { // 初始化可加载 |
| | | this.loadmaindata() |
| | | } |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | | loadingview: false, |
| | | viewlost: true |
| | | }) |
| | | notification.warning({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 5 |
| | | }) |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @description 主表数据加载 |
| | | */ |
| | | async loadmaindata () { |
| | | const { setting, search, BID } = this.state |
| | | let param = '' |
| | | let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0)) |
| | | |
| | | if (requireFields.length > 0) { |
| | | let labels = requireFields.map(item => item.label) |
| | | labels = Array.from(new Set(labels)) |
| | | |
| | | notification.warning({ |
| | | top: 92, |
| | | message: this.state.dict['form.required.input'] + labels.join('、') + ' !', |
| | | duration: 3 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | this.setState({ |
| | | loading: true |
| | | }) |
| | | |
| | | if (setting.interType !== 'inner' || (setting.interType === 'inner' && setting.innerFunc)) { |
| | | param = this.getCustomParam() |
| | | } else { |
| | | param = this.getDefaultParam() |
| | | } |
| | | |
| | | if (BID) { |
| | | param.BID = BID |
| | | } |
| | | // 数据管理权限 |
| | | if (this.props.dataManager) { |
| | | param.dataM = 'Y' |
| | | } |
| | | |
| | | let result = await Api.genericInterface(param) |
| | | if (result.status) { |
| | | this.setState({ |
| | | data: result.data.map((item, index) => { |
| | | item.key = index |
| | | return item |
| | | }), |
| | | loading: false |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | | loading: false |
| | | }) |
| | | notification.error({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 10 |
| | | }) |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @description 获取用户自定义存储过程传参 |
| | | */ |
| | | getCustomParam = () => { |
| | | const { search, setting, calendarYear, config } = this.state |
| | | |
| | | let _search = Utils.formatCustomMainSearch(search) |
| | | |
| | | let param = { |
| | | ..._search |
| | | } |
| | | |
| | | if (config.calendar.refresh === 'true') { |
| | | param.calendarDate = calendarYear |
| | | } |
| | | |
| | | if (setting.interType === 'inner') { |
| | | param.func = setting.innerFunc |
| | | } else { |
| | | if (this.props.menuType === 'HS') { |
| | | if (setting.sysInterface === 'true' && options.cloudServiceApi) { |
| | | param.rduri = options.cloudServiceApi |
| | | } else if (setting.sysInterface !== 'true') { |
| | | param.rduri = setting.interface |
| | | } |
| | | } else { |
| | | if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) { |
| | | param.rduri = window.GLOB.mainSystemApi |
| | | } else if (setting.sysInterface !== 'true') { |
| | | param.rduri = setting.interface |
| | | } |
| | | } |
| | | |
| | | if (setting.outerFunc) { |
| | | param.func = setting.outerFunc |
| | | } |
| | | } |
| | | |
| | | return param |
| | | } |
| | | |
| | | /** |
| | | * @description 获取系统存储过程 sPC_Get_TableData 的参数 |
| | | */ |
| | | getDefaultParam = () => { |
| | | const { arr_field, search, setting, config, calendarYear } = this.state |
| | | |
| | | let _search = Utils.joinMainSearchkey(search) |
| | | |
| | | _search = _search ? 'where ' + _search : '' |
| | | |
| | | let param = { |
| | | func: 'sPC_Get_TableData', |
| | | obj_name: 'data', |
| | | arr_field: arr_field, |
| | | custom_script: setting.customScript || '', |
| | | default_sql: setting.default || 'true' |
| | | } |
| | | |
| | | let _dataresource = setting.dataresource |
| | | |
| | | if (/\s/.test(_dataresource)) { |
| | | _dataresource = '(' + _dataresource + ') tb' |
| | | } |
| | | |
| | | if (this.props.dataManager) { // 数据权限 |
| | | _dataresource = _dataresource.replace(/\$@/ig, '/*') |
| | | _dataresource = _dataresource.replace(/@\$/ig, '*/') |
| | | param.custom_script = param.custom_script.replace(/\$@/ig, '/*') |
| | | param.custom_script = param.custom_script.replace(/@\$/ig, '*/') |
| | | } else { |
| | | _dataresource = _dataresource.replace(/@\$|\$@/ig, '') |
| | | param.custom_script = param.custom_script.replace(/@\$|\$@/ig, '') |
| | | } |
| | | |
| | | let regoptions = null |
| | | if (setting.queryType === 'statistics' || param.custom_script) { |
| | | let allSearch = Utils.getAllSearchOptions(search) |
| | | |
| | | regoptions = allSearch.map(item => { |
| | | return { |
| | | reg: new RegExp('@' + item.key + '@', 'ig'), |
| | | value: `'${item.value}'` |
| | | } |
| | | }) |
| | | } |
| | | |
| | | if (config.calendar.refresh === 'true' && regoptions) { |
| | | regoptions.push({ |
| | | reg: new RegExp('@calendarDate@', 'ig'), |
| | | value: `${calendarYear}-01-01 00:00:00.000` |
| | | }) |
| | | regoptions.push({ |
| | | reg: new RegExp('@calendarDate1@', 'ig'), |
| | | value: `${calendarYear}-12-31 23:59:59.999` |
| | | }) |
| | | } |
| | | |
| | | if (setting.queryType === 'statistics' && setting.default !== 'false') { // 统计数据源,内容替换 |
| | | regoptions.forEach(item => { |
| | | _dataresource = _dataresource.replace(item.reg, item.value) |
| | | }) |
| | | _search = '' |
| | | } |
| | | |
| | | let LText = '' |
| | | |
| | | if (setting.default !== 'false') { |
| | | LText = `select ${arr_field} from ${_dataresource} ${_search}` |
| | | } |
| | | |
| | | if (param.custom_script) { |
| | | regoptions.forEach(item => { |
| | | param.custom_script = param.custom_script.replace(item.reg, item.value) |
| | | }) |
| | | |
| | | if (LText) { |
| | | LText += ` |
| | | aaa: |
| | | if @ErrorCode!='' |
| | | insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ |
| | | ` |
| | | } else { |
| | | param.custom_script += ` |
| | | aaa: |
| | | if @ErrorCode!='' |
| | | insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@ |
| | | ` |
| | | } |
| | | } |
| | | |
| | | // 测试系统打印查询语句 |
| | | if (options.sysType === 'local' && !window.GLOB.systemType) { |
| | | param.custom_script && console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`) |
| | | LText && console.log(LText) |
| | | } |
| | | |
| | | param.custom_script = Utils.formatOptions(param.custom_script) |
| | | param.LText = Utils.formatOptions(LText) |
| | | param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000' |
| | | param.secretkey = Utils.encrypt(param.LText, param.timestamp) |
| | | param.DateCount = '' |
| | | |
| | | if (this.props.menuType === 'HS') { // 云端数据验证 |
| | | param.open_key = Utils.encrypt(param.secretkey, param.timestamp, true) |
| | | } |
| | | |
| | | return param |
| | | } |
| | | |
| | | /** |
| | | * @description 搜索条件改变时,重置表格数据 |
| | | * 含有初始不加载的页面,修改设置 |
| | | */ |
| | | refreshbysearch = (searches) => { |
| | | const { setting } = this.state |
| | | |
| | | if (setting.onload === 'false') { |
| | | this.setState({ |
| | | search: searches, |
| | | setting: {...setting, onload: 'true'} |
| | | }, () => { |
| | | this.loadmaindata() |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | | search: searches |
| | | }, () => { |
| | | this.loadmaindata() |
| | | }) |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * @description 页面刷新,重新获取配置 |
| | | */ |
| | | reloadview = () => { |
| | | this.setState({ loadingview: true, viewlost: false, lostmsg: '', data: null, loading: false, search: '' |
| | | }, () => { |
| | | this.loadconfig() |
| | | }) |
| | | } |
| | | |
| | | |
| | | handleviewconfig = (e) => { |
| | | e.stopPropagation() |
| | | |
| | | const { MenuNo } = this.props |
| | | const { config } = this.state |
| | | |
| | | if (config && config.funcs && config.funcs.length > 0) { |
| | | this.setState({ |
| | | treevisible: true |
| | | }) |
| | | } else { |
| | | let oInput = document.createElement('input') |
| | | oInput.value = MenuNo || '' |
| | | document.body.appendChild(oInput) |
| | | oInput.select() |
| | | document.execCommand('Copy') |
| | | document.body.removeChild(oInput) |
| | | message.success(this.state.dict['main.copy.success']) |
| | | } |
| | | } |
| | | |
| | | getTreeNode = (data) => { |
| | | let _type = { |
| | | view: '页面', |
| | | btn: '按钮', |
| | | tab: '标签' |
| | | } |
| | | |
| | | return data.map(item => { |
| | | let _title = _type[item.subtype] |
| | | let _others = [] |
| | | |
| | | _others.push( |
| | | (item.menuNo ? item.menuNo + '(菜单参数)' : ''), |
| | | (item.tableName ? item.tableName + '(表名) ' : ''), |
| | | (item.innerFunc ? item.innerFunc + '(内部函数) ' : ''), |
| | | (item.outerFunc ? item.outerFunc + '(外部函数)' : '') |
| | | ) |
| | | _others = _others.filter(Boolean) |
| | | _others = _others.join('、') |
| | | |
| | | if (item.label) { |
| | | _title = _title + '(' + item.label + ')' |
| | | } |
| | | if (_others) { |
| | | _title = _title + ': ' + _others |
| | | } |
| | | |
| | | if (item.subfuncs && item.subfuncs.length > 0) { |
| | | return ( |
| | | <TreeNode title={_title} key={item.uuid} dataRef={item} selectable={false}> |
| | | {this.getTreeNode(item.subfuncs)} |
| | | </TreeNode> |
| | | ) |
| | | } |
| | | return <TreeNode key={item.uuid} title={_title} isLeaf selectable={false} /> |
| | | }) |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | // 组件加载时,获取菜单数据 |
| | | this.loadconfig() |
| | | } |
| | | |
| | | UNSAFE_componentWillReceiveProps(nextProps) { |
| | | if (nextProps.refreshTab && nextProps.refreshTab.MenuID === this.props.MenuID) { |
| | | if (nextProps.refreshTab.position === 'grid') { |
| | | this.loadmaindata() |
| | | } else if (nextProps.refreshTab.position === 'view') { |
| | | this.reloadview() |
| | | } |
| | | this.props.refreshTabView('') |
| | | } else if (nextProps.param && !is(fromJS(this.props.param), fromJS(nextProps.param))) { |
| | | let search = this.state.search.map(item => { |
| | | if (item.type === 'text' && item.key === nextProps.param.searchkey) { |
| | | item.value = nextProps.param.searchval |
| | | } |
| | | return item |
| | | }) |
| | | this.refreshbysearch(search) |
| | | } |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | } |
| | | |
| | | changeDate = (value) => { |
| | | this.setState({calendarYear: value}, () => { |
| | | this.loadmaindata() |
| | | }) |
| | | } |
| | | |
| | | triggerDate = (item) => { |
| | | const { config } = this.state |
| | | let time = '' |
| | | |
| | | if (!config.tab) return |
| | | |
| | | if (item.time.length === 6) { |
| | | time = item.time.substr(0, 4) + '-' + item.time.substr(4, 2) |
| | | } else { |
| | | time = item.time.substr(0, 4) + '-' + item.time.substr(4, 2) + '-' + item.time.substr(6, 2) |
| | | } |
| | | |
| | | this.setState({ |
| | | visible: true, |
| | | triggerTime: time |
| | | }) |
| | | } |
| | | |
| | | closeTab = () => { |
| | | this.setState({ |
| | | visible: false, |
| | | triggerTime: '' |
| | | }) |
| | | } |
| | | |
| | | render() { |
| | | const { BID, searchlist, loadingview, viewlost, config, loading, data } = this.state |
| | | |
| | | return ( |
| | | <div className="calendar-page" id={this.state.ContainerId}> |
| | | {loadingview && <Spin size="large" />} |
| | | {searchlist && searchlist.length > 0 ? |
| | | <MainSearch |
| | | BID={BID} |
| | | dict={this.state.dict} |
| | | searchlist={searchlist} |
| | | menuType={this.props.menuType} |
| | | dataManager={this.props.dataManager} |
| | | refreshdata={this.refreshbysearch} |
| | | /> : null |
| | | } |
| | | {config && config.calendar ? <CalendarComponent calendar={config.calendar} loading={loading} data={data} triggerDate={this.triggerDate} changeDate={this.changeDate}/> : null} |
| | | {options.sysType !== 'cloud' ? <Button |
| | | icon="copy" |
| | | shape="circle" |
| | | className="common-table-copy" |
| | | onClick={this.handleviewconfig} |
| | | /> : null} |
| | | <Modal |
| | | className="menu-tree-modal" |
| | | title={'菜单结构树'} |
| | | width={'650px'} |
| | | maskClosable={false} |
| | | visible={this.state.treevisible} |
| | | onCancel={() => this.setState({treevisible: false})} |
| | | footer={[ |
| | | <Button key="close" onClick={() => this.setState({treevisible: false})}>{this.state.dict['main.close']}</Button> |
| | | ]} |
| | | destroyOnClose |
| | | > |
| | | <div className="menu-header"> |
| | | <span>菜单名称:{this.props.MenuName}</span> |
| | | <span>菜单参数:{<Paragraph copyable>{this.props.MenuNo}</Paragraph>}</span> |
| | | </div> |
| | | {this.state.treevisible ? <Tree defaultExpandAll showLine={true}> |
| | | {this.getTreeNode(config.funcs)} |
| | | </Tree> : null} |
| | | </Modal> |
| | | <Modal |
| | | title={config.tab ? config.tab.label : ''} |
| | | width={'80vw'} |
| | | maskClosable={false} |
| | | visible={this.state.visible} |
| | | onCancel={this.closeTab} |
| | | footer={[ |
| | | <Button key="close" onClick={this.closeTab}>{this.state.dict['main.close']}</Button> |
| | | ]} |
| | | destroyOnClose |
| | | > |
| | | {config.tab ? <SubTabTable |
| | | SupMenuID={this.props.MenuID} |
| | | MenuID={config.tab.linkTab} |
| | | refreshSupView={this.loadmaindata} |
| | | closeModalView={this.closeTab} |
| | | /> : null} |
| | | </Modal> |
| | | {viewlost ? <NotFount msg={this.state.lostmsg} /> : null} |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | const mapStateToProps = (state) => { |
| | | return { |
| | | menuType: state.editLevel, |
| | | tabviews: state.tabviews, |
| | | refreshTab: state.refreshTab, |
| | | permAction: state.permAction, |
| | | permRoles: state.permRoles, |
| | | dataManager: state.dataManager |
| | | } |
| | | } |
| | | |
| | | const mapDispatchToProps = (dispatch) => { |
| | | return { |
| | | refreshTabView: (refreshTab) => dispatch(refreshTabView(refreshTab)) |
| | | } |
| | | } |
| | | |
| | | export default connect(mapStateToProps, mapDispatchToProps)(NormalTable) |
New file |
| | |
| | | .calendar-page { |
| | | position: relative; |
| | | min-height: calc(100vh - 94px); |
| | | padding-top: 16px; |
| | | padding-bottom: 80px; |
| | | .box404 { |
| | | padding-top: 30px; |
| | | } |
| | | |
| | | .ant-modal-mask { |
| | | position: absolute; |
| | | } |
| | | .ant-modal-wrap { |
| | | position: absolute; |
| | | } |
| | | .action-modal .ant-modal { |
| | | top: 40px; |
| | | max-width: 95%; |
| | | .ant-modal-body { |
| | | max-height: calc(100vh - 265px); |
| | | } |
| | | } |
| | | > .ant-spin { |
| | | position: absolute; |
| | | z-index: 10; |
| | | left: calc(50% - 22px); |
| | | top: calc(50vh - 70px); |
| | | } |
| | | |
| | | .common-table-copy { |
| | | position: fixed; |
| | | z-index: 2; |
| | | bottom: 65px; |
| | | right: 30px; |
| | | width: 40px; |
| | | height: 40px; |
| | | } |
| | | } |
| | | |
| | | .menu-tree-modal { |
| | | .ant-modal-body { |
| | | min-height: 300px; |
| | | .menu-header { |
| | | text-align: center; |
| | | span { |
| | | font-weight: 600; |
| | | margin-right: 20px; |
| | | } |
| | | .ant-typography { |
| | | font-weight: 600; |
| | | display: inline-block; |
| | | } |
| | | } |
| | | .ant-tree li .ant-tree-node-content-wrapper { |
| | | cursor: default; |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | class SubTabModalTable extends Component { |
| | | static propTpyes = { |
| | | type: PropTypes.any, // 类型,calendar需特殊处理 |
| | | BID: PropTypes.string, // 上级数据ID |
| | | BData: PropTypes.any, // 上级数据 |
| | | MenuID: PropTypes.string, // 菜单Id |
| | | SupMenuID: PropTypes.string, // 上级菜单Id |
| | | refreshSupView: PropTypes.any // 刷新上级菜单 |
| | | refreshSupView: PropTypes.any, // 刷新上级菜单 |
| | | closeModalView: PropTypes.any // 关闭模态框 |
| | | } |
| | | |
| | | state = { |
| | |
| | | * @description 获取页面配置信息 |
| | | */ |
| | | async loadconfig () { |
| | | const { permAction } = this.props |
| | | const { permAction, type } = this.props |
| | | |
| | | let param = { |
| | | func: 'sPC_Get_LongParam', |
| | |
| | | } |
| | | |
| | | // 仅支持exec、prompt、pop 三种类型按钮 |
| | | if (type === 'calendar') { |
| | | config.action = config.action.filter(item => ['exec', 'prompt', 'pop', 'tab'].includes(item.OpenType)) |
| | | } else { |
| | | config.action = config.action.filter(item => ['exec', 'prompt', 'pop'].includes(item.OpenType)) |
| | | } |
| | | |
| | | // 权限过滤 |
| | | if (this.props.menuType !== 'HS') { |
| | |
| | | } else if (position === 'view') { |
| | | this.reloadview() |
| | | this.props.refreshSupView() |
| | | } else if (position === 'trigger') { // 日历子表触发标签点击事件 |
| | | this.props.closeModalView && this.props.closeModalView() |
| | | } |
| | | } |
| | | |
| | |
| | | if (!unclose) { |
| | | this.setState({running: false}) |
| | | } |
| | | } else if (type === 'trigger') { // 日历中的新标签页触发事件 |
| | | this.props.refreshdata('trigger') |
| | | } |
| | | } |
| | | |
| | |
| | | setting={setting} |
| | | selectedData={selectedData} |
| | | triggerBtn={this.state.triggerBtn} |
| | | updateStatus={this.updateStatus} |
| | | /> |
| | | ) |
| | | } else if (item.OpenType === 'innerpage' || item.OpenType === 'outerpage') { |
| | |
| | | selectedData: PropTypes.any, // 子表中选择数据 |
| | | setting: PropTypes.any, // 页面通用设置 |
| | | triggerBtn: PropTypes.any, |
| | | updateStatus: PropTypes.any |
| | | } |
| | | |
| | | state = { |
| | |
| | | tabs.splice(index + 1, 0, newtab) |
| | | } |
| | | |
| | | if (this.props.updateStatus) { |
| | | this.props.updateStatus('trigger') |
| | | } |
| | | |
| | | this.props.modifyTabview(tabs) |
| | | } |
| | | |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Select, Radio, Row, Col, Popover, Badge } from 'antd' |
| | | import { Select, Radio, Row, Col, Popover, Badge, Spin } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | // import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | | |
| | | const { Option } = Select |
| | |
| | | static propTpyes = { |
| | | data: PropTypes.any, // 事件数据 |
| | | calendar: PropTypes.any, |
| | | changeDate: PropTypes.func, |
| | | triggerDate: PropTypes.func, |
| | | loading: false |
| | | } |
| | | |
| | |
| | | |
| | | UNSAFE_componentWillReceiveProps(nextProps) { |
| | | if (!is(fromJS(this.props.data), fromJS(nextProps.data))) { |
| | | let datelist = this.mountdata(this.state.datelist, nextProps.data) |
| | | let datelist = this.mountdata(this.state.datelist, nextProps.data || []) |
| | | let monthlist = null |
| | | |
| | | if (this.state.levels.includes('month')) { |
| | |
| | | const { calendar } = this.props |
| | | |
| | | let datalist = [] |
| | | let levels = { |
| | | black: 1, |
| | | red: 2, |
| | | orange: 3, |
| | | yellow: 4, |
| | | green: 5, |
| | | lightgreen: 6, |
| | | cyan: 7, |
| | | blue: 8, |
| | | purple: 9, |
| | | white: 10 |
| | | } |
| | | let levels = { red: 1, orange: 2, yellow: 3, green: 4, cyan: 5, blue: 6, purple: 7, gray: 8 } |
| | | let colors = { red: '#d0021b', orange: '#f5a623', yellow: '#f8e71c', green: '#7ed321', cyan: '#50e3c2', blue: '#1890ff', purple: '#bd10e0', gray: '#9b9b9b' } |
| | | |
| | | data.forEach(item => { |
| | | let startTime = item[calendar.startfield] |
| | |
| | | if (!item[calendar.remarkfield]) return |
| | | |
| | | datalist.push({ |
| | | color: color, |
| | | color: colors[color] || '', |
| | | level: color && levels[color] ? levels[color] : 100, |
| | | remark: item[calendar.remarkfield], |
| | | startMonth: startTime.substr(0, 4) + startTime.substr(5, 2), |
| | |
| | | datalist.sort((a, b) => a.level - b.level) |
| | | |
| | | let styles = [ |
| | | {background: 'black', color: '#ffffff'}, |
| | | {background: 'red', color: '#ffffff'}, |
| | | {background: 'orange', color: '#ffffff'}, |
| | | {background: 'yellow', color: 'rgba(0,0,0,.65)'}, |
| | | {background: 'green', color: '#ffffff'}, |
| | | {background: 'lightgreen', color: 'rgba(0,0,0,.65)'}, |
| | | {background: 'cyan', color: 'rgba(0,0,0,.65)'}, |
| | | {background: 'blue', color: '#ffffff'}, |
| | | {background: 'purple', color: '#ffffff'}, |
| | | {background: 'white', color: 'rgba(0,0,0,.65)'}, |
| | | {background: '#d0021b', color: '#ffffff'}, |
| | | {background: '#f5a623', color: '#ffffff'}, |
| | | {background: '#f8e71c', color: '#ffffff'}, |
| | | {background: '#7ed321', color: '#ffffff'}, |
| | | {background: '#50e3c2', color: '#ffffff'}, |
| | | {background: '#1890ff', color: '#ffffff'}, |
| | | {background: '#bd10e0', color: '#ffffff'}, |
| | | {background: '#9b9b9b', color: '#ffffff'}, |
| | | ] |
| | | |
| | | return datelist.map(month => { |
| | |
| | | month.subData.push(item) |
| | | } |
| | | }) |
| | | if (month.subData[0]) { |
| | | month.style = styles[month.subData[0].level - 1] || null |
| | | } |
| | | month.sublist = month.sublist.map(week => { |
| | | week.sublist = week.sublist.map(day => { |
| | | if (!day) return null |
| | |
| | | } |
| | | |
| | | yearChange = (value) => { |
| | | const { calendar, data } = this.props |
| | | const { levels, selectMonth } = this.state |
| | | let datelist = this.getDateList(value) |
| | | let monthlist = null |
| | |
| | | monthlist = datelist.filter(item => item.month === selectMonth)[0] |
| | | } |
| | | |
| | | if (calendar.refresh !== 'true') { |
| | | datelist = this.mountdata(datelist, data) |
| | | |
| | | this.setState({ selectYear: value, datelist, monthlist }) |
| | | } else { |
| | | this.setState({ selectYear: value, datelist, monthlist }) |
| | | |
| | | if (this.props.changeDate) { |
| | | this.props.changeDate(value) |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | triggerDay = (item) => { |
| | | |
| | | if (this.props.triggerDate) { |
| | | this.props.triggerDate(item) |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { loading } = this.props |
| | | const { level, selectMonth, selectYear, yearlist, levels, datelist, monthlist } = this.state |
| | | const _levelName = {day: '日', month: '月', year: '年'} |
| | | console.log(loading) |
| | | |
| | | return ( |
| | | <div className="mk-calendar"> |
| | | {loading ? <div className="loading-data"><Spin /></div> : null} |
| | | <div className="mk-calendar-control"> |
| | | <Select value={selectYear} onChange={this.yearChange}> |
| | | {yearlist.map(item => (<Option key={item} value={item}>{item}年</Option>))} |
| | |
| | | </div> |
| | | <ul className="content"> |
| | | {d.subData.map((data, index) => ( |
| | | <li key={index} className="message" title={data.remark}> |
| | | <Badge color={data.color} text={data.remark} /> |
| | | <li key={index} className="message"> |
| | | <Badge color={d.style ? (data.color === d.style.background ? '#ffffff' : data.color) : data.color} text={data.remark} /> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | |
| | | {level === 'year' && monthlist ? <Row className="year-calendar"> |
| | | {datelist.map(item => ( |
| | | <Col span={8} key={item.month}> |
| | | <div className="year-wrap"> |
| | | <div className="header"> |
| | | <div className="year-wrap" style={item.style || null} onClick={() => this.triggerDay(item)}> |
| | | <div className="header" style={item.style ? null : {color: '#1890ff'}}> |
| | | {item.label} |
| | | </div> |
| | | <ul className="content"> |
| | | {item.subData.map((data, index) => ( |
| | | <li key={index} className="message" title={data.remark}> |
| | | <Badge color={data.color} text={data.remark} /> |
| | | <li key={index} className="message"> |
| | | <Badge color={item.style ? (data.color === item.style.background ? '#ffffff' : data.color) : data.color} text={`${data.remark}(${data.startTime} ~ ${data.endTime})`}/> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | |
| | | .mk-calendar { |
| | | position: relative; |
| | | width: 100%; |
| | | padding: 20px; |
| | | |
| | | .loading-data { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 20px; |
| | | right: 20px; |
| | | bottom: 0; |
| | | z-index: 2; |
| | | opacity: 0.5; |
| | | background: #ffffff; |
| | | .ant-spin-spinning { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 270px; |
| | | } |
| | | } |
| | | .mk-calendar-control { |
| | | text-align: right; |
| | | .ant-select { |
| | |
| | | .month-wrap { |
| | | cursor: pointer; |
| | | height: 120px; |
| | | width: 100%; |
| | | width: calc(100% - 2px); |
| | | transition: background 0.1s; |
| | | margin-bottom: 2px; |
| | | box-shadow: 0px 0px 1px #f7f7f7; |
| | | .header { |
| | | text-align: center; |
| | | font-size: 16px; |
| | |
| | | } |
| | | .content::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.7); |
| | | background: rgba(255, 255, 255, 0.7); |
| | | } |
| | | .content::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | |
| | | } |
| | | .year-calendar { |
| | | .year-wrap { |
| | | width: calc(100% - 2px); |
| | | cursor: pointer; |
| | | transition: background 0.1s; |
| | | box-shadow: 0px 0px 1px #f7f7f7; |
| | | .header { |
| | | text-align: center; |
| | | font-size: 16px; |
| | | color: #1890ff; |
| | | } |
| | | .content { |
| | | padding: 5px 15px 10px; |
| | | height: 110px; |
| | | overflow-y: auto; |
| | | margin-bottom: 2px; |
| | | .ant-badge-status-text { |
| | | color: inherit; |
| | | } |
| | | .message { |
| | | width: 100%; |
| | | white-space: nowrap; |
| | |
| | | } |
| | | .content::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.7); |
| | | background: rgba(255, 255, 255, 0.7); |
| | | } |
| | | .content::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | |
| | | })( |
| | | <Select onChange={(value, option) => {this.selectChange(item, value, option)}} disabled={item.readonly === 'true'}> |
| | | {calendarColors.map(option => |
| | | <Select.Option key={option.name} style={{background: option.name, color: option.value}} value={option.name}>{option.name}</Select.Option> |
| | | <Select.Option key={option.name} style={{background: option.value, color: '#ffffff'}} value={option.name}>{option.name}</Select.Option> |
| | | )} |
| | | </Select> |
| | | )} |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Select, Checkbox } from 'antd' |
| | | import { Form, Row, Col, Select, Checkbox, Tooltip, Icon, Radio } from 'antd' |
| | | import './index.scss' |
| | | |
| | | class MainTab extends Component { |
| | |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={24}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="开启后,使用系统函数时会自动替换数据源及自定义脚本中的calendarDate与calendarDate1,其值分别为选择年份的开始和结束时间,使用自定义函数时,会增加calendarDate传参,其值为选择年份。"> |
| | | <Icon type="question-circle" /> |
| | | 数据刷新 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('refresh', { |
| | | initialValue: calendar.refresh || 'false', |
| | | })( |
| | | <Radio.Group> |
| | | <Radio key="true" value="true">开启</Radio> |
| | | <Radio key="false" value="false">关闭</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | </Row> |
| | | </Form> |
| | | ) |
| | |
| | | position: absolute; |
| | | right: 0; |
| | | top: 0; |
| | | z-index: 2; |
| | | >.anticon-edit { |
| | | font-size: 18px; |
| | | padding: 5px; |
| | |
| | | }) |
| | | } |
| | | |
| | | if (_config.type === 'user') { |
| | | if (_config.tab) { |
| | | _config.tab.linkTab = '' |
| | | } |
| | | } |
| | | |
| | | this.setState({ |
| | | openEdition: menu.open_edition || '', |
| | | optionLibs: optionLibs, |
| | |
| | | {color: 'orange', remark: '系统异常,请及时处理!'}, |
| | | {color: 'yellow', remark: '您的订单异常,请联系客服!'}, |
| | | {color: 'green', remark: '您的订单已完成。'}, |
| | | {color: 'lightgreen', remark: '消息已发送,请及时查收。'}, |
| | | {color: 'cyan', remark: '您有一条新的消息。'}, |
| | | {color: 'blue', remark: '任务未完成,请注意后续工作。'}, |
| | | {color: 'purple', remark: '您有新的任务等待处理!'} |
| | | {color: 'purple', remark: '您有新的任务等待处理!'}, |
| | | {color: 'gray', remark: '您有一封未读邮件。'} |
| | | ] |
| | | let mockdata = [] |
| | | |
| | |
| | | this.menuformRef.handleConfirm().then(res => { |
| | | if (config.isAdd) { |
| | | config.search = config.search.filter(item => !item.origin) |
| | | } |
| | | |
| | | if (config.type === 'user') { // 使用已有菜单时,默认添加关联标签id |
| | | if (config.tab && !config.tab.linkTab) { |
| | | config.tab.linkTab = Utils.getuuid() |
| | | } |
| | | } |
| | | |
| | | let _LongParam = '' |
| | |
| | | */ |
| | | verifyconfig = (config) => { |
| | | let hasKey = false |
| | | let chartcols = [] |
| | | let cols = [] |
| | | config.columns.forEach(col => { |
| | | if (col.field) { |
| | | chartcols.push(col.field) |
| | | cols.push(col.field) |
| | | } |
| | | if (config.setting.primaryKey === col.field) { |
| | | hasKey = true |
| | | } |
| | | }) |
| | | |
| | | let calvaild = true |
| | | if (!cols.includes(config.calendar.startfield)) { |
| | | calvaild = false |
| | | } else if (!cols.includes(config.calendar.endfield)) { |
| | | calvaild = false |
| | | } else if (!cols.includes(config.calendar.colorfield)) { |
| | | calvaild = false |
| | | } else if (!cols.includes(config.calendar.remarkfield)) { |
| | | calvaild = false |
| | | } |
| | | |
| | | if (config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.default !== 'false' && !config.setting.dataresource) { |
| | | return '菜单尚未设置数据源,不可启用!' |
| | |
| | | return '菜单尚未设置主键,不可启用!' |
| | | } else if (!hasKey) { |
| | | return '显示列中不存在主键字段,不可启用!' |
| | | } else if (!calvaild) { |
| | | return '日历关联字段未设置,不可启用!' |
| | | } else { |
| | | return true |
| | | } |
| | |
| | | const { activeKey, config, tabviews, mockdata, mockloading } = this.state |
| | | |
| | | return ( |
| | | <div className="model-subtable-board"> |
| | | <div className="model-calendar-board"> |
| | | <DndProvider backend={HTML5Backend}> |
| | | {/* 工具栏 */} |
| | | <div className="tools"> |
| | |
| | | .model-subtable-board { |
| | | .model-calendar-board { |
| | | position: fixed; |
| | | z-index: 1070; |
| | | padding-top: 48px; |
| | |
| | | } |
| | | } |
| | | } |
| | | .config-btn { |
| | | position: relative; |
| | | |
| | | .config-btn-title { |
| | | margin-top: 20px; |
| | | margin-bottom: 10px; |
| | | color: #1890ff; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | } |
| | | } |
| | | .ant-list { |
| | | margin-top: 20px; |
| | | .ant-list-item { |
| | |
| | | position: relative; |
| | | padding: 0; |
| | | |
| | | .chart-view { |
| | | margin-bottom: 70px; |
| | | |
| | | .chart-title { |
| | | position: relative; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | margin: 0 20px; |
| | | padding: 10px 5px 5px; |
| | | } |
| | | } |
| | | > .anticon-setting { |
| | | position: absolute; |
| | | font-size: 18px; |
| | |
| | | startfield: '', |
| | | endfield: '', |
| | | colorfield: '', |
| | | remarkfield: '' |
| | | remarkfield: '', |
| | | refresh: 'false' |
| | | }, |
| | | search: [ |
| | | { |
| | |
| | | .model-calendar-tab { |
| | | position: absolute; |
| | | top: 0; |
| | | z-index: 2; |
| | | >.anticon-plus { |
| | | position: absolute; |
| | | font-size: 18px; |
| | |
| | | </Col> |
| | | <Col span={24} className="sqlfield"> |
| | | <Form.Item label={'可用字段'}> |
| | | id, bid, loginuid, sessionuid, userid, appkey, time_id{usefulFields ? ', ' + usefulFields : ''} |
| | | id, bid, loginuid, sessionuid, userid, appkey, time_id, calendarDate, calendarDate1{usefulFields ? ', ' + usefulFields : ''} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={10}> |
| | |
| | | {getFieldDecorator('primaryKey', { |
| | | initialValue: setting.primaryKey || '' |
| | | })( |
| | | <Select onChange={(value) => {this.selectChange('primaryKey', value)}}> |
| | | <Select> |
| | | {columns.map((option, i) => |
| | | <Select.Option key={i} value={option.value}> |
| | | {option.text} |
| | | <Select.Option key={i} value={option.field}> |
| | | {option.label} |
| | | </Select.Option> |
| | | )} |
| | | </Select> |
| | |
| | | }] |
| | | |
| | | export const calendarColors = [ |
| | | {name: 'black', value: '#ffffff'}, |
| | | {name: 'red', value: '#ffffff'}, |
| | | {name: 'orange', value: '#ffffff'}, |
| | | {name: 'yellow', value: 'rgba(0,0,0,.65)'}, |
| | | {name: 'green', value: '#ffffff'}, |
| | | {name: 'lightgreen', value: 'rgba(0,0,0,.65)'}, |
| | | {name: 'cyan', value: 'rgba(0,0,0,.65)'}, |
| | | {name: 'blue', value: '#ffffff'}, |
| | | {name: 'purple', value: '#ffffff'}, |
| | | {name: 'white', value: 'rgba(0,0,0,.65)'} |
| | | {name: 'red', value: '#d0021b'}, |
| | | {name: 'orange', value: '#f5a623'}, |
| | | {name: 'yellow', value: '#f8e71c'}, |
| | | {name: 'green', value: '#7ed321'}, |
| | | {name: 'cyan', value: '#50e3c2'}, |
| | | {name: 'blue', value: '#1890ff'}, |
| | | {name: 'purple', value: '#bd10e0'}, |
| | | {name: 'gray', value: '#9b9b9b'}, |
| | | ] |
| | | |
| | | // 显示列标记色系 |