rcs5.0 commit

This commit is contained in:
wangxinfei
2025-05-19 17:29:51 +08:00
commit e8af49b0f5
720 changed files with 175022 additions and 0 deletions
+570
View File
@@ -0,0 +1,570 @@
import request from '@/http/request.js';
import {
callGetFile,
} from '@/http/api.call';
// 使用示例: const res = await this.$apis.pubQueryComboxData(data)
// 交易簿记/ 现金流预览
export const getdcsPreviewCashflows = (data) => {
return request({
url: 'dcs/flow/previewCashflows.action',
method: 'post',
data,
});
};
// 交易簿记/ 新增获取id
export const getdcsDealNo = (data) => {
return request({
url: 'dcs/dcs/getDealNo.action',
method: 'post',
data,
});
};
// 交易簿记/ 操作风险
export const getdcsdealActionFlow = (data) => {
return request({
url: 'dcs/flow/dealActionFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 快速查询列表
export const getdealQueryqueryPage = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryPage.action',
method: 'post',
data,
});
};
// 交易簿记/ 现金流 现金流
export const getdcsQueryCashFlowList = (data) => {
return request({
url: 'dcs/dcs/queryCashFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 现金流 定盘
export const getdcsQueryObserveList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryObserveList.action',
method: 'post',
data,
});
};
// 交易簿记/ 提交
export const handledcsdealActionFlow = (data) => {
return request({
url: 'dcs/flow/dealActionFlow.action',
method: 'post',
data,
});
};
// 交易簿记/ 是否节假日
export const getdcsisHolidayByUnderlying = (data) => {
return request({
url: 'dcs/dcs/isHolidayByUnderlying.action',
method: 'post',
data,
});
};
// 交易簿记/ 按钮权限
export const getdcsdoGetFolderAuth = (data) => {
return request({
url: 'dcs/dcs/doGetFolderAuth.action',
method: 'post',
data,
});
};
// 交易簿记/账户信息
export const getDCSqueryCptyName = (data) => {
return request({
url: 'dcs/dcs/queryCptyName.action',
method: 'post',
data,
});
};
// 交易簿记/交易对手
export const getDCSqueryFolderById = (data) => {
return request({
url: 'dcs/dcs/queryFolderById.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDCSdoEvaluation = (data) => {
return request({
url: 'dcs/dcs/doEvaluation.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDCSgetSystemDate = (data) => {
return request({
url: 'dcs/dcs/getSystemDate.action',
method: 'post',
data,
});
};
// 交易簿记
export const querySettle = (data) => {
return request({
url: 'settle6-web/query_settle.action',
method: 'post',
data,
});
};
// 交易簿记
export const getdealQueryQueryList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryList.action',
method: 'post',
data,
});
};
// 交易簿记
export const getDcsOptions = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data,
});
};
// 交易簿记 获取即期汇率
export const getdcsPairInfo = (data) => {
return request({
url: 'dcs/dcs/getPairInfo.action',
method: 'post',
data,
});
};
// 交易簿记 获取起息日
export const getdcsValueDate = (data) => {
return request({
url: 'dcs/dcs/getValueDate.action',
method: 'post',
data,
});
};
// 参数审批-统计接口
export const getParamsStaList = (data) => {
return request({
url: 'eflow/flow/doQueryNumber.action',
method: 'post',
data,
});
};
// 参数审批-待处理接口
export const getParamsList = (data) => {
return request({
url: 'eflow/flow/doQueryPageWaiting.action',
method: 'post',
data,
});
};
// 参数审批-已处理接口
export const getFinishList = (data) => {
return request({
url: 'eflow/flow/doQueryPageFinish.action',
method: 'post',
data,
});
};
// 参数审批-已拒绝接口
export const getRefuseList = (data) => {
return request({
url: 'eflow/flow/doQueryPageRefuse.action',
method: 'post',
data,
});
};
// 参数审批-我发起接口
export const getInitiateList = (data) => {
return request({
url: 'eflow/flow/doQueryPageMine.action',
method: 'post',
data,
});
};
// 参数审批-批量审核
export const batchCheck = (data) => {
return request({
url: 'eflow/flow/approveBatch.action',
method: 'post',
data,
});
};
// 参数审批-审批状态字典
export const getApproveData = (data) => {
return request({
url: 'eflow/flow/queryComboxData.action',
method: 'post',
data,
});
};
// 参数审批-获取流程操作按钮
export const getUserFlowOperations = (data) => {
return request({
url: 'eflow/flow/getUserFlowOperations.action',
method: 'post',
data,
});
};
// 参数审批-获取审批流程日志
export const getFlowLogBySerialNoRepeat = (data) => {
return request({
url: 'eflow/flow/getFlowLogBySerialNoRepeat.action',
method: 'post',
data,
});
};
// 参数审批-获取变更数据
export const getFlowCompareData = (data) => {
return request({
url: 'pub/pub/eflowCompareData.action', // ?dealNo=174194761864137
method: 'post',
data,
});
};
// 参数审批-退回发起下拉获取
export const getBackList = (data) => {
return request({
url: 'eflow/flow/queryComboxData.action',
method: 'post',
data,
});
};
// 参数审批-退回发起提交
export const backSubmit = (data) => {
return request({
url: 'eflow/flow/approve.action',
method: 'post',
data,
});
};
// 存续期事件管理 列表查询
export const getEventList = (data) => {
return request({
url: 'dcs/dcs/queryPage.action',
method: 'post',
data,
});
};
// 存续期事件管理 撤销
export const batchRevoke = (data) => {
return request({
url: '',
method: 'post',
data,
});
};
// 发送异常管理 补发
export const batchSendAgain = (data) => {
return request({
url: 'dcs/pub/sendExceptionReissue.action',
method: 'post',
data,
});
};
// 发送异常管理 报文内容保存
export const messageSave = (data) => {
return request({
url: 'dcs/dcs/doUpdate.action',
method: 'post',
data,
});
};
// queryParam.moduleName:"pubSendExceptionManager","queryParam.domain":"{"id":"20250327_1df210eb-a865-4a6b-accf-8db487d2508c","messageContent":{}}
// 获取数据源-通用
export const queryComboxData = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data: data,
});
};
// 获取数据源-债券检索
export const queryBondList = (data) => {
return request({
url: 'dcs/dcs/queryBondList.action',
method: 'post',
data: data,
});
};
// 获取数据源-交易对手
export const queryCptyPage = (data) => {
return request({
url: 'dcs/dcs/queryCptyPage.action',
method: 'post',
data: data,
});
};
// 获取数据源-账户/账户组
export const queryFolderQueryAuthList = (data) => {
return request({
url: 'dcs/dcs/queryFolderQueryAuthList.action',
method: 'post',
data: data,
});
};
// 自定义交易查询接口
export const dcsQueryPage = (data) => {
return request({
url: 'dcs/dcs/queryPage.action',
method: 'post',
data: data,
});
};
// 自定义交易查询结果-产品表头
export const queryFieldByProduct = (data) => {
return request({
url: 'dcs/dcs/queryFieldByProduct.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-获取自定义查询组合
export const queryList = (data) => {
return request({
url: 'dcs/dcs/queryList.action',
method: 'post',
data: data,
});
};
//
export const pubqueryList = (data) => {
return request({
url: 'pub/pub/queryList.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-保存自定义查询组合
export const doSave = (data) => {
return request({
url: 'dcs/dcs/doSave.action',
method: 'post',
data: data,
});
};
// 自定义交易查询-删除自定义查询组合
export const doDelete = (data) => {
return request({
url: 'dcs/dcs/doDelete.action',
method: 'post',
data: data,
});
};
// 自定义交易查询结果-账户详情
export const getFolderInfo = (data) => {
return request({
url: 'dcs/dcs/getFolderInfo.action',
method: 'post',
data: data,
});
};
// 导出
export const exportData = (data) => {
return request({
url: 'dcs/baseQuery/exportAll.action',
method: 'post',
// headers: { 'Content-Type': 'multipart/form-data' },
data,
});
};
// 下载模板
export const downLoadTemplate = callGetFile('pub/baseData/downloadTemplate.action');
// export const downLoadTemplate = (data) => {
// return axios.request({
// url: 'pub/baseData/downloadTemplate.action',
// method: 'get',
// data,
// });
// };
// 导入校验
export const importCheck = (data) => {
return request({
url: 'pub/baseData/importCheck.action',
method: 'post',
// headers: { 'Content-Type': 'multipart/form-data' },
data,
});
};
// 确认导入
export const importData = (data) => {
return request({
url: 'pub/baseData/importData.action',
method: 'post',
data,
});
};
// 查询导入结果
export const getProcess = (data) => {
return request({
url: 'pub/baseData/queryResult.action',
method: 'post',
data,
});
};
export const getPosOptions = (data) => {
return request({
url: 'pos/pos/queryComboxData.action',
method: 'post',
data,
});
};
// 外汇账户明细字典
export const getForList = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action?codifierGrpCodes=static_currencies,FolderStatus,AccountingSection,HomeType',
method: 'get',
data,
});
};
// 自定义交易查询结果-账户详情
export const queryDealOperateLog = (data) => {
return request({
url: 'dcs/dcs/queryDealOperateLog.action',
method: 'post',
data: data,
});
};
// 交易模块查询历史版本
export const getCompareVersionLog = (data) => {
return request({
url: 'dcs/getCompareVersionLog.action',
method: 'get',
data,
});
};
// 公共模块查询历史版本详细信息
export const compareVersionLog = (data) => {
return request({
url: 'dcs/compareVersionLog.action',
method: 'post',
data,
});
};
// 获取历史版本版本号列表
export const versionsLogCombox = (data) => {
return request({
url: 'dcs/versionsLogCombox.action',
method: 'post',
data,
});
};
// 获取历史头寸配置
export const getOneQueryComponent = (data) => {
return request({
url: 'pos/pub/getOneQueryComponent.action',
method: 'post',
data,
});
};
// 获取登录账户
export const getUserInfo = (data) => {
return request({
url: 'pos/pos/getUserInfo.action',
method: 'post',
data,
});
};
// 获取登录用户信息
export const findPreferenceDtoByUserIdAndType = (data) => {
return request({
url: 'pos/pos/findPreferenceDtoByUserIdAndType.action',
method: 'post',
data,
});
};
// 历史头寸获取时间
export const getPosSystemDate = (data) => {
return request({
url: 'pos/baseRcs/getSystemDate.action',
method: 'post',
data,
});
};
// 交易主要信息
export const getQueryMainInfo = (data) => {
return request({
url: 'dcs/dcs/queryMainInfo.action',
method: 'post',
data,
});
};
// 交易派生信息
export const getQueryDeriveInfo = (data) => {
return request({
url: 'dcs/dcs/queryDeriveInfo.action',
method: 'post',
data,
});
};
// 交易审批信息
export const getQueryAuditInfo = (data) => {
return request({
url: 'dcs/dcs/queryAuditInfo.action',
method: 'post',
data,
});
};
// 交易收据模板
export const queryDealReceipt = (data) => {
return request({
url: 'dcs/dcs/queryDealReceipt.action',
method: 'post',
data,
});
};
// 交易跟踪记录
export const queryDealTrace = (data) => {
return request({
url: 'dcs/dcs/queryDealTrace.action',
method: 'post',
data,
});
};
// 交易收据数据
export const queryDealQueryList = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryList.action',
method: 'post',
data,
});
};
+21
View File
@@ -0,0 +1,21 @@
// 导入所有模块api
const modules = require.context('./', true, /.js/);
const apis = {};
modules.keys().forEach(item => {
if (item !== './index.js') {
let api = modules(item);
if (api.default) {
api = { ...api, ...api.default };
delete api.default;
}
for (const key in api) {
if (apis[key]) { // 请求方法名不能重复
throw new Error(`error: api method repeat!!! method---->${key}`);
} else {
apis[key] = api[key];
}
}
}
});
export default apis;
+118
View File
@@ -0,0 +1,118 @@
import request from '@/http/request.js';
/**
* 评级信息列表获取
* @returns
*/
export const msdQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action',
method: 'post',
data,
});
};
/** 评级目标 */
export const msdQueryComboxData = (data) => {
return request({
url: 'mds/baseRcs/queryComboxData.action',
method: 'post',
data,
});
};
/** 交易对手评级 */
export const mdsFindAllCptysi18n = () => {
return request({
url: 'mds/sdscounterparty/findAllCptysi18n.action',
method: 'post',
});
};
/** 发行人评级 */
export const mdsFindAllIssuerCptysi18n = () => {
return request({
url: 'mds/sdscounterparty/findAllIssuerCptysi18n.action',
method: 'post',
});
};
/** 债券评级 */
export const mdsFindAllbonds = () => {
return request({
url: 'mds/sdsbonds/findAllbonds.action',
method: 'post',
});
};
/** 国家评级 */
export const mdsFindAllCountries = () => {
return request({
url: 'mds/sdsthirdparty/findAllCountries.action',
method: 'post',
});
};
/** 担保人评级 */
export const mdsFindAllGuarantees = () => {
return request({
url: 'mds/sdscounterparty/findAllGuarantees.action',
method: 'post',
});
};
/** 评级机构 */
export const msdFindRatingAgenciesByContainsTermRating = () => {
return request({
url: 'mds/sdsrating/findRatingAgenciesByContainsTermRating.action',
method: 'post',
});
};
export const msdFindRatingByAgencyIdAndTerm = (data) => {
return request({
url: 'mds/sdsrating/findRatingByAgencyIdAndTerm.action',
method: 'post',
data,
});
};
export const msdHistoryQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action?queryParam.moduleName=mdsTargetRatingsHistory',
method: 'post',
data,
});
};
// 数据集查询
export const msdFindAllDataSet = () => {
return request({
url: 'mds/mds/findAllDataSet.action',
method: 'post',
});
};
// 数据类型
export const msdQueryComboxDataAction = (data) => {
return request({
url: `mds/baseRcs/queryComboxData.action?codifierGrpCodes=${data}`,
method: 'post',
});
};
// 数据集管理列表
export const msdBaseQueryPage = (data) => {
return request({
url: 'mds/baseData/queryPage.action?queryParam.moduleName=mdsDataRicSetService',
method: 'post',
data,
});
};
// 数据源
export const mdsFindAllDataSource = () => {
return request({
url: 'mds/mds/findAllDataSource.action',
method: 'post',
});
};
+220
View File
@@ -0,0 +1,220 @@
import request from '@/http/request.js';
// 获取数据源-通用
export const pmsQueryComboxData = (data) => {
return request({
url: 'dcs/dcs/queryComboxData.action',
method: 'post',
data: data
})
}
// 查询数据源PMS服务
export const queryComboxDataPMS = (data) => {
return request({
url: 'pms/baseRcs/queryComboxData.action',
method: 'post',
data: data
})
}
// 获取系统日期
export const getSystemDate = (data) => {
return request({
url: 'pub/desktop/getSystemDate.action',
method: 'post',
data
})
}
// pms服务获取系统日期
export const getSystemDatePMS = (data) => {
return request({
url: 'pms/getSystemDate.action',
method: 'post',
data
})
}
// 期权计算器-获取日期
export const getValueDate = (data) => {
return request({
url: 'dcs/dcs/getValueDate.action',
method: 'post',
data
})
}
// pms服务获取日期
export const getValueDatePMS = (data) => {
return request({
url: 'pms/getValueDate.action',
method: 'post',
data
})
}
// 期权计算器-获取日期间隔
export const getbetweenDays = (data) => {
return request({
url: 'dcs/dcs/getbetweenDays.action',
method: 'post',
data
})
}
// pms服务查询日期间隔
export const getbetweenDaysPMS = (data) => {
return request({
url: 'pms/getbetweenDays.action',
method: 'post',
data
})
}
// 期权计算器-获取金额
export const getPairInfo = (data) => {
return request({
url: 'dcs/dcs/getPairInfo.action',
method: 'post',
data
})
}
// pms服务查询金额
export const getPairInfoPMS = (data) => {
return request({
url: 'pms/getPairInfo.action',
method: 'post',
data
})
}
// 期权计算器-获取QuantoPairs
export const getQuantoPairs = (data) => {
return request({
url: 'dcs/dcs/getQuantoPairs.action',
method: 'post',
data
})
}
// 期权计算器-获取Model
export const getModelByParam = (data) => {
return request({
url: 'pms/getModelByParam.action',
method: 'post',
data
})
}
// 期权计算器-获取市场数据
export const findMarketInfoForAnalysis = (data) => {
return request({
url: 'mds/mds/findMarketInfoForAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-获取市场价格
export const findMarketPriceForValAnalysis = (data) => {
return request({
url: 'mds/findMarketPriceForValAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-保存市场价格
export const saveMarketPriceForValAnalysis = (data) => {
return request({
url: 'mds/saveMarketPriceForValAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-估值
export const simulationValuationAnalysis = (data) => {
return request({
url: 'mds/simulationValuationAnalysis.action',
method: 'post',
data
})
}
// 期权计算器-试算
export const simulateDealWithVlParam = (data) => {
return request({
url: 'mds/simulateDealWithVlParam.action',
method: 'post',
data
})
}
// 期权计算器-获取定价列表
export const createObs = (data) => {
return request({
url: 'pms/createObs.action',
method: 'post',
data
})
}
// 期权计算器-获取执行价
export const getPoints = (data) => {
return request({
url: 'dcs/dcs/getPoints.action',
method: 'post',
data
})
}
// pms服务查询执行价
export const getPointsPMS = (data) => {
return request({
url: 'pms/getForwardRate.action',
method: 'post',
data
})
}
// 逐笔估值结果查询-获取数据源
export const baseRcsQueryComboxData = (data) => {
return request({
url: 'pms/baseRcs/queryComboxData.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-获取列表
export const pmsQueryPage = (data) => {
return request({
url: 'pms/pmsone/queryPage.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-重估值
export const reDoCalcFont = (data) => {
return request({
url: 'pms/pms/reDoCalcFont.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
// 逐笔估值结果查询-查看估值中间数据
export const pmsFindPmsResultDetail = (data) => {
return request({
url: 'pms/pmsFindPmsResultDetailNew.action',
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data
})
}
+59
View File
@@ -0,0 +1,59 @@
import request from '@/http/request.js';
import { callPostFormFile, callPostAll, callPostFile } from '@/http/api.call';
// 外汇即期单货币头寸
export const getForeignCurrencyList = (data) => {
return request({
url: 'pos/equery.action',
method: 'post',
data,
});
};
// 导出
export const exportForData = callPostFormFile('/pos/equery.action');
// pv01头寸
export const getPv01DataList = (data) => {
return request({
url: 'pos/pos/pv01DataQuery.action',
method: 'post',
data,
});
};
// 外汇现金流查询
export const getTtCashFlowList = (data) => {
return request({
url: 'pos/pos/queryTtCashFlow.action',
method: 'post',
data,
});
};
// 期限列设置
export const queryTerm = (data) => {
return request({
url: 'pos/pos/queryTerm.action',
method: 'post',
data,
});
};
// 获取现金流期限列设置
export const findPreferenceDtoByUserId = (data) => {
return request({
url: 'pos/pos/findPreferenceDtoByUserIdAndType.action',
method: 'post',
data,
});
};
// 保存期限列设置
export const updatePreferenceDto = (data) => {
return request({
url: 'pos/pos/updatePreferenceDto.action',
method: 'post',
data,
});
};
+103
View File
@@ -0,0 +1,103 @@
import request from '@/http/request.js';
// 使用示例: const res = await this.$apis.pubQueryComboxData(data)
// 获取数据源-公共
export const pubQueryComboxData = (data) => {
return request({
url: 'pub/pub/queryComboxData.action',
method: 'post',
data,
});
};
// 货币-查询接口
export const queryPage = (data) => {
return request({
url: 'pub/pub/queryPage.action',
method: 'post',
data,
});
};
// 公共模块查询历史版本
export const getCompareVersion = (data) => {
return request({
url: 'pub/pub/getCompareVersion.action',
method: 'get',
data,
});
};
// 公共模块查询历史版本详细信息
export const compare = (data) => {
return request({
url: 'pub/compare.action',
method: 'post',
data,
});
};
// 获取历史版本版本号列表
export const versionsCombox = (data) => {
return request({
url: 'pub/pub/versionsCombox.action',
method: 'post',
data,
});
};
// 货币查询id
export const findStaticDataId = (data) => {
return request({
url: 'pub/sdsthirdparty/findStaticDataId.action',
method: 'post',
data,
});
};
// 节假日查询
export const queryAll = (data) => {
return request({
url: 'pub/pub/queryAll.action',
method: 'post',
data,
});
};
// 公共新增接口
export const pubDoSave = (data) => {
return request({
url: 'pub/pub/doSave.action',
method: 'post',
data,
});
};
// 公共编辑接口
export const pubDoUpdate = (data) => {
return request({
url: 'pub/pub/doUpdate.action',
method: 'post',
data,
});
};
// 接入数据管理-左侧树形数据
export const getPacketTree = (data) => {
return request({
url: 'pub/pub/getPacketTree.action',
method: 'post',
data,
});
};
// 获取数据源-交易对手
export const queryCptyPage1 = (data) => {
return request({
url: 'dcs/dcs/queryCptyPage.action',
method: 'post',
data: data,
});
};
+198
View File
@@ -0,0 +1,198 @@
import request from '@/http/request.js';
// 消息提醒获取数据
export const queryNormalMessageList = (data) => {
return request({
url: 'pub/desktop/queryNormalMessageList.action',
method: 'post',
data,
});
};
// 获取异常消息处理
export const queryErrorMessageList = (data) => {
return request({
url: 'pub/desktop/queryErrorMessageList.action',
method: 'post',
data,
});
};
// 获取日成交交易table数据
export const getDailyTradeQuery = (data) => {
return request({
url: 'dcs/dailyTradeQuery.action',
method: 'post',
data,
});
};
// 获取风险头寸图表数据
export const queryRiskPositionByType = (data) => {
return request({
url: 'rsk-new/rsk/queryRiskPositionByType.action',
method: 'post',
data,
});
};
// 获取市场风险图表数据
export const getMarketRiskChart = (data) => {
return request({
url: 'pub/desktop/getMarketRiskChart',
method: 'post',
data,
});
};
// 获取信用额度图表数据
export const getCreditLimitChart = (data) => {
return request({
url: 'pub/desktop/getCreditLimitChart',
method: 'post',
data,
});
};
// 获取授权占比图表数据
export const getEmpowerChart = (data) => {
return request({
url: 'pub/desktop/getEmpowerChart',
method: 'post',
data,
});
};
// 获取市场数据货币对价格
export const queryPriceList = (data) => {
return request({
url: 'mds/desktop/queryPriceList.action',
method: 'post',
data,
});
};
// 获取货币对对应的历史数据
export const queryHistoryPriceList = (data) => {
return request({
url: 'mds/hisprice/client/desktop/queryHistoryPriceList.action',
method: 'post',
data,
});
};
// 获取损益变动图表数据
export const queryPlByType = (data) => {
return request({
url: 'rsk-new/rsk/queryPlByType.action',
method: 'post',
data,
});
};
// 获取账户列表数据
export const queryAllFolderInfo = (data) => {
return request({
url: 'pub/desktop/getFolderTree.action',
method: 'post',
data,
});
};
// 获取损益货币
export const getFolderPlCcy = (data) => {
return request({
url: 'pub/desktop/getFolderPlCcy.action',
method: 'post',
data,
});
};
// 获取资产情况表格数据
export const queryPlChartByType = (data) => {
return request({
url: 'pos/queryPlChartByType.action',
method: 'post',
data,
});
};
// 获取资产情况期限数据
export const queryTermCash = (data) => {
return request({
url: 'dcs/queryCashFlowSumAmount.action',
method: 'post',
data,
});
};
// 获取超限事件表格数据
export const getOverEventChart = (data) => {
return request({
url: 'pub/desktop/queryEventList.action',
method: 'post',
data,
});
};
// 获取交易审批table数据
export const queryCommunicationMessage = (data) => {
return request({
url: 'pub/desktop/queryCommunicationMessage.action',
method: 'post',
data,
});
};
// 获取结算发报table数据
export const queryPaymentFlowProcessList = (data) => {
return request({
url: 'settle6-web/desktop/queryPaymentFlowProcessList.action',
method: 'post',
data,
});
};
// 获取收付审批列表
export const queryPaymentFlowAuditList = (data) => {
return request({
url: 'settle6-web/desktop/queryPaymentFlowAuditList.action',
method: 'post',
data,
});
};
// 获取接口通讯列表
export const getApiStatus = (data) => {
return request({
url: 'settle6-web/desktop/getApiStatus.action',
method: 'post',
data,
});
};
// 获取当日全量数据
export const queryDealAuditNum = (data) => {
return request({
url: 'settle6-web/desktop/queryDealAuditNum.action',
method: 'post',
data,
});
};
// 获取机构
export const querySiteList = (data) => {
return request({
url: 'pub/desktop/querySiteList.action',
method: 'post',
data,
});
};
// 日成交交易
export const queryDealPage = (data) => {
return request({
url: 'dcs/dcs/dealQuery/queryPage.action',
method: 'post',
data,
});
};
+539
View File
@@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
File diff suppressed because it is too large Load Diff
+297
View File
@@ -0,0 +1,297 @@
@font-face {
font-family: "iconfont"; /* Project id 4894712 */
/* Color fonts */
src:
url('iconfont.woff2?t=1746004916794') format('woff2'),
url('iconfont.woff?t=1746004916794') format('woff'),
url('iconfont.ttf?t=1746004916794') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-copy:before {
content: "\e79e";
}
.icon-email:before {
content: "\e78a";
}
.icon-calendar:before {
content: "\e7ed";
}
.icon-folder-add:before {
content: "\e80d";
}
.icon-folder:before {
content: "\e7f9";
}
.icon-layers:before {
content: "\e83c";
}
.icon-dollar:before {
content: "\e8b6";
}
.icon-monitor:before {
content: "\e985";
}
.icon-link1:before {
content: "\e789";
}
.icon-information-query:before {
content: "\e90b";
}
.icon-batch-search:before {
content: "\e977";
}
.icon-a-marketrisk:before {
content: "\e72f";
}
.icon-trending-up:before {
content: "\e7ae";
}
.icon-trending-down:before {
content: "\e7a9";
}
.icon-liedingzhi:before {
content: "\e787";
}
.icon-research:before {
content: "\e8b2";
}
.icon-bank-card-fill:before {
content: "\e9c6";
}
.icon-fund-fill:before {
content: "\e9b4";
}
.icon-term-exposure-fill:before {
content: "\e994";
}
.icon-bank-card:before {
content: "\e7e5";
}
.icon-date-time:before {
content: "\e7ef";
}
.icon-doc-edit:before {
content: "\e80c";
}
.icon-chart-combo:before {
content: "\e886";
}
.icon-account:before {
content: "\e8c4";
}
.icon-bank:before {
content: "\e8bd";
}
.icon-trend1:before {
content: "\e8b9";
}
.icon-credit-risk:before {
content: "\e98c";
}
.icon-market-risk:before {
content: "\e98a";
}
.icon-operational-risk:before {
content: "\e988";
}
.icon-chaxunguanli:before {
content: "\e783";
}
.icon-toucunguanli:before {
content: "\e784";
}
.icon-jisuangongjv:before {
content: "\e786";
}
.icon-home:before {
content: "\e731";
}
.icon-refresh1:before {
content: "\e72c";
}
.icon-delete:before {
content: "\e78c";
}
.icon-filter:before {
content: "\e790";
}
.icon-save:before {
content: "\e785";
}
.icon-search:before {
content: "\e788";
}
.icon-user1:before {
content: "\e7d9";
}
.icon-batch-failure:before {
content: "\e96f";
}
.icon-components:before {
content: "\e965";
}
.icon-application1-fill:before {
content: "\e9cd";
}
.icon-edit-fill:before {
content: "\e9bd";
}
.icon-home-fill:before {
content: "\e9ba";
}
.icon-rmb-fill:before {
content: "\e9a5";
}
.icon-parameter-fill:before {
content: "\e99f";
}
.icon-yijujue:before {
content: "\e781";
}
.icon-yitongguo:before {
content: "\e780";
}
.icon-daishenpi:before {
content: "\e782";
}
.icon-yituihui:before {
content: "\e77f";
}
.icon-more2:before {
content: "\e729";
}
.icon-remind:before {
content: "\e712";
}
.icon-add:before {
content: "\e79f";
}
.icon-double_right:before {
content: "\e7d0";
}
.icon-double-left:before {
content: "\e7d6";
}
.icon-down:before {
content: "\e7cb";
}
.icon-down1:before {
content: "\e7bd";
}
.icon-left1:before {
content: "\e7c6";
}
.icon-left:before {
content: "\e7a8";
}
.icon-right:before {
content: "\e7c1";
}
.icon-right1:before {
content: "\e7b8";
}
.icon-attention:before {
content: "\e867";
}
.icon-fail:before {
content: "\e868";
}
.icon-help:before {
content: "\e869";
}
.icon-success:before {
content: "\e86b";
}
.icon-caution:before {
content: "\e86c";
}
.icon-info:before {
content: "\e86d";
}
.icon-EUR:before {
content: "\e633";
}
.icon-meiguoguoqi:before {
content: "\e610";
}
.icon-zhongguoguoqi:before {
content: "\e632";
}
File diff suppressed because one or more lines are too long
+499
View File
@@ -0,0 +1,499 @@
{
"id": "4894712",
"name": "RCS-5.0",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "40904218",
"name": "copy",
"font_class": "copy",
"unicode": "e79e",
"unicode_decimal": 59294
},
{
"icon_id": "40904240",
"name": "email",
"font_class": "email",
"unicode": "e78a",
"unicode_decimal": 59274
},
{
"icon_id": "40904567",
"name": "calendar",
"font_class": "calendar",
"unicode": "e7ed",
"unicode_decimal": 59373
},
{
"icon_id": "40904659",
"name": "folder-add",
"font_class": "folder-add",
"unicode": "e80d",
"unicode_decimal": 59405
},
{
"icon_id": "40904674",
"name": "folder",
"font_class": "folder",
"unicode": "e7f9",
"unicode_decimal": 59385
},
{
"icon_id": "40905078",
"name": "layers",
"font_class": "layers",
"unicode": "e83c",
"unicode_decimal": 59452
},
{
"icon_id": "40906322",
"name": "dollar",
"font_class": "dollar",
"unicode": "e8b6",
"unicode_decimal": 59574
},
{
"icon_id": "40907675",
"name": "monitor",
"font_class": "monitor",
"unicode": "e985",
"unicode_decimal": 59781
},
{
"icon_id": "40904247",
"name": "link1",
"font_class": "link1",
"unicode": "e789",
"unicode_decimal": 59273
},
{
"icon_id": "40907403",
"name": "information-query",
"font_class": "information-query",
"unicode": "e90b",
"unicode_decimal": 59659
},
{
"icon_id": "40907711",
"name": "batch-search",
"font_class": "batch-search",
"unicode": "e977",
"unicode_decimal": 59767
},
{
"icon_id": "32459477",
"name": "market-risk",
"font_class": "a-marketrisk",
"unicode": "e72f",
"unicode_decimal": 59183
},
{
"icon_id": "40904404",
"name": "trending-up",
"font_class": "trending-up",
"unicode": "e7ae",
"unicode_decimal": 59310
},
{
"icon_id": "40904409",
"name": "trending-down",
"font_class": "trending-down",
"unicode": "e7a9",
"unicode_decimal": 59305
},
{
"icon_id": "44054370",
"name": "liedingzhi",
"font_class": "liedingzhi",
"unicode": "e787",
"unicode_decimal": 59271
},
{
"icon_id": "40906335",
"name": "research",
"font_class": "research",
"unicode": "e8b2",
"unicode_decimal": 59570
},
{
"icon_id": "40907821",
"name": "bank-card-fill",
"font_class": "bank-card-fill",
"unicode": "e9c6",
"unicode_decimal": 59846
},
{
"icon_id": "40907834",
"name": "fund-fill",
"font_class": "fund-fill",
"unicode": "e9b4",
"unicode_decimal": 59828
},
{
"icon_id": "40907871",
"name": "term-exposure-fill",
"font_class": "term-exposure-fill",
"unicode": "e994",
"unicode_decimal": 59796
},
{
"icon_id": "40904437",
"name": "bank-card",
"font_class": "bank-card",
"unicode": "e7e5",
"unicode_decimal": 59365
},
{
"icon_id": "40904566",
"name": "date-time",
"font_class": "date-time",
"unicode": "e7ef",
"unicode_decimal": 59375
},
{
"icon_id": "40904652",
"name": "doc-edit",
"font_class": "doc-edit",
"unicode": "e80c",
"unicode_decimal": 59404
},
{
"icon_id": "40905885",
"name": "chart-combo",
"font_class": "chart-combo",
"unicode": "e886",
"unicode_decimal": 59526
},
{
"icon_id": "40906317",
"name": "account",
"font_class": "account",
"unicode": "e8c4",
"unicode_decimal": 59588
},
{
"icon_id": "40906320",
"name": "bank",
"font_class": "bank",
"unicode": "e8bd",
"unicode_decimal": 59581
},
{
"icon_id": "40906329",
"name": "trend1",
"font_class": "trend1",
"unicode": "e8b9",
"unicode_decimal": 59577
},
{
"icon_id": "40907667",
"name": "credit-risk",
"font_class": "credit-risk",
"unicode": "e98c",
"unicode_decimal": 59788
},
{
"icon_id": "40907670",
"name": "market-risk",
"font_class": "market-risk",
"unicode": "e98a",
"unicode_decimal": 59786
},
{
"icon_id": "40907672",
"name": "operational-risk",
"font_class": "operational-risk",
"unicode": "e988",
"unicode_decimal": 59784
},
{
"icon_id": "44024976",
"name": "chaxunguanli",
"font_class": "chaxunguanli",
"unicode": "e783",
"unicode_decimal": 59267
},
{
"icon_id": "44024975",
"name": "toucunguanli",
"font_class": "toucunguanli",
"unicode": "e784",
"unicode_decimal": 59268
},
{
"icon_id": "44024977",
"name": "jisuangongjv",
"font_class": "jisuangongjv",
"unicode": "e786",
"unicode_decimal": 59270
},
{
"icon_id": "40903893",
"name": "home",
"font_class": "home",
"unicode": "e731",
"unicode_decimal": 59185
},
{
"icon_id": "40903911",
"name": "refresh1",
"font_class": "refresh1",
"unicode": "e72c",
"unicode_decimal": 59180
},
{
"icon_id": "40904228",
"name": "delete",
"font_class": "delete",
"unicode": "e78c",
"unicode_decimal": 59276
},
{
"icon_id": "40904232",
"name": "filter",
"font_class": "filter",
"unicode": "e790",
"unicode_decimal": 59280
},
{
"icon_id": "40904238",
"name": "save",
"font_class": "save",
"unicode": "e785",
"unicode_decimal": 59269
},
{
"icon_id": "40904242",
"name": "search",
"font_class": "search",
"unicode": "e788",
"unicode_decimal": 59272
},
{
"icon_id": "40904447",
"name": "user1",
"font_class": "user1",
"unicode": "e7d9",
"unicode_decimal": 59353
},
{
"icon_id": "40907708",
"name": "batch-failure",
"font_class": "batch-failure",
"unicode": "e96f",
"unicode_decimal": 59759
},
{
"icon_id": "40907732",
"name": "components",
"font_class": "components",
"unicode": "e965",
"unicode_decimal": 59749
},
{
"icon_id": "40907812",
"name": "application1-fill",
"font_class": "application1-fill",
"unicode": "e9cd",
"unicode_decimal": 59853
},
{
"icon_id": "40907832",
"name": "edit-fill",
"font_class": "edit-fill",
"unicode": "e9bd",
"unicode_decimal": 59837
},
{
"icon_id": "40907837",
"name": "home-fill",
"font_class": "home-fill",
"unicode": "e9ba",
"unicode_decimal": 59834
},
{
"icon_id": "40907851",
"name": "rmb-fill",
"font_class": "rmb-fill",
"unicode": "e9a5",
"unicode_decimal": 59813
},
{
"icon_id": "40907853",
"name": "parameter-fill",
"font_class": "parameter-fill",
"unicode": "e99f",
"unicode_decimal": 59807
},
{
"icon_id": "44024793",
"name": "yijujue",
"font_class": "yijujue",
"unicode": "e781",
"unicode_decimal": 59265
},
{
"icon_id": "44024789",
"name": "yitongguo",
"font_class": "yitongguo",
"unicode": "e780",
"unicode_decimal": 59264
},
{
"icon_id": "44024790",
"name": "daishenpi",
"font_class": "daishenpi",
"unicode": "e782",
"unicode_decimal": 59266
},
{
"icon_id": "44024751",
"name": "yituihui",
"font_class": "yituihui",
"unicode": "e77f",
"unicode_decimal": 59263
},
{
"icon_id": "40903907",
"name": "more2",
"font_class": "more2",
"unicode": "e729",
"unicode_decimal": 59177
},
{
"icon_id": "40903914",
"name": "remind",
"font_class": "remind",
"unicode": "e712",
"unicode_decimal": 59154
},
{
"icon_id": "40904214",
"name": "add",
"font_class": "add",
"unicode": "e79f",
"unicode_decimal": 59295
},
{
"icon_id": "40904365",
"name": "double_right",
"font_class": "double_right",
"unicode": "e7d0",
"unicode_decimal": 59344
},
{
"icon_id": "40904369",
"name": "double-left",
"font_class": "double-left",
"unicode": "e7d6",
"unicode_decimal": 59350
},
{
"icon_id": "40904373",
"name": "down",
"font_class": "down",
"unicode": "e7cb",
"unicode_decimal": 59339
},
{
"icon_id": "40904376",
"name": "down1",
"font_class": "down1",
"unicode": "e7bd",
"unicode_decimal": 59325
},
{
"icon_id": "40904380",
"name": "left1",
"font_class": "left1",
"unicode": "e7c6",
"unicode_decimal": 59334
},
{
"icon_id": "40904383",
"name": "left",
"font_class": "left",
"unicode": "e7a8",
"unicode_decimal": 59304
},
{
"icon_id": "40904386",
"name": "right",
"font_class": "right",
"unicode": "e7c1",
"unicode_decimal": 59329
},
{
"icon_id": "40904392",
"name": "right1",
"font_class": "right1",
"unicode": "e7b8",
"unicode_decimal": 59320
},
{
"icon_id": "40905242",
"name": "attention",
"font_class": "attention",
"unicode": "e867",
"unicode_decimal": 59495
},
{
"icon_id": "40905243",
"name": "fail",
"font_class": "fail",
"unicode": "e868",
"unicode_decimal": 59496
},
{
"icon_id": "40905244",
"name": "help",
"font_class": "help",
"unicode": "e869",
"unicode_decimal": 59497
},
{
"icon_id": "40905246",
"name": "success",
"font_class": "success",
"unicode": "e86b",
"unicode_decimal": 59499
},
{
"icon_id": "40905247",
"name": "caution",
"font_class": "caution",
"unicode": "e86c",
"unicode_decimal": 59500
},
{
"icon_id": "40905248",
"name": "info",
"font_class": "info",
"unicode": "e86d",
"unicode_decimal": 59501
},
{
"icon_id": "7524460",
"name": "EUR",
"font_class": "EUR",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "10956897",
"name": "美国国旗",
"font_class": "meiguoguoqi",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "41751543",
"name": "中国国旗",
"font_class": "zhongguoguoqi",
"unicode": "e632",
"unicode_decimal": 58930
}
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+109
View File
@@ -0,0 +1,109 @@
<template>
<el-dialog
v-bind="$attrs"
:class="{'rcs_dialog': true, 'padding_empty': $attrs.paddingempty, 'hidden_title': $attrs.hiddentitle}"
>
<template
v-for="(_, name) in $slots"
#[name]
>
<slot :name="name" />
</template>
<template #title>
<div class="title">
<div class="context">{{ $attrs.title }}</div>
<div class="right">
<slot name="title-right" />
</div>
</div>
</template>
</el-dialog>
</template>
<script>
export default {
name: 'RCSDialog',
data() {
return {};
},
mounted() {
},
methods: {
},
};
</script>
<style lang="scss" scoped>
.rcs_dialog {
// el-dialog
::v-deep .el-dialog {
background-color: var(--bg-color-main-2);
}
::v-deep .el-dialog__header {
padding: 0;
}
::v-deep .el-dialog__headerbtn {
right: 16px;
}
::v-deep .el-dialog__footer {
border-top: 1px solid var(--application-color-8);
padding: 10px 16px;
min-height: 48px;
}
::v-deep .el-dialog__body {
// TODO 滚动栏宽度有 10 px。开启 overflow: scroll 之后 增加 UI 兼容处理 padding-right - 10px
padding: 12px 2px 12px 12px !important;
max-height: 522px;
overflow: scroll;
}
}
.padding_empty {
::v-deep .el-dialog__body {
padding: 0 !important;
scrollbar-width: none; /* 隐藏滚动条 */
}
::v-deep .el-dialog__body::-webkit-scrollbar {
display: none; // 隐藏滚动条
width: 0; // 置滚动条的宽度为 0 来隐藏
}
}
.hidden_title {
::v-deep .el-dialog__header {
height: 0px !important;
.title {
display: none;
}
}
}
// el-button
::v-deep .el-button {
width: 51px;
height: 24px;
font-size: 12px;
padding: 0;
}
.title {
padding: 8px 16px 8px 16px;
min-height: 40px;
display: flex;
align-items: center;
flex-direction: row;
border-bottom: 1px solid var(--application-color-8);
.context {
font-size: 14px;
line-height: 22px;
color: var(--application-color-2);
flex: 1;
text-align: left;
}
.right {
flex: 1;
margin-right: 20px;
}
}
</style>
+530
View File
@@ -0,0 +1,530 @@
<template>
<div class="transfer-container">
<div class="transfer-modal">
<div class="transfer-header">
<span class="transfer-title">{{ title }}</span>
<span
class="transfer-close"
@click="onClose"
>×</span>
</div>
<div class="transfer-content">
<div class="transfer-panel source-panel">
<div class="panel-header">
<div class="panel-header-inner">
<span class="checkbox-wrapper">
<input
ref="allCheckbox"
type="checkbox"
:checked="isAllSourceChecked"
:indeterminate="isIndeterminate"
@change="toggleAllSource"
>
<span :class="{'checkbox-label': true, 'checkbox-select': sourceCheckedCount }">{{ sourceCheckedCount }}/{{ sourceData.length }} </span>
</span>
</div>
</div>
<div class="panel-search">
<input
v-model="sourceSearchText"
type="text"
placeholder="请输入搜索内容"
>
<span class="search-icon"></span>
</div>
<div class="panel-body">
<div
v-for="(item, index) in filteredSourceData"
:key="'source-' + item.value"
class="panel-item"
>
<label class="checkbox-item">
<input
type="checkbox"
:checked="item.checked"
@change="toggleItem(item)"
>
<span :class="{'item-label': true, 'item-select': item.checked}">{{ item.label }}</span>
</label>
</div>
</div>
<div class="panel-footer">
<button
class="btn-reset"
@click="resetToPreset"
>重置</button>
</div>
</div>
<div class="transfer-panel target-panel">
<div class="panel-header">
<div class="panel-header-inner">
<span>已选 {{ displayTargetData.length }} </span>
<button
class="btn-clear"
@click="clearTarget"
>全部清空</button>
</div>
</div>
<div class="panel-body">
<div
v-for="(item, index) in displayTargetData"
:key="'target-' + item.value"
class="panel-item"
>
<span class="item-icon"></span>
<span class="item-label">{{ item.label }}</span>
<span
class="item-remove"
@click="removeItem(item)"
>×</span>
</div>
</div>
</div>
</div>
<div class="transfer-footer">
<button
class="btn-cancel"
@click="onClose"
>取消</button>
<button
class="btn-confirm"
@click="onConfirm"
>确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TransferList',
props: {
title: {
type: String,
default: '',
},
value: {
type: Array,
default: () => [],
},
data: {
type: Array,
default: () => [],
},
presetSelected: {
type: Array,
default: () => [],
},
},
data() {
return {
sourceData: [],
targetData: [],
sourceSearchText: '',
};
},
computed: {
filteredSourceData() {
if (!this.sourceSearchText) {
return this.sourceData;
}
return this.sourceData.filter(item =>
item.label.toLowerCase().includes(this.sourceSearchText.toLowerCase()),
);
},
sourceCheckedCount() {
return this.sourceData.filter(item => item.checked).length;
},
isAllSourceChecked() {
return this.sourceData.length > 0 && this.sourceData.every(item => item.checked);
},
isIndeterminate() {
const checkedCount = this.sourceCheckedCount;
return checkedCount > 0 && checkedCount < this.sourceData.length;
},
displayTargetData() {
const checkedSourceItems = this.sourceData
.filter(item => item.checked)
.map(item => ({ ...item, fromSource: true }));
const targetKeys = this.targetData.map(item => item.value);
const uniqueCheckedItems = checkedSourceItems.filter(item => !targetKeys.includes(item.value));
return [...this.targetData, ...uniqueCheckedItems];
},
},
watch: {
data: {
immediate: true,
handler() {
this.initData();
},
},
isIndeterminate: {
handler(val) {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = val;
}
},
},
},
mounted() {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
}
},
updated() {
if (this.$refs.allCheckbox) {
this.$refs.allCheckbox.indeterminate = this.isIndeterminate;
}
},
methods: {
initData() {
const selectedKeys = this.value && this.value.length ? this.value : this.presetSelected || [];
this.targetData = this.data
.filter(item => selectedKeys.includes(item.value))
.map(item => ({ ...item }));
this.sourceData = this.data.map(item => ({
...item,
checked: selectedKeys.includes(item.value),
}));
},
toggleItem(item) {
item.checked = !item.checked;
this.syncTargetWithChecked();
this.emitChange();
},
toggleAllSource() {
const newCheckedState = !this.isAllSourceChecked;
this.sourceData.forEach(item => {
item.checked = newCheckedState;
});
this.syncTargetWithChecked();
this.emitChange();
},
syncTargetWithChecked() {
const checkedKeys = this.sourceData
.filter(item => item.checked)
.map(item => item.value);
this.targetData = this.data
.filter(item => checkedKeys.includes(item.value))
.map(item => ({ ...item }));
},
resetToPreset() {
const presetKeys = this.presetSelected || [];
this.sourceData.forEach(item => {
item.checked = presetKeys.includes(item.value);
});
this.targetData = this.data
.filter(item => presetKeys.includes(item.value))
.map(item => ({ ...item }));
this.sourceSearchText = '';
this.emitChange();
},
clearTarget() {
this.targetData = [];
this.sourceData.forEach(item => {
item.checked = false;
});
this.emitChange();
},
removeItem(item) {
const sourceItem = this.sourceData.find(sourceItem => sourceItem.value === item.value);
if (sourceItem) {
sourceItem.checked = false;
}
const targetIndex = this.targetData.findIndex(targetItem => targetItem.value === item.value);
if (targetIndex !== -1) {
this.targetData.splice(targetIndex, 1);
}
this.emitChange();
},
emitChange() {
const selectedKeys = [];
const selectedLabels = [];
this.targetData.forEach(item => {
selectedKeys.push(item.value);
selectedLabels.push(item.label);
});
this.$emit('input', selectedKeys, selectedLabels);
this.$emit('change', selectedKeys, selectedLabels);
},
onConfirm() {
this.syncTargetWithChecked();
this.$emit('confirm', this.targetData.map(item => item.value));
},
onClose() {
this.$emit('cancel');
},
},
};
</script>
<style lang="scss" scoped>
.transfer-container {
// 预留 css variables
--primary-color: #6AB2FF;
--bg-color: #151e2e;
--text-color: rgb(255, 255, 255, 0.9);
--border-color: #434343;
--item-hover-bg: #262626;
--panel-bg: #1f1f1f;
--button-primary-bg: #3389FF;
--button-primary-color: rgb(255, 255, 255, 0.9);
--button-default-bg: #151e2e;
--button-default-color: rgb(255, 255, 255, 0.7);
--modal-bg: #1f1f1f;
--modal-header-bg: #141414;
--checkbox-color: #177ddc;
--select-text-color: #6AB2FF;
}
.transfer {
&-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
}
&-modal {
width: 700px;
background-color: var(--modal-bg);
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.07);
box-shadow: 0px 8px 16px -8px rgba(0, 0, 0, 0.13), 0px 12px 32px rgba(0, 0, 0, 0.13), 0px 16px 48px rgba(0, 0, 0, 0.2);
background-color: rgba(20, 29, 40, 1);
}
&-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 9px 16px;
}
&-title {
font-size: 12px;
font-weight: 500;
color: var(--text-color);
}
&-close {
font-size: 22px;
color: var(--text-color);
opacity: 0.7;
cursor: pointer;
&:hover {
opacity: 1;
}
}
&-content {
display: flex;
padding: 16px;
gap: 12px;
font-size: 12px;
}
&-panel {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid var(--border-color);
border-radius: 4px;
height: 490px;
}
&-footer {
padding: 10px 16px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
}
.panel {
&-header {
padding: 8px 12px;
border-bottom: 1px solid var(--border-color);
&-inner {
display: flex;
justify-content: space-between;
align-items: center;
color: var(--text-color);
}
}
&-search {
padding: 8px 12px;
position: relative;
border-bottom: 1px solid var(--border-color);
input {
width: 100%;
box-sizing: border-box;
padding: 8px 12px;
padding-right: 30px;
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--bg-color);
color: var(--text-color);
}
}
&-body {
flex: 1;
overflow-y: auto;
padding: 8px 0;
}
&-item {
padding: 8px 12px;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
background-color: var(--item-hover-bg);
}
}
&-footer {
padding: 8px 12px;
display: flex;
justify-content: flex-start;
}
}
.search-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
color: var(--text-color);
opacity: 0.5;
}
.checkbox {
&-item {
display: flex;
align-items: center;
width: 100%;
cursor: pointer;
}
&-wrapper {
display: flex;
align-items: center;
}
&-label {
margin-left: 8px;
color: var(--text-color);
text-align: left;
}
&-select {
color: var(--select-text-color);
}
}
.item {
&-icon {
margin-right: 8px;
color: var(--text-color);
opacity: 0.5;
}
&-label {
flex: 1;
margin-left: 8px;
color: var(--text-color);
text-align: left;
}
&-remove {
color: var(--text-color);
opacity: 0.7;
cursor: pointer;
font-size: 12px;
&:hover {
opacity: 1;
}
}
&-select {
color: var(--select-text-color);
}
}
input[type="checkbox"] {
width: 16px;
height: 16px;
accent-color: var(--checkbox-color);
cursor: pointer;
}
.btn {
&-reset, &-cancel {
padding: 5px 16px;
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--button-default-bg);
color: var(--button-default-color);
cursor: pointer;
}
&-clear {
background: none;
border: none;
color: var(--primary-color);
cursor: pointer;
font-size: 12px;
padding: 0;
margin: 0;
}
&-confirm {
padding: 5px 16px;
border: none;
border-radius: 4px;
background-color: var(--button-primary-bg);
color: var(--button-primary-color);
cursor: pointer;
}
}
</style>
@@ -0,0 +1,657 @@
<template>
<div
v-if="visible"
class="dialog-overlay"
@click.self="handleCancel"
>
<div
class="dialog-container"
:class="{ 'theme-light': theme === 'light', 'theme-dark': theme === 'dark' }"
>
<div class="dialog-header">
<span class="dialog-title">{{ title }}</span>
<div class="header-actions">
<button
class="close-button"
@click="handleCancel"
>×</button>
</div>
</div>
<div class="dialog-tabs">
<div
class="tab"
:class="{ active: activeTab === 'account' }"
@click="activeTab = 'account'"
>
账户
</div>
<div
class="tab"
:class="{ active: activeTab === 'accountGroup' }"
@click="activeTab = 'accountGroup'"
>
账户组
</div>
</div>
<div class="search-container">
<div class="search-input">
<i class="search-icon"></i>
<div class="search-input-text">
<input
v-model="searchText"
type="text"
placeholder="输入关键词,可快速查找..."
@input="filterTree"
>
</div>
</div>
</div>
<!-- 账户标签内容 -->
<div
v-if="activeTab === 'account'"
class="dialog-content"
>
<div class="tree-container">
<el-tree
ref="accountTree"
:data="accountData"
:props="defaultProps"
:filter-node-method="filterNode"
node-key="id"
:expand-on-click-node="false"
:default-expanded-keys="defaultExpandedKeys"
@node-click="handleNodeClick"
>
<span
slot-scope="{ node, data }"
class="custom-tree-node"
@dblclick.stop="handleDoubleClick(data)"
>
<span class="node-title">{{ node.label.replace(/^.{1}@{2}/, '') }}</span>
<span
v-if="data.text"
class="node-subtitle"
>{{ data.text }}</span>
</span>
</el-tree>
</div>
</div>
<!-- 账户组标签内容 -->
<div
v-if="activeTab === 'accountGroup'"
class="dialog-content"
>
<div class="account-group-list">
<div
v-for="(item, index) in filteredAccountGroups"
:key="index"
class="account-group-item"
:class="{'selected': item.id == selectedItem?.id}"
@click="selectItem(item)"
@dblclick="handleDoubleClick(item)"
>
<span class="group-id">{{ item.value.replace(/^.{1}@{2}/, '') }}</span>
<span class="group-name">{{ item.text }}</span>
</div>
</div>
</div>
<div class="dialog-footer">
<button
class="btn-cancel"
@click="handleCancel"
>取消</button>
<button
class="btn-confirm"
@click="handleConfirm"
>确定</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TreeSearchDialog',
props: {
visible: {
type: Boolean,
default: false,
},
// 允许外部传入初始主题
initialTheme: {
type: String,
default: 'dark', // 默认为暗色主题
validator: (value) => ['dark', 'light'].includes(value),
},
accountData: {
type: Array,
default: () => [],
},
accountGroups: {
type: Array,
default: () => [],
},
title: {
type: String,
default: '',
},
// 默认展开的节点
defaultExpandedKeys: {
type: Array,
default: () => [],
},
},
data() {
return {
theme: this.initialTheme,
activeTab: 'account',
searchText: '',
selectedItem: null,
filteredAccountGroups: [],
defaultProps: {
children: 'children',
label: 'value',
},
};
},
watch: {
visible(val) {
if (val && this.$refs.accountTree) {
// 当对话框显示时,重置过滤器
this.$refs.accountTree.filter('');
this.searchText = '';
}
},
accountGroups: {
immediate: true,
handler() {
this.initDataGroup();
},
},
accountData: {
immediate: true,
handler() {
this.initData();
},
},
},
created() {
},
methods: {
initDataGroup() {
this.filteredAccountGroups = [...this.accountGroups];
},
initData() {
},
// 切换主题
toggleTheme() {
this.theme = this.theme === 'dark' ? 'light' : 'dark';
this.$emit('theme-change', this.theme);
},
// el-tree 的节点过滤方法
filterNode(value, data) {
if (!value) return true;
const searchTerm = value.toLowerCase();
// 检查节点标题和副标题
return data.value.toLowerCase().includes(searchTerm) ||
(data.text && data.text.toLowerCase().includes(searchTerm));
},
// 处理搜索输入
filterTree() {
if (this.activeTab === 'account' && this.$refs.accountTree) {
this.$refs.accountTree.filter(this.searchText);
} else if (this.activeTab === 'accountGroup') {
this.filterAccountGroups();
}
},
// 过滤账户组
filterAccountGroups() {
if (!this.searchText) {
this.filteredAccountGroups = [...this.accountGroups];
return;
}
const searchTerm = this.searchText.toLowerCase();
this.filteredAccountGroups = this.accountGroups.filter(group =>
group.id.toLowerCase().includes(searchTerm) ||
group.value.toLowerCase().includes(searchTerm) ||
group.text.toLowerCase().includes(searchTerm),
);
},
// 处理节点点击
handleNodeClick(data) {
this.selectedItem = data;
},
// 选择项目
selectItem(data) {
this.selectedItem = data;
},
// 处理双击事件
handleDoubleClick(data) {
this.selectedItem = data;
this.handleConfirm();
},
// 取消按钮
handleCancel() {
this.$emit('cancel');
},
// 确认按钮
handleConfirm() {
this.$emit('confirm', this.selectedItem);
},
},
};
</script>
<style lang="scss" scoped>
/* 全局主题变量 */
.dialog-overlay {
/* 暗色主题变量 */
--dark-bg-primary: #141D28;
--dark-bg-secondary: #2c3347;
--dark-bg-tertiary: #3a4257;
--dark-tab-bg-primary: #212b39;
--dark-text-primary: #ffffff;
--dark-text-secondary: #8e8e8e;
--dark-border: #2c3347;
--dark-accent: #3a8ee6;
--dark-hover: rgba(255, 255, 255, 0.05);
--dark-selected: rgba(255, 255, 255, 0.1);
/* 亮色主题变量 */
--light-bg-primary: #ffffff;
--light-bg-secondary: #f5f7fa;
--light-bg-tertiary: #e4e7ed;
--light-tab-bg-primary: #ffffff;
--light-text-primary: #303133;
--light-text-secondary: #606266;
--light-border: #dcdfe6;
--light-accent: #409eff;
--light-hover: rgba(0, 0, 0, 0.05);
--light-selected: rgba(0, 0, 0, 0.1);
}
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
/* 主题相关样式 */
.dialog-container {
width: 90%;
max-width: 500px;
max-height: 90vh;
border-radius: 4px;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* 暗色主题 */
.theme-dark {
background-color: var(--dark-bg-primary);
color: var(--dark-text-primary);
}
/* 亮色主题 */
.theme-light {
background-color: var(--light-bg-primary);
color: var(--light-text-primary);
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
}
.theme-dark .dialog-header {
border-bottom: 1px solid var(--dark-border);
}
.theme-light .dialog-header {
border-bottom: 1px solid var(--light-border);
}
.dialog-title {
font-size: 14px;
font-weight: 500;
}
.header-actions {
display: flex;
align-items: center;
}
.theme-toggle {
background: none;
border: none;
cursor: pointer;
font-size: 22px;
}
.close-button {
background: none;
border: none;
font-size: 30px;
cursor: pointer;
padding: 0;
margin: 0;
}
.theme-dark .close-button {
color: var(--dark-text-secondary);
}
.theme-light .close-button {
color: var(--light-text-secondary);
}
.dialog-tabs {
display: flex;
padding: 2px;
margin: 12px 16px;
border-radius: 2px;
font-size: 12px;
}
.theme-dark .dialog-tabs {
background-color: var(--dark-tab-bg-primary);
}
.theme-light .dialog-tabs {
background-color: var(--light-tab-bg-primary);
}
.tab {
cursor: pointer;
flex: 1;
text-align: center;
border-radius: 2px;
}
.theme-dark .tab {
background-color: transparent;
color: var(--dark-text-secondary);
}
.theme-light .tab {
background-color: transparent;
color: var(--light-text-secondary);
}
.theme-dark .tab.active {
background-color: var(--dark-bg-secondary);
color: var(--dark-text-primary);
}
.theme-light .tab.active {
background-color: var(--light-bg-secondary);
color: var(--light-text-primary);
}
.search-container {
padding: 12px 16px;
}
.search-input {
position: relative;
border-radius: 4px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.search-icon {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.search-input-text {
width: 100%;
display: flex;
}
.theme-dark .search-icon {
color: var(--dark-text-secondary);
}
.theme-light .search-icon {
color: var(--light-text-secondary);
}
.search-input input {
font-size: 12px;
width: 100%;
padding: 8px 8px 8px 36px;
border-radius: 4px;
border: none;
}
.theme-dark .search-input input {
background-color: transparent;
color: var(--dark-text-primary);
}
.theme-light .search-input input {
background-color: transparent;
color: var(--light-text-primary);
}
.theme-dark .search-input input::placeholder {
color: var(--dark-text-secondary);
}
.theme-light .search-input input::placeholder {
color: var(--light-text-secondary);
}
.dialog-content {
flex: 1;
overflow-y: auto;
max-height: calc(90vh - 180px);
}
.tree-container {
padding: 0 16px;
font-size: 12px;
}
/* 自定义 el-tree 样式 */
.theme-dark :deep(.el-tree) {
background-color: transparent !important;
color: var(--dark-text-primary) !important;
}
.theme-light :deep(.el-tree) {
background-color: transparent !important;
color: var(--light-text-primary) !important;
}
.theme-dark :deep(.el-tree-node__content) {
background-color: transparent !important;
}
.theme-light :deep(.el-tree-node__content) {
background-color: transparent !important;
}
.theme-dark :deep(.el-tree-node__content:hover) {
background-color: var(--dark-hover) !important;
}
.theme-light :deep(.el-tree-node__content:hover) {
background-color: var(--light-hover) !important;
}
.theme-dark :deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: var(--dark-selected) !important;
}
.theme-light :deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: var(--light-selected) !important;
}
.theme-dark :deep(.el-tree-node__expand-icon) {
color: var(--dark-text-secondary);
}
.theme-light :deep(.el-tree-node__expand-icon) {
color: var(--light-text-secondary) !important;
}
.theme-dark :deep(.el-tree-node__expand-icon.expanded) {
color: var(--dark-text-primary) !important;
}
.theme-light :deep(.el-tree-node__expand-icon.expanded) {
color: var(--light-text-primary) !important;
}
.custom-tree-node {
display: flex;
align-items: center;
width: 100%;
padding-right: 8px;
}
.node-title {
font-weight: 500;
margin-right: 8px;
}
.theme-dark .node-subtitle {
color: var(--dark-text-secondary);
}
.theme-light .node-subtitle {
color: var(--light-text-secondary);
}
.account-group-list {
padding: 0 16px;
font-size: 12px;
}
.account-group-item {
display: flex;
padding: 10px 0;
cursor: pointer;
}
.theme-dark .account-group-item {
border-bottom: 1px solid var(--dark-border);
}
.theme-light .account-group-item {
border-bottom: 1px solid var(--light-border);
}
.theme-dark .account-group-item:hover {
background-color: var(--dark-hover);
}
.theme-light .account-group-item:hover {
background-color: var(--light-hover);
}
.theme-dark .account-group-item.selected {
background-color: var(--dark-selected);
}
.theme-light .account-group-item.selected {
background-color: var(--light-selected);
}
.theme-dark .account-group-item.highlighted {
color: var(--dark-accent);
}
.theme-light .account-group-item.highlighted {
color: var(--light-accent);
}
.group-id {
margin-right: 12px;
font-weight: 500;
}
.theme-dark .group-name, .theme-dark .group-desc {
color: var(--dark-text-secondary);
margin-right: 8px;
}
.theme-light .group-name, .theme-light .group-desc {
color: var(--light-text-secondary);
margin-right: 8px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
padding: 12px 16px;
}
.theme-dark .dialog-footer {
border-top: 1px solid var(--dark-border);
}
.theme-light .dialog-footer {
border-top: 1px solid var(--light-border);
}
.btn-cancel, .btn-confirm {
padding: 6px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
margin-left: 8px;
font-size: 12px;
}
.theme-dark .btn-cancel {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--dark-text-primary);
}
.theme-light .btn-cancel {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--light-text-primary);
}
.theme-dark .btn-confirm {
background-color: var(--dark-accent);
color: var(--dark-text-primary);
}
.theme-light .btn-confirm {
background-color: var(--light-accent);
color: #ffffff;
}
</style>
+117
View File
@@ -0,0 +1,117 @@
<template>
<el-dialog
:visible.sync="show"
:title="configData.title"
:modal-append-to-body="false"
:width="`${percentWidth}%`"
@close="handleCancel"
>
<PublicForm
ref="publicForm"
:form-arr="formArr"
:form-data="formData"
@outOperation="outOperation"
/>
<span
slot="footer"
class="dialog-footer"
>
<slot name="footerBtn" />
<el-button
type="default"
:size="$buttonSize"
@click="handleCancel"
> </el-button>
<el-button
type="primary"
:size="$buttonSize"
@click="dialogOK"
> </el-button>
</span>
</el-dialog>
</template>
<script>
import PublicForm from '@/components/form/index.vue';
export default {
components: {
PublicForm,
},
props: {
visible: { // 是否展示弹窗
type: Boolean,
default: false,
},
formArr: { // 配置数组
type: Array,
required: true,
},
percentWidth: { // 弹窗宽度
type: Number,
default: 30,
},
formData: { // 表单数据
type: Object,
default: () => {},
},
/**
* 配置对象
* title 标题
* addApi 新增接口
* editApi 修改接口
* type 1 新增 2 编辑
* transFormData 参数处理方法
* 默认 transformRequest: (params) => {
return params;
}
*/
configData: {
type: Object,
default: () => ({}),
},
},
data() {
return {
show: false,
};
},
watch: {
visible: {
handler(nv) {
this.show = nv;
},
},
},
methods: {
handleCancel() {
console.log('我是formArr', this.formArr);
this.$emit('handleCancel');
},
outOperation(val, index, prop, num) {
console.log('我是outOperation', val, index, prop, num);
},
dialogOK() {
// 判断表单验证是否通过
if (this.$refs.publicForm.submitForm()) {
console.log('success');
console.log(this.formData);
const api = { 1: this.$apis[this.configData.addApi], 2: this.$apis[this.configData.editApi] };
const params = this.configData.transFormData(this.formData);
api[this.configData.type](params).then(res => {
this.$message.success('操作成功');
this.$emit('dialogOK', res);
});
} else {
console.log('error');
this.$emit('dialogCancel');
}
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .titiebox .titieboxlabel {
white-space: nowrap;
}
</style>
+63
View File
@@ -0,0 +1,63 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
v-on="formItems.events"
@change="handleInput"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
+73
View File
@@ -0,0 +1,73 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
v-on="formItems.events"
@change="handleChange($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
+297
View File
@@ -0,0 +1,297 @@
<template>
<el-dialog
title="列定制"
:visible.sync="visibleDialog"
width="640px"
@close="columnClose"
>
<div class="content">
<div class="left-box">
<div class="left-select">
<el-checkbox
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
>{{ checkedItems.length }} / {{ tableColumn.length }}</el-checkbox>
<el-checkbox-group
v-model="checkedItems"
class="check-list"
@change="handleCheckedCitiesChange"
>
<el-checkbox
v-for="item in tableColumn"
:key="item.label"
:label="item.label"
>{{ item.label }}</el-checkbox>
</el-checkbox-group>
</div>
<div class="left-bottom">
<el-button
:size="$buttonSize"
@click="resetColumn"
>恢复默认</el-button>
</div>
</div>
<div class="right-box">
<div class="right-top">
已选{{ checkedItems.length }}
<el-button
type="text"
:size="$buttonSize"
@click="clearSelect"
>全部清空</el-button>
</div>
<el-input
v-model="searchParams"
placeholder="请输入搜索内容"
>
<template #suffix>
<i
class="search-icon el-icon-search"
@click="searchColumns"
/>
</template>
</el-input>
<div class="select-columns">
<div
v-for="(item,index) in showItems"
:key="item"
class="select-li"
draggable="true"
@dragstart="onDragStart(index)"
@dragover.prevent
@drop="onDrop(index)"
>
<div class="li-left">
<i class="el-icon-s-grid" />
<div class="li-label">{{ item }}</div>
</div>
<!-- <img src="../../../public/images/close.svg"> -->
<div class="icon-groups">
<i
class="el-icon-close"
style="cursor:pointer;font-size:16px"
@click="deleteItem(item)"
/>
<i
class="el-icon-top"
style="cursor:pointer;font-size:16px"
@click="sortItem(item,index)"
/></div>
</div>
</div>
</div>
</div>
<div
slot="footer"
class="dialog-footer"
>
<el-button
:size="$buttonSize"
class="drawer-footer-cancel-btn"
@click="columnClose"
> </el-button>
<el-button
:size="$buttonSize"
class="drawer-footer-confirm-btn"
type="primary"
@click="handleCustomColumnConfirm"
>保存</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
props: {
showDialog: {
type: Boolean,
default: false,
},
tableColumn: {
type: Array,
default: () => [],
},
},
data() {
return {
visibleDialog: false,
columnDialog: false,
checked: false,
checkAll: false,
isIndeterminate: false,
checkedItems: [],
showItems: [],
searchParams: '',
draggedIndex: '',
};
},
watch: {
showDialog: {
handler(nv) {
this.visibleDialog = nv;
},
},
},
mounted() {},
methods: {
onDragStart(index) {
this.draggedIndex = index;
this.$nextTick(() => {
const draggedItem = this.$el.querySelector(`.draggable-item:nth-child(${index + 1})`);
draggedItem.classList.add('dragging');
});
console.log(index, 'dropStart');
},
onDrop(index) {
console.log(index, 'drop');
if (this.draggedIndex !== index) {
const draggedItem = this.items.splice(this.draggedIndex, 1)[0];
this.items.splice(index, 0, draggedItem);
this.draggedIndex = null;
// 保存新顺序到服务器或本地存储
// this.saveOrder();
}
},
handleCheckAllChange(val) {
this.checkedItems = val ? this.tableColumn.map(v => v.label) : [];
this.showItems = [...this.checkedItems];
this.isIndeterminate = false;
},
handleCheckedCitiesChange(value) {
const checkedCount = value.length;
this.showItems = [...this.checkedItems];
this.checkAll = checkedCount === this.tableColumn.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.tableColumn.length;
},
resetColumn() { // 恢复默认
},
searchColumns() {
console.log(this.searchParams, 'searchParams');
if (this.searchParams) {
this.showItems = this.checkedItems.filter(v => v.includes(this.searchParams));
} else {
this.showItems = [...this.checkedItems];
}
},
clearSelect() {
this.checkedItems = [];
this.showItems = [];
this.isIndeterminate = false;
this.checkAll = this.checkedItems === this.tableColumn.length;
},
columnClose() {
this.visibleDialog = false;
this.$emit('update:showDialog', false);
this.searchParams = '';
this.clearSelect();
},
deleteItem(item) {
this.checkedItems = this.checkedItems.filter(v => v !== item);
this.showItems = [...this.checkedItems];
this.checkAll = this.checkedItems === this.tableColumn.length;
this.isIndeterminate = this.checkedItems.length > 0 && this.checkedItems.length < this.tableColumn.length;
},
sortItem(item, index) {
if (index > 0) {
const arr = this.checkedItems;
arr.splice(index - 1, 1, ...arr.splice(index, 1, arr[index - 1]));
this.showItems = [...this.checkedItems];
}
},
handleCustomColumnConfirm() {
console.log(this.checkedItems, 'checkItems');
this.columnClose();
// this.$emit('customColumnChange', this.tableData);
},
},
};
</script>
<style lang="scss" scoped>
.content{
display: flex;
}
.left-box {
width:360px;
height:490px;
.left-select{
padding: 8px 0 0 16px;
border-radius: 2px;
border: 1px solid var(--input-border);
background-color: var(--desktop-bg-color-1);
height:456px;
.check-list{
height:420px;
line-height:20px;
overflow:auto;
margin-top:10px
}
}
.left-bottom{
border-radius: 0px 0px 2px 2px;
border-left: 1px solid var(--input-border);
border-right: 1px solid var(--input-border);
border-bottom: 1px solid var(--input-border);
padding:5px 12px
}
}
.right-box{
border-radius: 2px;
border: 1px solid var(--input-border);
opacity: 1;
width:240px;
height:490px;
background:var(--desktop-bg-color-1);
margin-left:8px;
padding:5px 12px;
.right-top{
display:flex;
justify-content: space-between;
color:var(--text-color-1);
font-family: "SourceHanSansSC-Regular";
font-size: 12px;
font-weight: 400;
font-style: Regular;
letter-spacing: 0px;
text-align: left;
line-height: 20px;
}
.select-columns{
height:424px;
overflow:auto;
margin-top:8px;
.select-li{
height:28px;
display: flex;
align-items: center;
justify-content: space-between;
}
.li-left{
display:flex;
align-items: center;
}
.select-li:hover{
border-radius: 2px;
background-color: rgba(0, 0, 0, 0.05);
.icon-groups{
display: block;
}
}
.icon-groups{
display: none;
i+i{
margin-left:5px
}
}
}
}
.search-icon{
font-size:16px;
line-height: 30px;
cursor:pointer;
color:var(--text-color-1)
}
</style>
+160
View File
@@ -0,0 +1,160 @@
<template>
<el-dialog
title="导出"
:visible.sync="visibleDialog"
width="400px"
class="export-dialog"
@close="close"
>
<el-form
ref="form"
:model="form"
label-width="60px"
>
<el-row>
<el-form-item label="范围">
<el-radio-group v-model="form.exportScope">
<el-radio label="page">导出当前页</el-radio>
<el-radio label="all">导出全部</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
<el-row>
<el-form-item label="类型">
<el-radio-group v-model="form.exportType">
<el-radio label="xls">Excel</el-radio>
<el-radio label="csv">CSV</el-radio>
<el-radio label="txt">TxT</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
</el-form>
<div
slot="footer"
class="dialog-footer"
>
<el-button
type="primary"
class="btn"
@click="submitExport"
>{{
$t("button.confirm")
}}</el-button>
</div>
</el-dialog>
</template>
<script>
import { commonMore } from '../../utils/index';
export default {
props: {
showDialog: {
type: Boolean,
default: false,
},
exportParams: {
type: Object,
default: () => {},
},
},
data() {
return {
visibleDialog: false,
form: {
exportType: 'csv',
exportScope: 'all',
},
};
},
watch: {
showDialog: {
handler(nv) {
this.visibleDialog = nv;
},
},
},
mounted() {},
methods: {
close() {
console.log('关闭了');
this.visibleDialog = false;
this.$emit('update:showDialog', false);
this.form = {
exportType: 'csv',
exportScope: 'all',
};
},
async submitExport() {
const params = { ...this.form, ...this.exportParams };
if (this.form.exportScope === 'all') {
delete params.pageStart;
delete params.pageLimit;
}
console.log(params, 'ppp');
const exportParams = commonMore.dataHandler(params);
const res = await this.$apis.exportData(exportParams);
console.log(res, 'res');
this.download(res.data.result);
},
download(ticket) {
const action = window.origin.replace(/^https?:/, '') + '/dcs/baseQuery/download.action';
// ticket = '8572f582-f927-40f1-b487-27ce3b4e5119'
const url = `${action}?queryParam.ticket=${ticket}`;
console.log(action, 'aaa');
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/vnd.ms-excel;charset=UTF-8',
},
})
.then(async(response) => {
if (!response.ok) {
const text = await response.text();
throw new Error(text);
}
// 关键:确保服务器暴露 Content-Disposition 头
const contentDisposition = response.headers.get(
'Content-Disposition',
);
let filename = '导出文件.csv'; // 默认值
if (contentDisposition) {
// 关键步骤:提取并解码 Java URLEncoder 编码的文件名
const filenameMatch = contentDisposition.match(
/filename=("?)([^";]+)\1/i,
);
if (filenameMatch && filenameMatch[2]) {
// 替换 "+" 为 "%20"(解决 Java URLEncoder 的空格编码问题)
const encodedName = filenameMatch[2].replace(/\+/g, '%20');
// 解码 URL 编码
filename = decodeURIComponent(encodedName);
}
}
return response.blob().then((blob) => ({ blob, filename }));
})
.then(({ blob, filename }) => {
console.log(blob, filename, '文件信息');
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename; // 动态设置文件名
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
})
.catch((error) => {
console.error('下载失败:', error);
});
},
},
};
</script>
<style lang="scss" scoped>
.export-dialog{
:deep(.el-form-item__content){
line-height:40px
}
}
</style>
+158
View File
@@ -0,0 +1,158 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@blur="handleBlur"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
// 使用的小数位数的最小数目,可能的值是从 0 到 20
minimumFractionDigits: {
type: Number,
default: 2,
},
// 使用的小数位数的最大数目。可能的值是从 0 到 20
maximumFractionDigits: {
type: Number,
default: 20,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
watch: {
value(nVal) {
if (nVal) {
const val = nVal.toString();
this.inputValue = this.inputValueCopy = this.changePercentile(val);
} else {
this.inputValue = this.inputValueCopy = '';
}
},
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
this.$emit('input', this.inputValue);
},
handleBlur() {
this.delcomma();
let inputValue = this.inputValue;
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
inputValue = num * Math.pow(10, unit);
this.inputValue = this.changePercentile(inputValue);
}
console.log('blurNUm', inputValue);
this.$emit('input', inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.delcomma();
},
// 转换千分位
changePercentile(val) {
return val.toLocaleString('en-US', {
minimumFractionDigits: this.minimumFractionDigits,
maximumFractionDigits: this.maximumFractionDigits,
});
},
// 去掉","号
delcomma() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
+114
View File
@@ -0,0 +1,114 @@
<template>
<div class="foldbox">
<div
class="header"
@click="$emit('click')"
>
<div class="header-icon"><icon-font
:name="titleIcon"
size="11"
/></div>
<div class="header-title">{{ title }}</div>
<div class="header-rotate">
<i
v-if="!isOpen"
class="el-icon-arrow-right"
/>
<i
v-if="isOpen"
class="el-icon-arrow-down"
/>
</div>
</div>
<div
class="content"
/>
<slot :row="row" />
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: 'title',
},
titleIcon: {
type: String,
default: 'icon-research',
},
isOpen: {
type: Boolean,
default: false,
},
row: {
type: Object,
default: () => {},
},
},
data() {
return {
};
},
watch: {
row: {
handler(nVal) {
console.log('nValnVal---row11111122', nVal);
},
deep: true,
immediate: true,
},
},
};
</script>
<style scoped lang="scss">
.foldbox {
margin-bottom: 8px;
width: 100%;
padding: 12px;
border-radius: 4px;
background-color: var(--card-bg);
}
.header {
display: flex;
width: 100%;
font-weight: 800;
align-items: center;
height: 24px;
.header-icon {
width: 20px;
height: 20px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.13);
display: flex;
align-items: center;
justify-content: center;
}
.header-title {
margin-left: 8px;
font-size: 14px;
}
.header-rotate {
margin-left: 14px;
}
}
.content {
margin-top: 10px;
padding-top: 7px;
width: 100%;
border-top: 1px solid var(--card-border);
}
.fade-enter-active {
transition: opacity 2s ease, height 2s ease;
}
.fade-leave-active {
transition: opacity 0s, height 0s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
+336
View File
@@ -0,0 +1,336 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type === 'input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 自定义列展示 -->
<CSelectLabel
v-if="formItems.type==='selectLabel'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 周选择器 -->
<CPickerWeek
v-if="formItems.type==='pickerWeek'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 月选择器 -->
<CPickerMonth
v-if="formItems.type==='pickerMonth'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 年选择器 -->
<CPickerYear
v-if="formItems.type==='pickerYear'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间范围选择器 -->
<CPickerTimeRange
v-if="formItems.type==='pickerTimeRange'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期时间选择器 -->
<CPickerDateTime
v-if="formItems.type==='pickerDateTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期时间范围选择器 -->
<CPickerDateTimeRange
v-if="formItems.type==='pickerDateTimeRange'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择-选择 -->
<CSelectSelect
v-if="formItems.type==='selectSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本输入-选择 -->
<CInputSelect
v-if="formItems.type==='inputSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 下拉懒加载 -->
<CSelectLazyLoading
v-if="formItems.type==='selectLazyLoading'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器拆分单个日期 -->
<CPickerDateSingle
v-if="formItems.type==='pickerDateSingle'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<CSelectTable
v-if="formItems.type==='selectTable'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
<!-- 穿梭框 -->
<CSelectTransfer
v-if="formItems.type==='selectTransfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 树结构 -->
<CSelectTreeTable
v-if="formItems.type==='selectTreeTable'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
</div>
</template>
<script>
import CInput from '../input';
import CTextarea from '../textarea';
import CSelect from '../select';
import CSelectLabel from '../selectLabel';
import CSelectApi from '../selectApi';
import CSelectTree from '../selectTree';
import CSelectTreeApi from '../selectTreeApi';
import CInputNumber from '../inputNumber';
import CInputFinance from '../finance';
import CInputDate from '../inputDate';
import CPickerDate from '../pickerDate';
import CPickerTime from '../pickerTime';
import CPickerTimeRange from '../pickerTimeRange';
import CPickerDateTime from '../pickerDateTime';
import CPickerDateTimeRange from '../pickerDateTimeRange';
import CPickerWeek from '../pickerWeek';
import CPickerMonth from '../pickerMonth';
import CPickerYear from '../pickerYear';
import CRadio from '../radio';
import CCheckbox from '../checkbox';
import CSwitch from '../switch';
import CCascader from '../cascader';
import CTransfer from '../transfer';
import CSelectSelect from '../select-select';
import CInputNumber2 from '../inputNumber2';
import CInputSelect from '../input-select';
import CSelectLazyLoading from '../selectLazyLoading';
import CPickerDateSingle from '../pickerDateSingle';
import CSelectTable from '../selectTable/index';
import CSelectTransfer from '../selectTransfer/index';
import CSelectTreeTable from '../selectTreeTable/index';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CPickerTimeRange,
CPickerDateTime,
CPickerDateTimeRange,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CSelectSelect,
CInputNumber2,
CInputSelect,
CSelectLazyLoading,
CPickerDateSingle,
CSelectLabel,
CPickerYear,
CPickerWeek,
CPickerMonth,
CSelectTable,
CSelectTransfer,
CSelectTreeTable,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
data() {
return {
// formItems: {},
// formData: {},
};
},
watch: {
// formItems(newval) {
// this.formItems = newval;
// },
// formData(newval) {
// this.formData = newval;
// },
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
+268
View File
@@ -0,0 +1,268 @@
<template>
<el-form ref="ruleForm" :model="formData" class="demo-ruleForm" inline>
<el-row>
<el-col
v-for="(formItems, index) in formObj"
v-show="!formItems.notShow"
:span="formItems.span"
:key="index"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
label-width="80px"
>
<!-- 文件上传 -->
<!-- 如果对象有值就回显没有值就为空 -->
<el-upload
v-if="formobj.upload"
:ref="formobj.prop"
:accept="formobj.accept ? formobj.accept : 'PNG,JPEG'"
:file-list="formData[formobj.prop] ? formData[formobj.prop] : []"
:action="`${uploadUrl}${
formobj.uploadObj.fileType ? formobj.uploadObj.fileType : ''
}`"
:limit="formobj.uploadObj.limit"
:class="{
hide:
formobj.uploadObj.hideUpload ||
formData[formobj.prop].length == formobj.uploadObj.limit,
}"
:on-preview="handlePictureCardPreview"
:on-remove="
(file, fileList) =>
handleRemove(
file,
fileList,
formobj.uploadObj.limit,
formobj.prop,
index
)
"
:on-success="
(response, file, fileList) =>
uploadSuccess(
response,
file,
fileList,
formobj.uploadObj.limit,
formobj.prop,
index
)
"
list-type="picture-card"
:auto-upload="true"
>
<i slot="default" class="el-icon-plus" />
</el-upload>
<el-dialog
v-if="formobj.upload"
:visible.sync="dialogVisible"
:append-to-body="true"
width="40%"
>
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<!-- text展示 -->
<span v-if="formobj.text" v-text="formData[formobj.prop]" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import FormItem from "./formItem.vue";
export default {
components: {
FormItem,
},
props: {
formObj: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
searchSelectOptionsCb: {
type: Array,
},
},
data() {
return {
uploadUrl: "",
dialogImageUrl: "",
searchSelectLoading: false,
dialogVisible: false,
disabled: false,
searchShow: "", //高德地图input收索联想
setSearchVal: [], //高德地图赋值搜索内容
};
},
created() {},
watch: {},
methods: {
//select变化调用
selectChange(value, index, prop) {
this.$emit("selectChange", value, index, prop);
},
// input的input事件
inputINPUT(value, index, prop) {
this.$emit("inputINPUT", value, index, prop);
},
// input的change事件
inputChange(value, index, prop) {
this.$emit("inputChange", value, index, prop);
},
// 搜索类型select搜索
remoteMethod(query, index, prop) {
if (query) {
this.searchSelectLoading = true;
this.$emit("querySelectValue", query, index, prop);
setTimeout(() => {
this.formObj[index].options = this.searchSelectOptionsCb;
this.searchSelectLoading = false;
}, 500);
} else {
this.searchSelectOptios = [];
}
},
//switch变化
formSwitchChange(val, index, prop) {
this.$emit("formSwitchChange", val, index, prop);
},
//按钮点击事件
buttonClick(prop, index) {
this.$emit("buttonClick", prop, index);
},
//文件上传成功回调
uploadSuccess(response, file, fileList, limit, prop, index) {
this.formObj[index].uploadObj.hideUpload = fileList.length == limit; //文件列表变化后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮
this.pushUpload(file, fileList, limit, prop);
},
//文件删除
handleRemove(file, fileList, limit, prop, index) {
this.formObj[index].uploadObj.hideUpload = fileList.length == limit; //文件删除后判断当前文件列表长度是否等于限制长度。目的,当长度相等时隐藏文件上传按钮
this.pushUpload(file, fileList, limit, prop);
},
// 文件预览
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
//提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning("请把信息填写完整");
formValidate = false;
}
});
return formValidate;
},
/* 清空表单
逻辑:
1 、如果要清空文件上传列表,要传入要清空的upload的字段名,假如多个upload用for循环,调用清空方法!
2、清空upload之后,还要把upload上传框展示出来,通过字段名比对,获取到在formObj中的下标,通过下标操作对象属性,进行展示
*/
resetForm(uploadArr) {
this.$refs.ruleForm.resetFields();
if (uploadArr) {
for (let i = 0; i < uploadArr.length; i++) {
this.$refs[uploadArr[i]][0].clearFiles();
let index = this.formObj.findIndex(
(item) => item.prop == uploadArr[i]
);
this.formObj[index].uploadObj.hideUpload = false;
}
}
},
// 单个字段验证
validateFieldProp(prop) {
let formValidate = Boolean;
this.$refs.ruleForm.validateField(prop, (valid) => {
if (!valid) {
formValidate = true;
} else {
formValidate = false;
}
});
return formValidate;
},
// 对文件上传,删除进行赋值,调用form验证
pushUpload(file, fileList, limit, prop) {
if (fileList.length > 0) {
this.formData[prop] = fileList;
} else {
// 表示没有数据,把字段置空
this.formData[prop] = "";
}
this.$refs.ruleForm.validateField(prop); //调用验证form表单的文件上传
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-input,
::v-deep.el-select,
::v-deep.el-date-editor.el-input {
width: 208px;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-date-editor .el-range-separator {
width: 20px !important;
}
::v-deep.el-range-editor--small.el-input__inner {
width: 400px;
}
.el-textarea {
width: 400px;
}
.hide {
::v-deep .el-upload--picture-card {
display: none;
}
}
.amap_div {
overflow: hidden;
height: 400px;
width: 600px;
position: relative;
.sreach_ul {
position: absolute;
top: 1;
background-color: white;
z-index: 9;
min-width: 210px;
float: auto;
height: 200px;
overflow: auto;
padding: 0 20px;
line-height: 24px;
}
}
</style>
+99
View File
@@ -0,0 +1,99 @@
<template>
<el-form
ref="ruleForm"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index) in formArr"
v-show="!formItems.notShow"
:key="index"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems.prop,num)"
@getRequestData="getRequestData(index,formItems.prop)"
/>
</el-form-item>
</el-col>
<slot />
</el-row>
</el-form>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
watch: {},
created() {},
methods: {
// select 请求接口
// val返回值,index表单上第几个组件,prop组件名,num一行的组件里的第几个值
outOperation(val, index, prop, num) {
this.$emit('outOperation', val, index, prop, num);
},
// 提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
return formValidate;
},
getRequestData(index, prop) {
if (prop === 'selectLazyLoading') {
this.$emit('getRequestData', index, true);
}
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 17px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
+200
View File
@@ -0,0 +1,200 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type==='input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
</div>
</template>
<script>
import CInput from '../input';
import CTextarea from '../textarea';
import CSelect from '../select';
import CSelectApi from '../selectApi';
import CSelectTree from '../selectTree';
import CSelectTreeApi from '../selectTreeApi';
import CInputNumber from '../inputNumber';
import CInputFinance from '../finance';
import CInputDate from '../inputDate';
import CPickerDate from '../pickerDate';
import CPickerTime from '../pickerTime';
import CRadio from '../radio';
import CCheckbox from '../checkbox';
import CSwitch from '../switch';
import CCascader from '../cascader';
import CTransfer from '../transfer';
import CInputNumber2 from '../inputNumber2';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CInputNumber2,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
+118
View File
@@ -0,0 +1,118 @@
<template>
<el-collapse
v-model="activeNames"
@change="collapseChange"
>
<el-collapse-item
v-for="(item,index) in formArr"
:key="index"
:title="item.title"
:name="index.toString()"
>
<el-form
:ref="`ruleForm${index}`"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index1) in item.formArr"
v-show="!formItems.notShow"
:key="index1"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems.prop,num)"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-collapse-item>
</el-collapse>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
computed: {
activeNames() {
return this.getActiveNames();
},
},
watch: {},
created() {},
methods: {
collapseChange(val) {
console.log(val);
},
outOperation(val, index, prop, num) {
this.$emit('outOperation', val, index, prop, num);
},
async submitForm() {
let formValidate = true;
this.formArr.forEach((_, index) => {
this.$refs[`ruleForm${index}`][0].validate((valid) => {
if (!valid) {
// this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
});
return formValidate;
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
getActiveNames() {
const arr = [];
for (const i in this.formArr) {
if (this.formArr[i].isActive) {
arr.push(i.toString());
}
}
return arr;
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 12px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
@change="handleChangeEvent"
@expand-change="handleExpandchangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
@@ -0,0 +1,58 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
@change="handleChangeEvent($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
@@ -0,0 +1,37 @@
export default {
computed: {
},
methods: {
// --------------------- 组件内部方法 begin ------------------//
handleInputEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleChangeEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleBlurEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleFocusEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleClearEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleExpandchangeEvent() {},
// --------------------- 组件内部方法 end ------------------//
// --------------------- 事件处理 begin ------------------//
// --------------------- 以上为组件支持外部调用的API方法 end ------------------//
},
};
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
this.inputValue = (num * Math.pow(10, unit)).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,151 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-input
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>
{{
formItems.attrs.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>
{{
formItems.attrs.append
}}
</template>
</el-input>
<el-select
v-model="value[1]"
size="mini"
style="margin-left:5px;"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange1(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,88 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInputEvent"
@blur="handleBlurEvent"
@change="handleChangeEvent"
@focus="handleFocusEvent"
@clear="handleClearEvent"
>
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>{{
formItems.attrs.prepend
}}</template>
<template
v-if="formItems.attrs?.append"
slot="append"
>{{
formItems.attrs.append
}}</template>
</el-input>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// d天 m月,y年,
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'd') {
unit = 1;
} else if (lastLetter === 'm') {
unit = 30;
} else if (lastLetter === 'y') {
unit = 365;
}
this.inputValue = (num * unit).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 22px;
line-height: 22px;
top: 2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,78 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:controls-position="formItems.attrs?.['controls-position'] || 'right'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 12px !important;
}
.el-input-number__increase{
top:2px;
}
}
::v-deep.el-input-number--mini.is-controls-right {
.el-input-number__decrease {
bottom:2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,56 @@
<template>
<div class="titiebox">
<div
v-if="label"
:style="{ width: width }"
class="titieboxlabel"
>
<span
v-if="needStar"
style="color: #f00"
>{{ "*" }}</span>{{ label }} <span>{{ ':' }}</span>
</div>
<div class="titieboxvalue">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
needStar: {
type: Boolean,
default: false,
},
width: {
type: String,
default: '80px',
},
},
};
</script>
<style lang="scss" scoped>
.titiebox {
display: flex;
flex-wrap: nowrap;
align-items: center;
font-size: 12px;
width: 100%;
.titieboxlabel {
padding-right: 12px;
height: 24px;
line-height: 24px;
text-align: right;
}
.titieboxvalue {
flex: 1;
box-sizing: border-box;
}
}
</style>
@@ -0,0 +1,195 @@
<template>
<div
class="operateCard"
:style="{width: foldCard ? '24px': width}"
>
<div
v-if="!foldCard"
class="card"
>
<div class="title">
<div class="left">
<el-tooltip
v-for="(item,index) in iconLeftList"
:key="index"
:content="item.text"
placement="bottom"
effect="dark"
class="custom-tooltip"
>
<i
:class="[item.type,'left-icon']"
@click="item.callback(value)"
/>
</el-tooltip>
</div>
<div class="center"><slot /></div>
<div class="right">
<i
v-for="(item,index) in iconRightList"
:key="index"
:class="[item.type,'right-icon']"
@click="item.callback()"
/>
<i
v-if="showFold"
:class="['el-icon-d-arrow-left','right-icon']"
@click="handlefoldCard(true)"
/>
</div>
</div>
<div class="content">
<el-tree
:data="formList"
:props="{
children: children,
label: label
}"
v-bind="operateCardTreeAttrs"
@node-click="handleNodeClick"
/>
</div>
</div>
<div
v-if="foldCard"
class="fold"
>
<i
v-if="showFold"
:class="['el-icon-d-arrow-right']"
@click="handlefoldCard(false)"
/>
</div>
</div>
</template>
<script>
export default {
name: 'OperatedCard',
props: {
iconLeftList: {
type: Array,
default: () => [],
},
iconRightList: {
type: Array,
default: () => [],
},
formList: {
type: Array,
default: () => [],
},
// 折叠按钮
showFold: {
type: Boolean,
default: false,
},
// 组件宽度
width: {
type: String,
default: '200px',
},
//
children: {
type: String,
default: 'children',
},
//
label: {
type: String,
default: 'label',
},
operateCardTreeAttrs: {
type: Object,
default: () => {},
},
},
data() {
return {
foldCard: false,
};
},
methods: {
handlefoldCard(bool) {
this.foldCard = bool;
},
handleNodeClick(row) {
this.$emit('handleNodeClick', row);
},
},
};
</script>
<style lang="scss" scoped>
.operateCard {
height: 100%;
.card {
width: 100%;
height: 100%;
background: var(--card-bg);
border: 1px solid var(--input-border);
.title {
width: 100%;
height: 30px;
padding: 0 5px;
border-bottom: 1px solid var(--input-border);
display: flex;
justify-content: space-between;
align-items: center;
.left-icon {
margin-right: 12px;
cursor: pointer;
}
.center {
font-size: 14px;
}
.right-icon {
cursor: pointer;
}
}
.content {
height: calc(100% - 30px);
// padding: 12px;
overflow: scroll;
.content-items {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
}
.content-items:hover {
background-color: #e6f2ff;
}
.content-items-selected {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
background: #7489ff;
color: #ffffff;
}
}
}
:deep(.el-tree>.el-tree-node){
min-width:100%;
display: inline-block;
}
.fold {
height: 100%;
text-align: center;
padding-left: 2px;
background: var(--card-bg);
border: 1px solid var(--input-border);
}
}
.custom-tooltip {
--el-tooltip-fill: #000000; /* 背景色 */
--el-tooltip-color: #ffffff; /* 文字颜色 */
}
</style>
@@ -0,0 +1,61 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
@blur="handleBlurEvent"
@focus="handleFocusEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
</style>
@@ -0,0 +1,88 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
value-format="yyyy-MM-dd"
@input="handleInputEvent"
@blur="handleBlurEvent"
@focus="handleFocusEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner,
.eui-theme-default .el-date-editor--timerange.el-input,
.eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
// 修复placeholder与日期图标重合的样式
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,70 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-radio-group
class="radio"
size="mini"
:value="value"
@input="handleInputEvent"
>
<el-radio
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-radio>
</el-radio-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.radio {
min-height: 30px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,195 @@
<template>
<div class="rcs-search">
<el-form
ref="form"
:model="form"
label-position="left"
:inline="true"
:rules="customRules || rules"
@submit.native.prevent
>
<template v-for=" (item,index) in search">
<template v-if="item.type === 'input'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-input
v-model.trim="form[item.name]"
:placeholder="item.placeholder||'请输入'"
:title="item.placeholder"
:maxlength="item.maxLength"
clearable
:style="item.styleWidth || defaultWidth"
@keyup.enter.native="doEnter(item.type)"
/>
</el-form-item>
</template>
<template v-if="item.type === 'select'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label&&(!item.isNoSign)?item.label+'':item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-select
v-model.trim="form[item.name]"
:disabled="item.disabled"
:placeholder="item.placeholder||'请选择'"
:filterable="item.filterable||true"
:multiple="item.multiple"
:collapse-tags="item.collapseTags"
:clearable="item.clearable||true"
:remote="item.remote||false"
:remote-method="(query)=>remoteMethod(query,item.name)"
:style="item.styleWidth || defaultWidth"
>
<el-option
v-for="inner in item.options"
:key="inner.value"
:label="inner.text"
:value="inner.value"
/>
</el-select>
</el-form-item>
</template>
<template v-if="item.type === 'date'">
<el-form-item
:key="item.name"
:prop="item.name"
:label="item.label&&(!item.isNoSign)?item.label+'':item.label"
:label-width="item.labelWidth?item.labelWidth + 'px':labelWidth + 'px'"
>
<el-date-picker
v-model.trim="form[item.name]"
type="date"
:value-format="item.format||'yyyy-MM-dd'"
:placeholder="item.placeholder||'请选择'"
/>
</el-form-item>
</template>
</template>
<el-form-item v-if="isShowExpandParams">
<el-button
v-if="!isExpand"
type="text"
@click="updateExpandParams(1)"
>+更多筛选</el-button>
<el-button
v-else
type="text"
@click="updateExpandParams(0)"
>-收起筛选</el-button>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="dosearch()"
>
</el-button>
</el-form-item>
<el-form-item v-if="isShowReset">
<el-button @click="reset()">
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: 'SearchForm',
props: {
search: {
type: Array,
default: () => [],
required: true,
},
labelWidth: {
type: [Number, String],
default: () => '70',
required: false,
},
defaultValues: {
type: Array,
default: () => [],
},
customRules: {
type: Object,
default: null,
},
isShowExpandParams: { // 扩展展开/收起功能 默认值false:没有展开收起功能
type: Boolean,
default: false,
},
isShowReset: {
type: Boolean,
default: true,
},
},
data() {
return {
form: null,
rules: {},
defaultWidth: {
width: '200px',
},
isExpand: false,
};
},
watch: {
defaultValues: {
handler(val) {
this.defaultValues.forEach(item => {
this.$set(this.form, item.key, item.value);
});
},
deep: true,
},
},
created() {
const obj = {};
for (const item of this.search) {
obj[item.name] = undefined;
if (item.isValid) { // 校验必选条件
const message = item.type === 'input' ? '请输入' : '请选择';
this.rules[item.name] = [
{ required: true, message: item.message ? item.message : message, trigger: 'change' },
];
} else if (item.regex) {
this.rules[item.name] = [
{ required: item.required ?? true, validator: item.validator || this.validator, trigger: 'change' }, // 规则校验:默认是必填,有配置required用配置的值
];
}
}
this.defaultValues.forEach(item => {
obj[item.key] = item.value;
});
this.form = obj;
},
mounted() {
console.log('this.form, this.rules------', this.form, this.rules);
},
methods: {
updateExpandParams(val) {
// val1 展开 0 收起
this.isExpand = !this.isExpand;
},
remoteMethod(query, prop) {
this.$emit('onRemote', query, prop);
},
},
};
</script>
<style lang="scss" scoped>
.rcs-search{
::v-deep .el-date-editor .el-input__inner{
padding-left: 30px;
}
}
</style>
@@ -0,0 +1,116 @@
<template>
<!-- formItems.attrs为假的时候会返空-->
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="select-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="(val)=> handleChange(val,0)"
>
<el-option
v-for="item in formItems.options1"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-model="value[1]"
size="mini"
style="margin-left:5px;"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="(val)=> handleChange(val,1)"
>
<el-option
v-for="item in formItems.options2"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val, i) {
this.value[i] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, i);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
.select-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
</style>
@@ -0,0 +1,85 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="handleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item[formItems.attrs?.optionLabel]||item.label||item.text"
:value="item[formItems.attrs?.optionValue]||item.value"
>
<span style="float: left">{{ item[formItems.attrs?.optionLabel]||item.label||item.text }}</span>
<span
v-if="formItems.attrs?.showValue"
>{{ item[formItems.attrs?.optionValue]||item.value }}</span>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,96 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
filterable
remote
reserve-keyword
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:remote-method="selectApi"
:loading="loading"
@focus="selectfocusApi"
@change="handleInput"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
loading: false,
};
},
methods: {
handleInput(value) {
this.$emit('input', value);
},
selectApi(val) {
// this.loading = true;
this.$emit('outOperation', val);
},
// 聚焦时候拿全部数据
selectfocusApi() {
// this.loading = true;
this.$emit('outOperation', undefined);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,174 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
popper-class="lazy-load-select"
remote
:loading="loading"
:remote-method="remoteMethod"
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<!-- 加载状态提示 -->
<div
v-if="formItems.attrs.loadingMore"
class="load-more-tip"
>
<i class="el-icon-loading" /> 加载中...
</div>
<div
v-if="formItems.attrs.noMore"
class="no-more-tip"
>没有更多数据了</div>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
// loading: false,
// loadingMore: false, //加载更多状态
// noMore: false, // 是否没有更多数据
// page: 1,
// pageSize: 10,
// total: 0,
scrollEl: null, // 保存滚动元素引用
};
},
watch: {
formItems(newval) {
this.formItems = newval;
console.log(formItems.attrs.loadingMore);
},
},
beforeDestroy() {
// 关键点5:组件销毁前移除监听
if (this.scrollEl) {
this.scrollEl.removeEventListener('scroll', this.handleScroll);
}
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
// 下拉框显示/隐藏状态变化
handleVisibleChange(visible) {
if (visible) {
this.$nextTick(() => {
// 关键点2:获取下拉框滚动元素
this.scrollEl = document.querySelector(
'.lazy-load-select .el-select-dropdown__wrap',
);
if (this.scrollEl) {
this.scrollEl.addEventListener('scroll', this.handleScroll);
}
});
} else if (this.scrollEl) {
// 移除监听
this.scrollEl.removeEventListener('scroll', this.handleScroll);
this.scrollEl = null;
}
},
// 滚动事件处理
handleScroll() {
if (!this.scrollEl) return;
const { scrollTop, scrollHeight, clientHeight } = this.scrollEl;
const threshold = 50; // 距离底部阈值(px)
// 关键点3:判断是否滚动到底部
if (scrollHeight - (scrollTop + clientHeight) < threshold) {
this.loadMoreData();
}
},
// 加载更多数据
loadMoreData() {
if (this.formItems.attrs.loadingMore || this.formItems.attrs.noMore) return;
// this.page++;
// this.loadData(true);
this.$emit('getRequestData');
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
/* 关键点6:自定义下拉框样式 */
::v-deep.lazy-load-select .el-select-dropdown__wrap {
max-height: 300px; /* 限制下拉框高度 */
}
/* 加载提示样式 */
.load-more-tip,
.no-more-tip {
padding: 8px 0;
text-align: center;
color: #999;
font-size: 12px;
}
.load-more-tip .el-icon-loading {
margin-right: 5px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'value',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'id',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
@@ -0,0 +1,45 @@
<template>
<LabelBox
class="switch"
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-switch
v-model="value"
size="mini"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.switch {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,549 @@
<template>
<div class="table-box">
<div
v-if="tableTopButton.length > 0 || isNeedCustomcolumn"
class="need-btn-line"
>
<!-- 列定制按钮 -->
<el-button
v-if="isNeedCustomcolumn"
type="primary"
size="small"
@click="handlecustomcolumnOpen"
>列定制</el-button>
<!-- 自定义按钮 -->
<el-button
v-for="(value, i) in tableTopButton"
:key="'$' + i"
:style="{ fontSize: fontSize + 'px' }"
size="small"
:type="value.type || 'text'"
:icon="value.icon"
:class="value.class"
@click="value.callback(value)"
>{{ value.text }}</el-button>
</div>
<el-table
ref="tableData"
v-loading="loading"
size="default"
:row-key="rowKey"
:style="{ width: '100%', fontSize: fontSize + 'px' }"
:show-header="showHeader"
:data="tableData"
:height="tableHeight"
:cell-style="cellStyle"
:cell-class-name="tableCellClassName"
:span-method="arraySpanMethod"
:border="border"
:highlight-current-row="highlightCurrentRow"
v-bind="tableInfo"
:stripe="isStripe"
:tree-props="{
children: treePropsChildren,
hasChildren: treePropshasChildren,
}"
v-on="events"
@selection-change="handleSelectionChange"
@select-all="handleSelectionAllChange"
>
<slot name="expand" />
<!-- 多选 -->
<el-table-column
v-if="needSelect"
type="selection"
width="30"
:reserve-selection="isReserve"
/>
<!-- 序号 -->
<el-table-column
v-if="hasIndex"
label="序号"
width="50"
type="index"
/>
<template v-for="(item, index) in tableColumn">
<el-table-column
:key="'%' + index"
:show-overflow-tooltip="!item.notTooltip"
v-bind="item"
v-on="events"
>
<!-- 头部 -->
<template
slot="header"
slot-scope="scope"
>
<i
v-if="item.tableTopColumnIcon"
:class="item.tableTopColumnIcon"
@click="handleTableTopColumnIconClick(item,index)"
/>
{{ item.label }}
<span v-if="item.tableTopColumnCheck">
<el-checkbox
v-model="item.tableTopColumnCheckValue"
:v-bind="item.tableTopColumnCheckValue"
:indeterminate="false"
@change="(val)=>
handleTableTopColumncheckChange(item,index,val)"
/>
</span>
</template>
<template slot-scope="scope">
<!-- render 函数式 -->
<template v-if="item.render">
<ex-slot
:render="item.render"
:index="scope.$index"
:row="scope.row"
:column="item"
:class="item.prop"
:default-value="item.defaultValue"
/>
</template>
<!-- progress 进度条 -->
<template v-else-if="item.progress">
<el-progress :percentage="parseFloat(scope.row[item.prop])" />
</template>
<!-- formatter 自定义 -->
<template v-else-if="item.formatter">
<span v-html="item.formatter(scope.row, item)" />
</template>
<!-- checkbox -->
<template v-else-if="item.tableTopColumnCheck">
<el-checkbox
v-model="scope.row[item.prop]"
@change="(val)=>
handleTableTopColumnRowcheckChange(scope,index,val)"
/>
</template>
<!-- 正常列 -->
<template v-else>
<span>
{{ scope.row[item.prop] }}
</span>
</template>
</template>
</el-table-column>
</template>
<!-- 操作 -->
<el-table-column
v-if="hasOperation"
label="操作"
:min-width="operationWidth"
:fixed="operationFixed ? 'right' : false"
align="center"
>
<template
v-if="btnButton.length"
slot-scope="{ row, column, $index }"
>
<el-button
v-for="(value, i) in btnButton"
:key="'$' + i"
:style="{ fontSize: fontSize + 'px' }"
size="small"
:type="value.type || 'text'"
:icon="value.icon"
:class="value.class || 'el-text-color'"
@click="value.callback(row, column, $index)"
>{{ value.text }}</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div
v-if="isNeedPagination"
:style="{
display: 'flex',
justifyContent: operatedString ? 'space-between' : 'flex-end',
alignItems: 'center',
width: '100%',
}"
>
<div
v-if="operatedString"
class="operated"
>{{ operatedString }}</div>
<el-pagination
ref="pagination"
class="no-border-top"
:page-sizes="pageSizes"
:page-size.sync="computedPageSize"
:hide-on-single-page="isSinglePageHide"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="computedCurrentPage"
:total="total"
:small="small"
:pager-count="pagerCount"
@current-change="currentChange"
@size-change="sizeChange"
/>
</div>
<el-drawer
title="数据列"
:visible.sync="drawer"
direction="rtl"
:before-close="handlecustomcolumnClose"
>
<div
v-for="(item, index) in tableData"
:key="index"
class="drawer-custom"
>
<el-checkbox v-model="item.check">{{ item.label }}</el-checkbox>
</div>
<div class="drawer-footer">
<el-button
size="mini"
class="drawer-footer-confirm-btn"
type="primary"
@click="handlecustomcolumnConfirm"
>确定</el-button>
<el-button
size="mini"
class="drawer-footer-cancel-btn"
@click="handlecustomcolumnCancel"
> </el-button>
</div>
</el-drawer>
</div>
</template>
<script>
// 自定义组件的内容
const exSlot = {
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null,
},
},
render: (h, ctx) => {
const params = {
row: ctx.props.row,
index: ctx.props.index,
};
if (ctx.props.column) params.column = ctx.props.column;
return ctx.props.render(h, params);
},
};
export default {
name: 'PublicTable',
components: {
'ex-slot': exSlot,
},
props: {
// key(唯一key值,和reserve-selection搭配使用)
rowKey: {
type: [Object, Function],
default: () => ({}),
},
// 多选框是否记住上一页数据(必须与row-key唯一值搭配使用)
isReserve: {
type: Boolean,
default: false,
},
// 单元格的 style 的回调方法
cellStyle: {
type: [Object, Function],
default: () => ({}),
},
pagerCount: {
type: Number,
default: 7,
},
// 是否显示表头
showHeader: {
type: Boolean,
default: true,
},
// 是否要高亮当前行
highlightCurrentRow: {
type: Boolean,
default: true,
},
// 获取表格行列索引值
tableCellClassName: {
type: Function,
default: () => {},
},
// 合并行或列
arraySpanMethod: {
type: Function,
default: () => {},
},
// 是否需要多选
needSelect: {
type: Boolean,
default: false,
},
// 是否需要序号
hasIndex: {
type: Boolean,
default: false,
},
// 默认是否选中第一列
isSetCurrentRow: {
type: Boolean,
default: false,
},
// 是否需要分页
isNeedPagination: {
type: Boolean,
default: false,
},
// 是否需要 列定制 按钮
isNeedCustomcolumn: {
type: Boolean,
default: false,
},
// 是否单页隐藏,默认为true
isSinglePageHide: {
type: Boolean,
default: true,
},
// 当前页页码,支持.sync修饰符
currentPage: {
type: Number,
default: 1,
},
// 每页数据条数, 支持.sync修饰符默认为每页10条
pageSize: {
type: Number,
default: 20,
},
// 数据总条数
total: {
type: Number,
default: 0,
},
// 每页多少数据
pageSizes: {
type: Array,
required: false,
default: () => [10, 20, 50, 100],
},
tableInfo: {
type: Object,
default: () => {},
},
// 获取数据时是否需要加载loading
loading: {
type: Boolean,
default: false,
},
tableData: {
type: Array,
default: () => [],
},
// 表格展示数据
tableColumn: {
type: Array,
default: () => [],
},
// 是否需要操作列
hasOperation: {
type: Boolean,
default: true,
},
// 是否需要边框
border: {
type: Boolean,
default: false,
},
// 操作 自定义按钮
btnButton: {
type: Array,
default: () => [],
},
// 表格顶部自定义按钮
tableTopButton: {
type: Array,
default: () => [],
},
// 操作列宽度
operationWidth: {
type: String,
default: '60px',
},
// 固定操作栏
operationFixed: {
type: [Boolean, String],
default: false,
},
// 表格方法
events: {
type: Object,
default: () => {},
},
// 是否为斑马纹 table
isStripe: {
type: Boolean,
default: true,
},
// 树结构(树结构必须有rowKey)
treePropsChildren: {
type: String,
default: 'children',
},
// 树结构(树结构必须有rowKey)
treePropshasChildren: {
type: String,
default: 'hasChildren',
},
// 点击图标计算的值
operatedString: {
type: String,
default: '',
},
},
data() {
return {
fontSize: sessionStorage.getItem('fontSize') || '',
drawer: false,
checked: false,
};
},
computed: {
computedCurrentPage: {
get() {
return this.currentPage;
},
set(val) {
this.$emit('update:currentPage', val);
},
},
computedPageSize: {
get() {
return this.pageSize;
},
set(val) {
this.$emit('update:pageSize', val);
},
},
tableHeight() {
return this.tableInfo?.tableHeight ? this.tableInfo?.tableHeight : !this.isNeedPagination ? '100%' : 'calc(100% - 47px)';
},
},
watch: {
},
mounted() {
if (this.isSetCurrentRow) {
setTimeout(() => {
this.$refs.tableData.setCurrentRow(this.tableData[0]);
}, 500);
}
},
methods: {
getTableRef() {
return this.$refs.tableData;
},
currentChange(val) {
this.$emit('currentChange', val);
},
sizeChange(val) {
this.$emit('sizeChange', val);
},
handlecustomcolumnOpen() {
this.drawer = true;
},
handlecustomcolumnClose(done) {
done();
},
handlecustomcolumnCancel() {
this.drawer = false;
},
handlecustomcolumnConfirm() {
this.drawer = false;
this.$emit('customColumnChange', this.tableData);
},
handleTableTopColumnIconClick(item, index) {
this.$emit('handleTableTopColumnIconClick', item, index);
},
handleTableTopColumncheckChange(item, index, val) {
this.$emit('handleTableTopColumncheckChange', item, index, val);
},
handleTableTopColumnRowcheckChange(item, index, val) {
this.$emit('handleTableTopColumnRowcheckChange', item, index, val);
},
handleSelectionChange(row) {
this.$emit('handleSelectionChange', row);
},
handleSelectionAllChange(row) {
this.$emit('handleSelectionAllChange', row);
},
},
};
</script>
<style lang="scss" scoped>
.table-box {
margin-top: 12px;
background-color: #fff;
border: 1px solid #dfe6ec;
}
.need-btn-line {
padding: 8px;
}
::v-deep .el-table td {
padding: 0;
height: 40px;
}
// // table选中行高亮
// ::v-deep .el-table__body tr.current-row {
// .flex_div {
// background: rgba(21, 91, 212, 0.3) !important;
// }
// td {
// background: rgba(21, 91, 212, 0.3) !important;
// }
// td {
// background: rgba(21, 91, 212, 0.2) !important;
// }
// }
::v-deep .el-pagination {
margin-right: 8px;
}
.drawer-custom {
padding: 8px 16px;
}
.drawer-footer {
position: absolute;
display: flex;
flex-direction: row-reverse;
align-items: center;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
.drawer-footer-confirm-btn,
.drawer-footer-cancel-btn {
margin-right: 12px;
}
}
.operated {
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
width: 50%;
}
</style>
@@ -0,0 +1,51 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
type="textarea"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:value="value"
v-bind="formItems.attrs"
:autosize="{
minRows: formItems.attrs.minRows,
maxRows: formItems.attrs.maxRows,
}"
@input="handleInputEvent"
@blur="handleBlurEvent"
@change="handleChangeEvent"
@focus="handleFocusEvent"
@clear="handleClearEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-textarea .el-textarea__inner {
padding: 0 7px;
line-height: 22px;
}
</style>
@@ -0,0 +1,86 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-transfer
v-model="value"
class="transferBox"
:value="value"
:data="formItems.options"
v-bind="formItems.attrs"
@change="handleChange"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: [],
},
},
methods: {
handleChange(val, direction, movedKeys) {
this.$emit('input', val, direction, movedKeys);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
.transferBox {
display: flex;
flex-wrap: nowrap;
align-items: center;
}
::v-deep .el-transfer-panel {
flex: 1;
}
::v-deep.transferBox .el-transfer__buttons {
padding: 0 10px !important;
.el-button {
padding: 0 0;
}
}
::v-deep.transferBox {
line-height: 24px;
.el-transfer-panel__header {
height: 24px;
.el-checkbox {
height: 24px;
line-height: 24px;
.el-checkbox__label {
font-size: 12px;
}
}
}
.el-checkbox__label {
height: 24px;
line-height: 24px;
span {
font-size: 12px;
}
}
.el-checkbox__input {
// top: 8px;
}
}
</style>
@@ -0,0 +1,230 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type === 'input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择-选择 -->
<CSelectSelect
v-if="formItems.type==='selectSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本输入-选择 -->
<CInputSelect
v-if="formItems.type==='inputSelect'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器拆分单个日期 -->
<CPickerDateSingle
v-if="formItems.type==='pickerDateSingle'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
</div>
</template>
<script>
import CInput from './components/input';
import CTextarea from './components/textarea';
import CSelect from './components/select';
import CSelectApi from './components/selectApi';
import CSelectTree from './components/selectTree';
import CSelectTreeApi from './components/selectTreeApi';
import CInputNumber from './components/inputNumber';
import CInputFinance from './components/finance';
import CInputDate from './components/inputDate';
import CPickerDate from './components/pickerDate';
import CPickerTime from './components/pickerTime';
import CRadio from './components/radio';
import CCheckbox from './components/checkbox';
import CSwitch from './components/switch';
import CCascader from './components/cascader';
import CTransfer from './components/transfer';
import CSelectSelect from './components/select-select';
import CInputNumber2 from './components/inputNumber2';
import CInputSelect from './components/input-select';
import CSelectLazyLoading from './components/selectLazyLoading';
import CPickerDateSingle from './components/pickerDateSingle';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CSelectSelect,
CInputNumber2,
CInputSelect,
CSelectLazyLoading,
CPickerDateSingle,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
@@ -0,0 +1,97 @@
<template>
<el-form
ref="ruleForm"
:model="formData"
class="demo-ruleForm"
inline
>
<el-row>
<el-col
v-for="(formItems, index) in formArr"
v-show="!formItems.notShow"
:key="index"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="(val,num) => outOperation(val, index, formItems,num)"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
watch: {},
created() {},
methods: {
outOperation(val, index, formItems, num) {
// console.log('val, index, formItems, num', val, index, formItems, num);
if (formItems.onchange) {
const changeFn = new Function('value', 'oldValue', formItems.onchange);
changeFn.call(this, val, index, formItems, num);
}
this.$emit('outOperation', val, index, formItems, num);
},
// 提交时验证表单,直接在父级调用
submitForm() {
let formValidate = Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate = true;
} else {
this.$message.warning('请把信息填写完整!');
formValidate = false;
}
});
return formValidate;
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
::v-deep.el-form-item {
width: 100%;
// margin-bottom: 12px;
margin-bottom: 12px;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
@@ -0,0 +1,60 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-cascader
v-model="value"
class="cascader"
size="mini"
:value="value"
:options="formItems.options"
:placeholder="formItems.attrs?.placeholder || '请选择'"
v-bind="formItems.attrs"
:props="{ expandTrigger: 'hover' }"
v-on="formItems.events"
@change="handleChangeEvent"
@expand-change="handleExpandchangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.cascader {
.el-input__inner {
height: 24px;
line-height: 24px;
}
.el-input__icon {
width: 24px;
height: 24px;
line-height: 24px;
}
}
::v-deep .el-cascader--mini {
width: 100%;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-checkbox-group
v-model="value"
class="checkbox"
size="mini"
:value="value"
v-on="formItems.events"
@change="handleChangeEvent($event)"
>
<el-checkbox
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-checkbox>
</el-checkbox-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
};
</script>
<style lang="scss" scoped>
.checkbox {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
::v-deep.el-checkbox .el-checkbox__label {
font-size: 12px;
}
</style>
@@ -0,0 +1,37 @@
export default {
computed: {
},
methods: {
// --------------------- 组件内部方法 begin ------------------//
handleInputEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleChangeEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleBlurEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleFocusEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleClearEvent(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
handleExpandchangeEvent() {},
// --------------------- 组件内部方法 end ------------------//
// --------------------- 事件处理 begin ------------------//
// --------------------- 以上为组件支持外部调用的API方法 end ------------------//
},
};
@@ -0,0 +1,150 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-input
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>
{{
formItems.attrs.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>
{{
formItems.attrs.append
}}
</template>
</el-input>
<el-select
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange1(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 33px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,90 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInputEvent"
@change="handleChangeEvent"
@clear="handleClearEvent"
>
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>{{
formItems.attrs.prepend
}}</template>
<template
v-if="formItems.attrs?.append"
slot="append"
>{{
formItems.attrs.append
}}</template>
</el-input>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input .el-input__inner::placeholder {
color: #fff;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,136 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</LabelBox>
</template>
<script>
// d天 m月,y年,
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'd') {
unit = 1;
} else if (lastLetter === 'm') {
unit = 30;
} else if (lastLetter === 'y') {
unit = 365;
}
this.inputValue = (num * unit).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,146 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@blur="handleBlur"
/>
</LabelBox>
</template>
<script>
// 1k => 1000 1m => 1000000 1b => 1000000000
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
watch: {
value(nVal) {
if (nVal) {
const val = nVal.toString();
this.inputValue = this.inputValueCopy = this.changePercentile(val);
} else {
this.inputValue = this.inputValueCopy = '';
}
},
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
this.$emit('input', this.inputValue);
},
handleBlur() {
this.delcomma();
let inputValue = this.inputValue;
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'k') {
unit = 3;
} else if (lastLetter === 'm') {
unit = 6;
} else if (lastLetter === 'b') {
unit = 9;
}
inputValue = num * Math.pow(10, unit);
}
this.inputValue = this.changePercentile(inputValue);
this.$emit('input', inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.delcomma();
},
// 转换千分位
changePercentile(val) {
return val.toLocaleString('en-US', {
minimumFractionDigits: this.formItems?.attrs?.precision || 2,
maximumFractionDigits: this.formItems?.attrs?.precision || 2,
});
},
// 去掉","号
delcomma() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,148 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="displayValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
@focus="handleFocus"
@blur="handleBlur"
@keydown="handleKeyDown"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: 0,
},
},
data() {
return {
isFocused: false,
localValue: this.parseValue(this.value),
};
},
computed: {
displayValue() {
if (this.isFocused) {
return this.localValue.toString();
}
return this.formatNumber(this.localValue);
},
},
watch: {
value(newVal) {
if (!this.isFocused) {
this.localValue = this.parseValue(newVal);
}
},
},
methods: {
parseValue(value) {
const num = parseFloat(value);
if (isNaN(num)) return 0;
return num;
},
formatNumber(num) {
if (isNaN(num)) return '0.00';
return num.toLocaleString('en-US', {
minimumFractionDigits: this.formItems?.attrs?.precision || 2,
maximumFractionDigits: this.formItems?.attrs?.precision || 2,
});
},
handleInput(e) {
let value = e
.replace(/[^\d.]/g, '') // 移除非数字和小数点
.replace(/\.{2,}/g, '.') // 只保留第一个小数点
.replace(/(\.\d*)\./g, '$1'); // 禁止输入多个小数点
// 处理开头的小数点
if (value.startsWith('.')) {
value = '0' + value;
}
// 拆分整数和小数部分
const parts = value.split('.');
const integerPart = parts[0].replace(/\D/g, '');
let decimalPart = parts[1] || '';
// 限制小数位数
if (decimalPart.length > (this.formItems?.attrs?.precision || 2)) {
decimalPart = decimalPart.substring(0, (this.formItems?.attrs?.precision || 2));
}
// 拼接最终值
const newValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
const numericValue = parseFloat(newValue) || 0;
// 更新本地值和触发事件
this.localValue = numericValue;
// console.log('this.localValue', this.localValue);
this.$emit('input', this.localValue);
},
handleFocus() {
this.isFocused = true;
},
handleBlur() {
this.isFocused = false;
this.localValue = this.parseValue(this.localValue);
this.$emit('input', this.localValue);
this.$emit('outOperation', this.localValue);
},
handleKeyDown(e) {
// 阻止非法字符输入
if (['e', 'E', '+', '-'].includes(e.key)) {
e.preventDefault();
}
},
},
};
</script>
<style scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 32px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 22px;
line-height: 22px;
top: 2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 32px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,78 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:controls-position="formItems.attrs?.['controls-position'] || 'right'"
label="描述文字"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 32px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 12px !important;
}
.el-input-number__increase{
top:2px;
}
}
::v-deep.el-input-number--mini.is-controls-right {
.el-input-number__decrease {
bottom:2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 32px;
line-height: 23px;
// color: #f00;
}
}
</style>
@@ -0,0 +1,60 @@
<template>
<div class="titiebox">
<div
v-if="label"
:style="{ width: width }"
class="titieboxlabel"
>
{{ label }} <span
v-if="needStar"
style="color: #f00"
>{{ "*" }}</span>
</div>
<div class="titieboxvalue">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
needStar: {
type: Boolean,
default: false,
},
width: {
type: String,
default: '150px',
},
},
};
</script>
<style lang="scss" scoped>
.titiebox {
display: flex;
flex-wrap: nowrap;
align-items: center;
font-size: 12px;
border-left: 1px solid var(--card-border);
width: 100%;
.titieboxlabel {
border-top: 1px solid var(--card-border);
padding-left: 8px;
padding-right: 8px;
height: 32px;
line-height: 32px;
text-align: left;
background-color: var(--desktop-bg-color-2);
}
.titieboxvalue {
flex: 1;
box-sizing: border-box;
}
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor .el-input__inner {
height: 32px;
}
</style>
@@ -0,0 +1,87 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
format="yyyy-MM-dd"
value-format="yyyyMMdd"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner,
.eui-theme-default .el-date-editor--timerange.el-input,
.eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
// 修复placeholder与日期图标重合的样式
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,59 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-date-picker
class="datePicker"
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择日期'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep.el-range-editor {
// height: 20px;
// }
::v-deep.el-range-editor.el-input__inner {
height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
</style>
@@ -0,0 +1,70 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,72 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-time-picker
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '选择时间'"
v-bind="formItems.attrs"
format="hh:mm"
value-format="hhmm"
@input="handleInputEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
import fieldMixin from '../fieldMixin';
export default {
components: {
LabelBox,
},
mixins: [fieldMixin],
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-range-editor--mini .el-range-separator {
line-height: 16px;
}
::v-deep.el-range-editor--mini .el-range__icon {
line-height: 16px;
}
::v-deep.el-range-editor.el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-date-editor--daterange.el-input__inner, .eui-theme-default .el-date-editor--timerange.el-input, .eui-theme-default .el-date-editor--timerange.el-input__inner {
width: 100%;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner{
padding-left: 19px;
}
</style>
@@ -0,0 +1,52 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-radio-group
class="radio"
size="mini"
:value="value"
@input="handleInputEvent"
>
<el-radio
v-for="(options, i) in formItems.options"
:key="i"
:label="options.label"
>
{{ options.value }}
</el-radio>
</el-radio-group>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.radio {
min-height: 30px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,150 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-input
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请填写'"
v-bind="formItems.attrs2"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs2?.prepend"
slot="prepend"
>
{{
formItems.attrs2.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs2?.append"
slot="append"
>
{{
formItems.attrs2.append
}}
</template>
</el-input>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange1(val) {
this.value[0] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-input .el-input__icon {
height: 32px;
line-height: 33px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 32px;
line-height: 32px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
@@ -0,0 +1,115 @@
<template>
<!-- formItems.attrs为假的时候会返空-->
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="select-select">
<el-select
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
@change="(val)=> handleChange(val,0)"
>
<el-option
v-for="item in formItems.options1"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select
v-model="value[1]"
size="mini"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="(val)=> handleChange(val,1)"
>
<el-option
v-for="item in formItems.options2"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleChange(val, i) {
this.value[i] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, i);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
.select-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
</style>
@@ -0,0 +1,86 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
v-on="formItems.events"
@change="handleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item[formItems.attrs?.optionLabel]||item.label||item.text"
:value="item[formItems.attrs?.optionValue]||item.value"
>
<span style="float: left">{{ item[formItems.attrs?.optionLabel]||item.label||item.text }}</span>
<span
v-if="formItems.attrs?.showValueName"
>{{ item[formItems.attrs?.showValueName]||item.value }}</span>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,96 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
filterable
remote
reserve-keyword
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:remote-method="selectApi"
:loading="loading"
@focus="selectfocusApi"
@change="handleInput"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
loading: false,
};
},
methods: {
handleInput(value) {
this.$emit('input', value);
},
selectApi(val) {
// this.loading = true;
this.$emit('outOperation', val);
},
// 聚焦时候拿全部数据
selectfocusApi() {
// this.loading = true;
this.$emit('outOperation', undefined);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,174 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
v-model="value"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs?.filterable || true"
v-bind="formItems.attrs"
popper-class="lazy-load-select"
remote
:loading="loading"
:remote-method="remoteMethod"
@change="handleChange"
@visible-change="handleVisibleChange"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<!-- 加载状态提示 -->
<div
v-if="formItems.attrs.loadingMore"
class="load-more-tip"
>
<i class="el-icon-loading" /> 加载中...
</div>
<div
v-if="formItems.attrs.noMore"
class="no-more-tip"
>没有更多数据了</div>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
data() {
return {
// loading: false,
// loadingMore: false, //加载更多状态
// noMore: false, // 是否没有更多数据
// page: 1,
// pageSize: 10,
// total: 0,
scrollEl: null, // 保存滚动元素引用
};
},
watch: {
formItems(newval) {
this.formItems = newval;
console.log(formItems.attrs.loadingMore);
},
},
beforeDestroy() {
// 关键点5:组件销毁前移除监听
if (this.scrollEl) {
this.scrollEl.removeEventListener('scroll', this.handleScroll);
}
},
methods: {
handleChange(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
// 下拉框显示/隐藏状态变化
handleVisibleChange(visible) {
if (visible) {
this.$nextTick(() => {
// 关键点2:获取下拉框滚动元素
this.scrollEl = document.querySelector(
'.lazy-load-select .el-select-dropdown__wrap',
);
if (this.scrollEl) {
this.scrollEl.addEventListener('scroll', this.handleScroll);
}
});
} else if (this.scrollEl) {
// 移除监听
this.scrollEl.removeEventListener('scroll', this.handleScroll);
this.scrollEl = null;
}
},
// 滚动事件处理
handleScroll() {
if (!this.scrollEl) return;
const { scrollTop, scrollHeight, clientHeight } = this.scrollEl;
const threshold = 50; // 距离底部阈值(px)
// 关键点3:判断是否滚动到底部
if (scrollHeight - (scrollTop + clientHeight) < threshold) {
this.loadMoreData();
}
},
// 加载更多数据
loadMoreData() {
if (this.formItems.attrs.loadingMore || this.formItems.attrs.noMore) return;
// this.page++;
// this.loadData(true);
this.$emit('getRequestData');
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 32px;
line-height: 32px;
}
::v-deep.input-box {
height: 32px;
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
/* 关键点6:自定义下拉框样式 */
::v-deep.lazy-load-select .el-select-dropdown__wrap {
max-height: 300px; /* 限制下拉框高度 */
}
/* 加载提示样式 */
.load-more-tip,
.no-more-tip {
padding: 8px 0;
text-align: center;
color: #999;
font-size: 12px;
}
.load-more-tip .el-icon-loading {
margin-right: 5px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'value',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,210 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-select
ref="select"
v-model="value"
size="mini"
:multiple="false"
:placeholder="formItems.attrs?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
style="width: 100%"
v-bind="formItems.attrs"
>
<el-option
ref="option"
class="tree-select__option"
:value="optionData.value"
:label="optionData.label"
>
<el-tree
ref="tree"
class="tree-select__tree"
:class="`tree-select__tree--${
formItems.attrs?.multiple ? 'checked' : 'radio'
}`"
:node-key="nodeKey"
:data="formItems.options"
:props="props"
:show-checkbox="formItems.attrs?.multiple || false"
:highlight-current="!formItems.attrs?.multiple || false"
:expand-on-click-node="formItems.attrs?.multiple || false"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
@check-change="handleCheckChange"
/>
</el-option>
</el-select>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
name: 'TreeSelect',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: true,
},
// 每个树节点用来作为唯一标识的属性
nodeKey: {
type: [String, Number],
default: 'id',
},
filterable: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// tree的props配置
props: {
type: Object,
default: function() {
return {
label: 'label',
children: 'children',
};
},
},
},
data() {
return {
optionData: {
value: '',
label: '',
},
};
},
watch: {
value: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
formItems: {
handler(val) {
if (this.formItems.prop && val) {
this.init(val);
}
},
immediate: true,
deep: true,
},
},
created() {},
methods: {
init(val) {
// 多选
if (this.formItems.attrs?.multiple) {
const arr = val.toString().split(',');
this.$nextTick(() => {
this.$refs.tree.setCheckedKeys(arr);
const nodes = this.$refs.tree.getCheckedNodes();
this.optionData.value = val;
this.optionData.label = nodes
.map((item) => item[this.props.label])
.join(',');
});
}
// 单选
else {
val = val === '' ? null : val;
this.$nextTick(() => {
this.$refs.tree.setCurrentKey(val);
if (val === null) {
return;
}
const node = this.$refs.tree.getNode(val);
this.optionData.value = val;
this.optionData.label = node.label;
});
}
},
handleNodeClick(data) {
if (this.formItems.attrs?.multiple) {
return;
}
this.$emit('input', data[this.nodeKey]);
this.$emit('outOperation', data[this.nodeKey]);
this.$refs.select.visible = false;
},
handleCheckChange() {
const nodes = this.$refs.tree.getCheckedNodes();
const value = nodes.map((item) => item[this.nodeKey]).join(',');
this.$emit('input', value);
this.$emit('outOperation', value);
},
filterMethod(val) {
this.$refs.tree.filter(val);
},
filterNode(value, data) {
if (!value) return true;
const label = this.props.label || 'label';
return data[label].indexOf(value) !== -1;
},
},
};
</script>
<style lang="scss" scoped>
.tree-select__option {
&.el-select-dropdown__item {
height: auto;
line-height: 1;
padding: 0;
background-color: #fff;
}
}
.tree-select__tree {
padding: 4px 0px;
font-weight: 400;
&.tree-select__tree--radio {
.el-tree-node.is-current > .el-tree-node__content {
font-weight: 700;
color: #ff0000;
}
}
}
::v-deep.el-select .el-input__icon {
height: 32px;
line-height: 33px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 32px;
line-height: 32px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 32px;
line-height: 32px;
}
</style>
@@ -0,0 +1,45 @@
<template>
<LabelBox
class="switch"
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-switch
v-model="value"
size="mini"
v-bind="formItems.attrs"
@change="handleChangeEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
.switch {
min-height: 28px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
}
</style>
@@ -0,0 +1,51 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
type="textarea"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:value="value"
v-bind="formItems.attrs"
:autosize="{
minRows: formItems.attrs.minRows,
maxRows: formItems.attrs.maxRows,
}"
@input="handleInputEvent"
@blur="handleBlurEvent"
@change="handleChangeEvent"
@focus="handleFocusEvent"
@clear="handleClearEvent"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-textarea .el-textarea__inner {
padding: 0 7px;
line-height: 30px;
}
</style>
@@ -0,0 +1,86 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-transfer
v-model="value"
class="transferBox"
:value="value"
:data="formItems.options"
v-bind="formItems.attrs"
@change="handleChange"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: [],
},
},
methods: {
handleChange(val, direction, movedKeys) {
this.$emit('input', val, direction, movedKeys);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
.transferBox {
display: flex;
flex-wrap: nowrap;
align-items: center;
}
::v-deep .el-transfer-panel {
flex: 1;
}
::v-deep.transferBox .el-transfer__buttons {
padding: 0 10px !important;
.el-button {
padding: 0 0;
}
}
::v-deep.transferBox {
line-height: 24px;
.el-transfer-panel__header {
height: 24px;
.el-checkbox {
height: 24px;
line-height: 24px;
.el-checkbox__label {
font-size: 12px;
}
}
}
.el-checkbox__label {
height: 24px;
line-height: 24px;
span {
font-size: 12px;
}
}
.el-checkbox__input {
// top: 8px;
}
}
</style>
+231
View File
@@ -0,0 +1,231 @@
<template>
<div>
<!-- 文本 -->
<CInput
v-if="formItems.type === 'input'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 文本域 -->
<CTextarea
v-if="formItems.type==='textarea'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器 -->
<CInputNumber
v-if="formItems.type==='inputNumber'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 计数器2 -->
<CInputNumber2
v-if="formItems.type==='inputNumber2'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择 单选 多选 -->
<CSelect
v-if="formItems.type==='select'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择单选 多选 调接口 -->
<CSelectApi
v-if="formItems.type==='selectApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选 -->
<CSelectTree
v-if="formItems.type==='selectTree'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 选择树单选 多选调接口 未完成 -->
<CSelectTreeApi
v-if="formItems.type==='selectTreeApi'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 金额数字输入 -->
<CInputFinance
v-if="formItems.type==='inputFinance'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- input数字 年月日 -->
<CInputDate
v-if="formItems.type==='inputDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器 -->
<CPickerDate
v-if="formItems.type==='pickerDate'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTime
v-if="formItems.type==='pickerTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 时间选择器 -->
<CPickerTimeHHMM
v-if="formItems.type==='pickerTimeHHMM'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期 时间 选择器 -->
<CpickerDateTime
v-if="formItems.type==='pickerDateTime'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 单选 -->
<CRadio
v-if="formItems.type==='radio'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 多选 -->
<CCheckbox
v-if="formItems.type==='checkbox'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 开关 -->
<CSwitch
v-if="formItems.type==='switch'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 级联选择 -->
<CCascader
v-if="formItems.type==='cascader'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 穿梭 -->
<CTransfer
v-if="formItems.type==='transfer'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 日期选择器拆分单个日期 -->
<CPickerDateSingle
v-if="formItems.type==='pickerDateSingle'"
v-model="formData[formItems.prop]"
:form-items="formItems"
@outOperation="outOperation"
/>
<!-- 上传-->
</div>
</template>
<script>
import CInput from './components/input';
import CTextarea from './components/textarea';
import CSelect from './components/select';
import CSelectApi from './components/selectApi';
import CSelectTree from './components/selectTree';
import CSelectTreeApi from './components/selectTreeApi';
import CInputNumber from './components/inputNumber';
import CInputFinance from './components/inputFinance';
import CInputDate from './components/inputDate';
import CPickerDate from './components/pickerDate';
import CPickerTime from './components/pickerTime';
import CPickerTimeHHMM from './components/pickerTimeHHMM';
import CpickerDateTime from './components/pickerDateTime';
import CRadio from './components/radio';
import CCheckbox from './components/checkbox';
import CSwitch from './components/switch';
import CCascader from './components/cascader';
import CTransfer from './components/transfer';
import CInputNumber2 from './components/inputNumber2';
import CPickerDateSingle from './components/pickerDateSingle';
export default {
name: 'FormItem',
components: {
CInput,
CTextarea,
CSelect,
CSelectApi,
CSelectTree,
CSelectTreeApi,
CInputNumber,
CInputFinance,
CInputDate,
CPickerDate,
CPickerTime,
CPickerTimeHHMM,
CPickerDateSingle,
CpickerDateTime,
CRadio,
CCheckbox,
CSwitch,
CCascader,
CTransfer,
CInputNumber2,
},
props: {
formItems: {
type: Object,
default: () => {},
},
formData: {
type: Object,
default: () => {},
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
},
outOperation(val, num) {
this.$emit('outOperation', val, num);
},
},
};
</script>
+133
View File
@@ -0,0 +1,133 @@
<template>
<div>
<div
v-for="(item, num) in formArr"
:key="num"
>
<div class="card">
<div class="htitle">
<span class="label" />
<span class="value">{{ item.title }}</span>
</div>
</div>
<el-form
:ref="`ruleForm${num}`"
:model="formData"
class="bookkeeping-form"
inline
>
<el-row>
<el-col
v-for="(formItems, num1) in item.formArr"
v-show="!formItems.notShow"
:key="num1"
:span="formItems.span"
>
<el-form-item
:label="null"
:prop="formItems.prop"
:rules="formItems.rules"
>
<FormItem
v-if="formItems.prop"
v-model="formData[formItems.prop]"
:form-items="formItems"
:form-data="formData"
@outOperation="
(val, num2) => outOperation(val, num, num1, num2, formItems,formItems.prop)
"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</div>
</template>
<script>
import FormItem from './formItem.vue';
export default {
components: {
FormItem,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {};
},
methods: {
outOperation(val, num1, num2, num3, formItems, prop) {
if (formItems.onchange) {
const changeFn = new Function('value', 'oldValue', formItems.onchange);
changeFn.call(this, val, num1, num2, num3, formItems);
}
this.$emit('outOperation', val, num1, num2, num3, formItems, prop);
},
submitForm() {
let formValidate = true;
this.formArr.forEach((_, index) => {
this.$refs[`ruleForm${index}`][0].validate((valid) => {
if (!valid) {
formValidate = false;
}
});
});
return formValidate;
},
resetForm() {
this.formArr.forEach((_, index) => {
this.$refs[`ruleForm${index}`][0].resetFields();
});
},
},
};
</script>
<style lang="scss" scoped>
form {
overflow: hidden;
}
.bookkeeping-form {
border-bottom: 1px solid var(--card-border);
}
.card {
.htitle {
margin-top: 12px;
display: flex;
align-items: center;
border-radius: 4px 4px 0 0;
height: 32px;
line-height: 32px;
border-top: 1px solid var(--card-border);
border-left: 1px solid var(--card-border);
border-right: 1px solid var(--card-border);
.label {
margin-left: 9px;
width: 3px;
height: 14px;
background-color: rgb(51, 137, 255);
border-radius: 3px;
}
.value {
margin-left: 8px;
font-size: 12px;
}
}
}
::v-deep.el-form-item {
width: 100%;
margin-bottom: 0;
}
::v-deep.el-form-item .el-form-item__content {
width: 100%;
}
</style>
+149
View File
@@ -0,0 +1,149 @@
<template>
<div
class="search-form"
:class="{ close: !search_open }"
>
<Form
ref="form"
class="form"
:form-arr="formArr"
:form-data="formData"
@outOperation="outOperation"
>
<el-col
v-if="!isShowSpread||(search_open&&isShowSpread)"
:span="4"
:class="searchStyle"
>
<div
class="search"
:style="isShowSpread?'text-align:right':''"
>
<slot name="defineBtn" />
<el-button
type="primary"
size="small"
@click="searchSubmit"
>查询</el-button>
<!-- icon="el-icon-search" -->
<el-button
size="small"
plain
@click="reset"
>重置</el-button>
<el-button
v-if="search_open&&isShowSpread"
type="text"
size="small"
@click="searchOpenClose(false)"
>收起<i class="el-icon-arrow-up" /></el-button>
</div>
</el-col>
</Form>
<div
v-if="!search_open&&isShowSpread"
class="search"
:style="isShowSpread?'text-align:right':''"
>
<slot name="defineBtn" />
<el-button
type="primary"
size="small"
@click="searchSubmit"
>查询</el-button>
<!-- icon="el-icon-search" -->
<el-button
size="small"
plain
@click="reset"
>重置</el-button>
<el-button
type="text"
size="small"
@click="searchOpenClose(true)"
>展开<i class="el-icon-arrow-down" /></el-button>
</div>
</div>
</template>
<script>
import Form from '../form';
export default {
components: {
Form,
},
props: {
formArr: {
type: Array,
required: true,
},
formData: {
type: Object,
required: true,
},
},
data() {
return {
search_open: false,
};
},
computed: {
isShowSpread() {
return this.formArr.reduce((sum, item) => sum + item.span, 0) > 24;
},
searchStyle() {
return this.formArr.length % 6 === 0 ? 'search-class' : '';
},
},
watch: {},
created() {},
methods: {
outOperation(val, index, prop, num) {
this.$emit('outOperation', val, index, prop, num);
},
searchSubmit() {
if (this.$refs.form.submitForm()) {
this.$emit('searchSubmit', this.formData);
} else {
console.log('submitForm Error');
}
},
reset() {
this.$emit('reset');
},
resetForm() {
this.$refs.form.resetForm();
},
searchOpenClose(boolean) {
this.search_open = boolean;
},
},
};
</script>
<style lang="scss" scoped>
.search-form {
display: flex;
flex-wrap: nowrap;
background-color: var(--bg-color-2);
padding: 8px;
.form {
flex: 1;
}
.search {
width: 220px;
padding:3px 8px 0 ;
}
}
.search-class{
float:right;
.search{
float:right
}
}
.close {
height: 50px;
// overflow: hidden;
}
</style>
+171
View File
@@ -0,0 +1,171 @@
<template>
<el-dialog
title="历史版本比较"
:visible.sync="ownVisible"
@close="handleCancel"
>
<el-table
v-loading="loading"
:data="tableData"
border
:row-key="rowKey"
style="width: 100%"
>
<el-table-column align="right">
<template
slot="header"
slot-scope="scope"
>
<span>{{ $t('field.version') }}</span>
</template>
<template slot-scope="scope">
<span>{{ $t(`${scope.row.langId}`) }}</span>
</template>
</el-table-column>
<el-table-column align="right">
<template
slot="header"
slot-scope="scope"
>
<el-select
v-model="selectedValue[0]"
@change="(value)=>versionChange(value,0)"
>
<el-option
v-for="(item,index) in options"
:key="index"
:label="item.value"
:value="item.text"
/>
</el-select>
</template>
<template slot-scope="scope">
<span
:style="scope.row.versionData1===scope.row.versionData2?'':'color:red'"
>{{ scope.row.versionData1 }}</span>
</template>
</el-table-column>
<el-table-column align="right">
<template
slot="header"
slot-scope="scope"
>
<el-select
v-model="selectedValue[1]"
@change="(value)=>versionChange(value,1)"
>
<el-option
v-for="(item,index) in options"
:key="index"
:label="item.value"
:value="item.text"
/>
</el-select>
</template>
<template slot-scope="scope">
<span
:style="scope.row.versionData1===scope.row.versionData2?'':'color:red'"
>{{ scope.row.versionData2 }}</span>
</template>
</el-table-column>
</el-table>
</el-dialog>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false,
},
dataId: {
type: String,
default: false,
},
type: {
type: String,
default: false,
},
rowKey: {
type: String,
default: 'id',
},
module: {
type: String,
default: 'pub',
}
},
data() {
return {
tableData: [],
options: [],
loading: false,
ownVisible: false,
selectedValue: [],
apiObj: {
pub: {
getCompareVersion: 'getCompareVersion',
versionsCombox: 'versionsCombox',
compare: 'compare',
},
dcs: {
getCompareVersion: 'getCompareVersionLog',
versionsCombox: 'versionsLogCombox',
compare: 'compareVersionLog',
}
}
};
},
computed: {},
methods: {
handleCancel() {
this.$emit('handleCancel');
},
versionChange(value, index) {
this.getDataList();
},
onOpen() {
this.$nextTick(async () => {
const versionRes = await this.$apis[this.apiObj[this.module].getCompareVersion]({ dataId: this.dataId })
if (versionRes.data.result.length === 0) {
this.$message.warning('该条数据未存储过历史版本数据');
this.$emit('handleCancel');
this.ownVisible = false;
return;
}
this.ownVisible = this.visible;
this.loading = true;
this.selectedValue = versionRes.data.result
await this.getHistoryVersions();
this.getDataList();
})
},
async getHistoryVersions() {
// 请求版本号接口
const versionRes = await this.$apis[this.apiObj[this.module].versionsCombox]({ dataId: this.dataId })
this.options = versionRes.data.result;
},
async getDataList() {
// 请求表格数据
const params = {
type: this.type ? this.type : this.dataId.split('_')[0],
dataId: this.dataId,
version1: this.selectedValue[0],
version2: this.selectedValue[1]
}
const versionRes = await this.$apis[this.apiObj[this.module].compare](params)
if (versionRes.success) {
this.tableData = versionRes.data.result
}
this.loading = false;
},
},
};
</script>
<style lang="scss" scoped>
// ::v-deep .el-table thead {
// display: none;
// }
</style>
+53
View File
@@ -0,0 +1,53 @@
<template>
<svg
class="icon"
aria-hidden="true"
:style="iconStyle"
@click="handleClick"
>
<use :xlink:href="`#${name}`" />
</svg>
</template>
<script>
export default {
name: 'IconFont',
props: {
name: {
type: String,
required: true,
},
size: {
type: [Number, String],
default: 16,
},
color: {
type: String,
default: '',
},
},
computed: {
iconStyle() {
return {
fontSize: typeof this.size === 'number' ? `${this.size}px` : this.size,
color: this.color,
};
},
},
methods: {
handleClick() {
this.$emit('click');
},
},
};
</script>
<style scoped>
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
+324
View File
@@ -0,0 +1,324 @@
<template>
<div>
<el-dialog
title="导入"
:visible.sync="visibleDialog"
width="640px"
@close="close"
>
<el-upload
drag
v-bind="$attrs"
:show-file-list="false"
:accept="fileConfig?.accept||'.xls,.xlsx'"
:auto-upload="false"
:on-change="uploadChange"
>
<i class="el-icon-upload" />
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div
slot="tip"
class="el-upload__tip"
>
<div>请按照数据模板的格式准备导入数据模板中的表头名称不可更改表头行不能删除
<el-button
type="text"
:size="$buttonSize"
@click="downloadTemplate"
>下载模板</el-button></div>
<div style="margin-bottom:16px">文件后缀名必须为xls 或xlsx即Excel格式文件大小不得大于1GB</div>
<div class="file-list">
<div
v-for="(v,i) in fileList"
:key="i"
class="file-li"
>
<div>
{{ v.name }}
<el-button
v-if="v.data.notImportableNum>0"
type="text"
:size="$buttonSize"
@click="viewReason(v)"
>查看原因</el-button>
</div>
<div class="right-status">
<i
:class="v.data.notImportableNum>0?'el-icon-error':'el-icon-success'"
:style="v.data.notImportableNum>0?'color:red':'color:green'"
/>
</div>
<div class="right-btn">
<i
class="el-icon-delete-solid"
@click="deleteFileItem(v,i)"
/>
</div>
<!-- <el-progress
v-if="v.process!=100"
:percentage="v.process"
/> -->
</div>
</div>
</div></el-upload>
<div
slot="footer"
class="dialog-footer"
>
<el-button
:size="$buttonSize"
@click="close"
>{{
$t("button.cancel")
}}</el-button>
<el-button
type="primary"
:size="$buttonSize"
@click="submit"
>{{
$t("button.confirm")
}}</el-button>
</div>
</el-dialog>
<el-dialog
title="查看原因"
:visible.sync="failDialog"
width="640px"
@close="failClose"
>
<div class="import-false">
<div class="false-box">
<span class="fail-text">导入失败明细</span>
<span class="fail-num">总数</span><span>{{ failObj.failNum+failObj.successNum }}</span>
<span class="fail-num">通过</span><span style="color: rgba(32, 201, 139, 1);font-size: 16px;">{{ failObj.successNum }}</span>
<span class="fail-num">失败</span><span style="color: rgba(233, 86, 82, 1);font-size: 16px;">{{ failObj.failNum }}</span>
</div>
<p style="margin-top:16px">以下是本次导入失败的列表详情请修改后重新导入<el-button
type="text"
:size="$buttonSize"
@click="downLoadReason"
>下载失败原因</el-button></p>
<el-table :data="failObj.list">
<el-table-column
v-for="v in tableColumns"
:key="v.prop"
:prop="v.prop"
:label="v.label"
:width="v.width"
/>
</el-table>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
showDialog: {
type: Boolean,
default: false,
},
fileConfig: {
type: Object,
default: () => ({}),
},
},
data() {
return {
visibleDialog: false,
processData: {},
fileList: [],
failObj: {},
failDialog: false,
tableColumns: [],
};
},
watch: {
showDialog: {
handler(nv) {
this.visibleDialog = nv;
},
},
},
mounted() {},
methods: {
failClose() {
this.failObj = {};
},
viewReason(row) { // 查看原因
this.failObj = row.data;
console.log(this.failObj, 'failObj');
this.failDialog = true;
},
downLoadReason() { // 下载失败原因
},
deleteFileItem(v, i) {
this.fileList.splice(i, 1);
},
close() {
this.visibleDialog = false;
this.fileList = [];
this.failObj = {};
this.processData = {};
this.$emit('update:showDialog', false);
},
jyFile(file) { // 校验文件
console.log(file, 'file');
const maxSize = this.fileConfig?.size ? this.fileConfig?.size * 1024 * 1024 : 1024 * 1024 * 1024; // 10MB,根据你的需求设置最大文件大小
if (file.size > maxSize) {
this.$message.warning(`文件大小超过了${maxSize / (1024 * 1024)}MB的限制`);
return false;
}
return true;
},
async uploadChange(e, fileList) {
const file = e.raw;
if (!this.jyFile(file)) return;
console.log(file, fileList, this.fileConfig, 'file');
const fileData = new FormData();
for (const key in this.fileConfig.uploadParams) {
if (Object.hasOwnProperty.call(this.fileConfig.uploadParams, key)) {
fileData.append(key, key === 'param' ? JSON.stringify(this.fileConfig.uploadParams[key]) : this.fileConfig.uploadParams[key]);
}
}
fileData.append('file', file);
// const res = await this.$apis.importCheck(params);
const url = window.origin.replace(/^https?:/, '') + (process.env.NODE_ENV !== 'production' ? '/dev' : '') + '/pub/baseData/importCheck.action';
console.log(url, 'uuu');
fetch(url, {
method: 'POST',
body: fileData,
}).then(response => response.json()) // 假设服务器返回 JSON 数据
.then(async res => {
await this.$apis.getProcess({ importKey: res.data.result }).then(res => {
this.processData = res.data.result;
this.fileList = [...this.fileList, { name: file.name, process: res.data.result.progress, data: res.data.result }];
console.log(this.fileList, '文件');
this.tableColumns = [
{ label: '行号', prop: 'line', width: 100 },
...res.data.result.columns.map(v => {
return {
label: v.title,
prop: v.field,
};
}),
{ label: '失败原因', prop: 'reason' },
];
console.log(this.tableColumns, 'this.tableColumns ');
});
this.$emit('importCallBack', file);
});
},
async downloadTemplate() {
const { data, fileName } = await this.$apis.downLoadTemplate({ moduleName: this.fileConfig.uploadParams.moduleName });
console.log(data, fileName, 'flfl');
const link = document.createElement('a');
link.href = URL.createObjectURL(data);
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
// const url = window.origin.replace(/^https?:/, '') + (process.env.NODE_ENV !== 'production' ? '/dev' : '') + `/pub/baseData/downloadTemplate.action?moduleName=${this.fileConfig.uploadParams.moduleName}`;
// fetch(url, {
// method: 'GET',
// })
// .then(async(response) => {
// if (!response.ok) {
// const text = await response.text();
// throw new Error(text);
// }
// const contentDisposition = response.headers.get(
// 'Content-Disposition',
// );
// let filename = '导出文件.csv'; // 默认值
// if (contentDisposition) {
// const filenameMatch = contentDisposition.match(
// /filename=("?)([^";]+)\1/i,
// );
// if (filenameMatch && filenameMatch[2]) {
// const encodedName = filenameMatch[2].replace(/\+/g, '%20');
// filename = decodeURIComponent(encodedName);
// }
// }
// return response.blob().then((blob) => ({ blob, filename }));
// })
// .then(({ blob, filename }) => {
// console.log(blob, filename, '文件信息');
// const link = document.createElement('a');
// link.href = URL.createObjectURL(blob);
// link.download = filename; // 动态设置文件名
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// URL.revokeObjectURL(link.href);
// })
// .catch((error) => {
// console.error('下载失败:', error);
// });
// console.log(res, 'res');
},
submit() {
this.$apis.importData({ importKey: this.processData.importKey }).then(res => {
});
},
},
};
</script>
<style lang="scss" scoped>
:deep(.el-upload-dragger),:deep(.el-upload){
width:100%
}
.import-false{
color:var(--table-text-color);
background-color: var(--card-bg);
.false-box{
border-radius: 4px;
opacity: 1;
height:45px;
display:flex;
align-items: center;
}
}
.fail-text{
color:var(--color-90);
margin-right:12px
}
.fail-num{
color:var(--color-44);
font-size:12px;
margin-left:25px
}
.file-li{
height:24px;
cursor:pointer;
display:flex;
justify-content: space-between;
align-items: center;
padding:0 8px;
font-size:14px;
.right-btn{
display: none;
}
.right-status{
display:block
}
i{
font-size:14px
}
}
.file-li:hover{
background:var(--card-border);
.right-btn{
display:block
}
.right-status{
display:none
}
}
</style>
+94
View File
@@ -0,0 +1,94 @@
<template>
<el-dialog
:title="config.title"
:visible.sync="dialogVisible"
:width="config.width"
class="infoShow"
:before-close="handleClose"
>
<ul
class="box"
:style="{ maxHeight: config.height }"
>
<li
v-for="(item, index) in config.lists"
:key="index"
class="item"
>
<h4>{{ item.group }}</h4>
<el-row>
<el-col
v-for="(inner, idx) in item.children"
:key="idx"
:span="inner.col"
>
<span>{{ inner.key }}</span>
<span>{{ inner.value }}</span>
</el-col>
</el-row>
</li>
</ul>
</el-dialog>
</template>
<script>
export default {
name: 'InfoShow',
props: {
config: {
type: Object,
default: () => {},
},
},
data() {
return {
dialogVisible: false,
};
},
mounted() {
},
methods: {
init() {
this.dialogVisible = true;
},
handleClose() {
this.dialogVisible = false;
},
},
};
</script>
<style lang="scss" scoped>
.infoShow{
.box{
margin: 0;
padding: 0;
overflow: hidden;
overflow-y: auto;
.item{
margin-bottom: 10px;
&:last-child{
margin-bottom: 0;
}
h4{
margin: 10px 0;
}
.el-col{
margin-bottom: 10px;
display: flex;
span{
display: inline-block;
&:nth-of-type(1) {
width: 90px;
margin-right: 10px;
color: rgba(0, 0, 0, 0.5);
}
&:nth-of-type(2) {
flex: 1;
}
}
}
}
}
}
</style>
+153
View File
@@ -0,0 +1,153 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<div class="input-select">
<el-input
v-model="value[0]"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
@input="handleChange"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>
{{
formItems.attrs.prepend
}}
</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>
{{
formItems.attrs.append
}}
</template>
</el-input>
<el-select
v-model="value[1]"
size="mini"
style="margin-left:5px;"
:placeholder="formItems.attrs2?.placeholder || '请选择'"
:clearable="formItems.clearable || true"
:filterable="formItems.attrs2?.filterable || true"
v-bind="formItems.attrs2"
@change="handleChange1"
>
<el-option
v-for="item in formItems.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Array,
default: () => [],
},
},
methods: {
handleChange(val) {
this.value[0] = val;
console.log(this.value);
this.$emit('input', this.value);
this.$emit('outOperation', val, 0);
},
handleChange1(val) {
this.value[1] = val;
this.$emit('input', this.value);
this.$emit('outOperation', val, 1);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-select {
width: 100%;
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-select .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-select .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-select .el-input__inner {
height: 24px;
line-height: 24px;
}
.input-select {
width: 100%;
display: flex;
flex-wrap: nowrap;
}
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
+91
View File
@@ -0,0 +1,91 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
size="mini"
:value="value"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
>
<!-- 前文字 -->
<template
v-if="formItems.attrs?.prepend"
slot="prepend"
>{{
formItems.attrs.prepend
}}</template>
<!-- 后文字 -->
<template
v-if="formItems.attrs?.append"
slot="append"
>{{
formItems.attrs.append
}}</template>
</el-input>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: String,
default: '',
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
margin-left: -6px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
::v-deep.el-input--prefix .el-input__inner {
padding-left: 19px;
}
</style>
+135
View File
@@ -0,0 +1,135 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input
v-model="inputValue"
type="text"
:placeholder="formItems.attrs?.placeholder || '请填写'"
v-bind="formItems.attrs"
v-on="formItems.events"
@input="handleInput"
/>
</LabelBox>
</template>
<script>
// d天 m月,y年,
import LabelBox from '../labelBox/index.vue';
export default {
name: 'NumberInput',
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: [Number, String],
default: null,
},
digit: {
type: Number,
default: 0,
},
},
data() {
return {
inputValue: '',
inputValueCopy: '',
};
},
mounted() {
this.inputValue = this.value
? this.value.toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
})
: ''; // 转换千分位
},
methods: {
handleInput(value) {
// 使用正则表达式限制只能输入数字、指定英文和一个小数点
const regex = /^[0-9bkmBKM]*\.?[0-9bkmBKM]*$/;
// 如果输入的值不符合正则规则,则回退到上一次的值
if (!regex.test(value)) {
this.inputValue = this.inputValueCopy;
} else {
this.inputValue = value;
this.inputValueCopy = value;
}
},
handleBlur() {
if (this.inputValue) {
const lastLetter = this.getLastLetter(this.inputValue);
const firstLetter = this.getFirstLetter(this.inputValue);
const num = firstLetter
? this.inputValue.split(firstLetter)[0].replace(/[a-zA-Z]/g, '') * 1
: this.inputValue.replace(/[a-zA-Z]/g, '') * 1; // 去除字母
let unit = 0;
if (lastLetter === 'd') {
unit = 1;
} else if (lastLetter === 'm') {
unit = 30;
} else if (lastLetter === 'y') {
unit = 365;
}
this.inputValue = (num * unit).toLocaleString('en-US', {
minimumFractionDigits: this.digit,
maximumFractionDigits: this.digit,
}); // 转换千分位
}
this.$emit('input', this.inputValue);
this.$emit('outOperation', this.inputValue);
},
handleFocus() {
this.inputValue = this.inputValueCopy = this.inputValue.replace(/,/g, '');
},
// 获取第一个字母
getFirstLetter(str) {
return str.match(/[a-zA-Z]/)?.[0] || '';
},
// 获取最后一个字母
getLastLetter(str) {
const letters = str.match(/[a-zA-Z]/g); // 使用正则表达式匹配所有字母
if (letters) {
return letters[letters.length - 1]; // 返回最后一个字母
}
return '';
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep.input-box {
height: 24px;
}
::v-deep.el-input .el-input__icon {
height: 24px;
line-height: 25px;
}
::v-deep.el-input .el-input-group__prepend {
box-sizing: border-box;
padding: 0 10px;
height: 24px;
line-height: 24px;
border: none;
}
::v-deep.el-input .el-input__inner {
height: 24px;
line-height: 24px;
}
</style>
+89
View File
@@ -0,0 +1,89 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
label="描述文字"
v-bind="formItems.attrs"
v-on="formItems.events"
@change="handleInput"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 22px;
line-height: 22px;
top: 2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
+95
View File
@@ -0,0 +1,95 @@
<template>
<LabelBox
:label="formItems.attrs?.label"
:need-star="formItems.attrs?.needStar"
:width="formItems.attrs?.width"
>
<el-input-number
v-model="value"
class="numberInput"
size="mini"
:placeholder="formItems.attrs?.placeholder || '请填写'"
:controls-position="formItems.attrs?.['controls-position'] || 'right'"
label="描述文字"
v-bind="formItems.attrs"
v-on="formItems.events"
@change="handleInput"
/>
</LabelBox>
</template>
<script>
import LabelBox from '../labelBox/index.vue';
export default {
components: {
LabelBox,
},
props: {
formItems: {
type: Object,
default: () => {},
},
value: {
type: Number,
default: 0,
},
},
data() {
return {
formItems: {},
};
},
watch: {
formItems(newval) {
this.formItems = newval;
},
},
methods: {
handleInput(val) {
this.$emit('input', val);
this.$emit('outOperation', val);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep.el-input {
height: 24px;
line-height: 24px;
}
::v-deep .el-input-number {
width: 100%;
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
height: 24px;
}
}
::v-deep.el-input-number--mini {
.el-input-number__increase,
.el-input-number__decrease {
width: 22px;
height: 12px !important;
}
.el-input-number__increase{
top:2px;
}
}
::v-deep.el-input-number--mini.is-controls-right {
.el-input-number__decrease {
bottom:2px;
}
}
::v-deep.numberInput .el-input--mini {
.el-input__inner {
text-align: center;
height: 24px;
line-height: 23px;
// color: #f00;
}
}
</style>
+57
View File
@@ -0,0 +1,57 @@
<template>
<div class="titiebox">
<div
v-if="label"
:style="{ width: width }"
class="titieboxlabel"
>
<span
v-if="needStar"
style="color: #f00"
>{{ "*" }}</span>{{ label }}
<!-- <span>{{ ':' }}</span> -->
</div>
<div class="titieboxvalue">
<slot />
</div>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
default: '',
},
needStar: {
type: Boolean,
default: false,
},
width: {
type: String,
default: '100px',
},
},
};
</script>
<style lang="scss" scoped>
.titiebox {
display: flex;
flex-wrap: nowrap;
align-items: center;
font-size: 12px;
width: 100%;
.titieboxlabel {
padding-right: 12px;
height: 24px;
line-height: 24px;
text-align: right;
}
.titieboxvalue {
flex: 1;
box-sizing: border-box;
}
}
</style>
+196
View File
@@ -0,0 +1,196 @@
export default [{
value: 'zhinan',
label: '指南1',
children: [{
value: 'shejiyuanze',
label: '设计原则',
children: [{
value: 'yizhi',
label: '一致',
}, {
value: 'fankui',
label: '反馈',
}, {
value: 'xiaolv',
label: '效率',
}, {
value: 'kekong',
label: '可控',
}],
}, {
value: 'daohang',
label: '导航',
children: [{
value: 'cexiangdaohang',
label: '侧向导航',
}, {
value: 'dingbudaohang',
label: '顶部导航',
}],
}],
}, {
value: 'zujian',
label: '组件',
children: [{
value: 'basic',
label: 'Basic',
children: [{
value: 'layout',
label: 'Layout 布局',
}, {
value: 'color',
label: 'Color 色彩',
}, {
value: 'typography',
label: 'Typography 字体',
}, {
value: 'icon',
label: 'Icon 图标',
}, {
value: 'button',
label: 'Button 按钮',
}],
}, {
value: 'form',
label: 'Form',
children: [{
value: 'radio',
label: 'Radio 单选框',
}, {
value: 'checkbox',
label: 'Checkbox 多选框',
}, {
value: 'input',
label: 'Input 输入框',
}, {
value: 'input-number',
label: 'InputNumber 计数器',
}, {
value: 'select',
label: 'Select 选择器',
}, {
value: 'cascader',
label: 'Cascader 级联选择器',
}, {
value: 'switch',
label: 'Switch 开关',
}, {
value: 'slider',
label: 'Slider 滑块',
}, {
value: 'time-picker',
label: 'TimePicker 时间选择器',
}, {
value: 'date-picker',
label: 'DatePicker 日期选择器',
}, {
value: 'datetime-picker',
label: 'DateTimePicker 日期时间选择器',
}, {
value: 'upload',
label: 'Upload 上传',
}, {
value: 'rate',
label: 'Rate 评分',
}, {
value: 'form',
label: 'Form 表单',
}],
}, {
value: 'data',
label: 'Data',
children: [{
value: 'table',
label: 'Table 表格',
}, {
value: 'tag',
label: 'Tag 标签',
}, {
value: 'progress',
label: 'Progress 进度条',
}, {
value: 'tree',
label: 'Tree 树形控件',
}, {
value: 'pagination',
label: 'Pagination 分页',
}, {
value: 'badge',
label: 'Badge 标记',
}],
}, {
value: 'notice',
label: 'Notice',
children: [{
value: 'alert',
label: 'Alert 警告',
}, {
value: 'loading',
label: 'Loading 加载',
}, {
value: 'message',
label: 'Message 消息提示',
}, {
value: 'message-box',
label: 'MessageBox 弹框',
}, {
value: 'notification',
label: 'Notification 通知',
}],
}, {
value: 'navigation',
label: 'Navigation',
children: [{
value: 'menu',
label: 'NavMenu 导航菜单',
}, {
value: 'tabs',
label: 'Tabs 标签页',
}, {
value: 'breadcrumb',
label: 'Breadcrumb 面包屑',
}, {
value: 'dropdown',
label: 'Dropdown 下拉菜单',
}, {
value: 'steps',
label: 'Steps 步骤条',
}],
}, {
value: 'others',
label: 'Others',
children: [{
value: 'dialog',
label: 'Dialog 对话框',
}, {
value: 'tooltip',
label: 'Tooltip 文字提示',
}, {
value: 'popover',
label: 'Popover 弹出框',
}, {
value: 'card',
label: 'Card 卡片',
}, {
value: 'carousel',
label: 'Carousel 走马灯',
}, {
value: 'collapse',
label: 'Collapse 折叠面板',
}],
}],
}, {
value: 'ziyuan',
label: '资源',
children: [{
value: 'axure',
label: 'Axure Components',
}, {
value: 'sketch',
label: 'Sketch Templates',
}, {
value: 'jiaohu',
label: '组件交互文档',
}],
}];
+262
View File
@@ -0,0 +1,262 @@
<template>
<div
class="operateCard"
:style="{width: foldCard ? '24px': width}"
>
<div
v-if="!foldCard"
class="card"
>
<div class="title">
<div
v-if="iconLeftList?.length >0"
class="left"
>
<el-tooltip
v-for="(item,index) in iconLeftList"
:key="index"
:content="item.text"
placement="bottom"
effect="dark"
class="custom-tooltip"
>
<i
:class="[item.type,'left-icon']"
@click="item.callback(value)"
/>
</el-tooltip>
</div>
<div class="center">
<span class="ctitle">{{ title }}</span>
<slot />
</div>
<div
v-if="iconRightList?.length >0"
class="right"
>
<i
v-for="(item,index) in iconRightList"
:key="index"
:class="[item.type,'right-icon']"
@click="item.callback()"
/>
<i
v-if="showFold"
:class="['el-icon-d-arrow-left','right-icon']"
@click="handlefoldCard(true)"
/>
</div>
</div>
<div class="content">
<el-input
style="width: 90%;margin-left: 7%;margin-top: 8px;margin-bottom: 8px;"
v-if="showSearch"
placeholder="输入关键词,可快速查找..."
v-model="filterText">
</el-input>
<el-tree
ref="tree"
:node-key="nodeKey"
:data="formList"
:render-content="renderContent"
:props="{
children: children,
label: label
}"
v-bind="operateCardTreeAttrs"
@node-click="handleNodeClick"
:filter-node-method="filterNode"
/>
</div>
</div>
<div
v-if="foldCard"
class="fold"
>
<i
v-if="showFold"
:class="['el-icon-d-arrow-right']"
@click="handlefoldCard(false)"
/>
</div>
</div>
</template>
<script>
export default {
name: 'OperatedCard',
props: {
//
showSearch: {
type: Boolean,
default: false,
},
//
title: {
type: String,
default: '',
},
// key
nodeKey: {
type: String,
default: 'id',
},
iconLeftList: {
type: Array,
default: () => [],
},
iconRightList: {
type: Array,
default: () => [],
},
formList: {
type: Array,
default: () => [],
},
//
showFold: {
type: Boolean,
default: false,
},
//
width: {
type: String,
default: '220px',
},
//
children: {
type: String,
default: 'children',
},
//
label: {
type: String,
default: 'label',
},
operateCardTreeAttrs: {
type: Object,
default: () => {},
},
//
customRenderContent: {
type: Boolean,
default: false,
},
renderContent: {
type: Function,
require: false,
default: (h, { node, data }) => {
return (<span class="">{data}</span>);
},
},
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
}
},
data() {
return {
filterText: '',
foldCard: false,
};
},
methods: {
filterNode(value, data) {
if (!value) return true;
return data[this.label].indexOf(value) !== -1;
},
handlefoldCard(bool) {
this.foldCard = bool;
},
handleNodeClick(row) {
this.$emit('handleNodeClick', row);
},
},
};
</script>
<style lang="scss" scoped>
.operateCard {
height: 100%;
.card {
width: 100%;
height: 100%;
background: var(--desktop-bg-color-1);
// border: 1px solid var(--input-border);
.title {
width: 100%;
height: 30px;
padding: 0 5px;
border-bottom: 1px solid var(--input-border);
display: flex;
justify-content: space-between;
align-items: center;
.left-icon {
margin-right: 12px;
cursor: pointer;
}
.center {
font-size: 14px;
.ctitle {
font-weight: 700;
margin-left: 12px;
}
}
.right-icon {
cursor: pointer;
}
}
.content {
height: calc(100% - 30px);
// padding: 12px;
overflow: scroll;
.content-items {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
}
.content-items:hover {
background-color: #e6f2ff;
}
.content-items-selected {
height: 32px;
white-space: nowrap;
cursor: pointer;
padding-left: 19px;
font-size: 12px;
line-height: 32px;
background: var(--blue-50);
color: var(--card-bg);
}
}
}
:deep(.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content){
background: var(--blue-20);
}
:deep(.el-tree>.el-tree-node){
min-width:100%;
display: inline-block;
}
.fold {
height: 100%;
text-align: center;
padding-left: 2px;
background: var(--card-bg);
border: 1px solid var(--input-border);
}
}
.custom-tooltip {
--el-tooltip-fill: #000000; /* 背景色 */
--el-tooltip-color: #ffffff; /* 文字颜色 */
}
</style>

Some files were not shown because too many files have changed in this diff Show More