| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- /**
- * H5版本的字段格式化工具函数
- * 基于小程序版本改造,适配H5环境
- */
- /**
- * 获取字典翻译 - H5版本
- * @param {string} cbName - 字典名称
- * @param {string|number} value - 值
- * @param {string} cacheKey - 缓存键
- * @param {Map} dictCache - 字典缓存
- * @param {Function} updateCallback - 更新回调函数
- */
- const getDictTranslation = async (
- cbName,
- value,
- cacheKey,
- dictCache,
- updateCallback
- ) => {
- try {
- console.log(`🔍 获取字典翻译 [${cbName}:${value}]`);
- // 使用 loadObjpOpt 接口调用字典
- const result = await request.post(
- "/service?ssServ=loadObjpOpt&objectpickerdropdown1=1",
- {
- objectpickerparam: JSON.stringify({
- input: "false",
- codebook: cbName,
- }),
- objectpickertype: 2, // 2表示获取要回显的一项
- objectpickervalue: value, // 需回显的值
- },
- { loading: false, formData: true }
- );
- console.log(`字典翻译 [${cbName}:${value}] API返回:`, result);
- // 处理返回数据格式:{"result":{"622182":"会议室A"}}
- let translatedValue = value; // 默认返回原值
- if (result && result.data && result.data.result) {
- // 从result对象中根据value查找对应的翻译
- translatedValue = result.data.result[value] || value;
- console.log(`字典翻译结果: ${value} -> ${translatedValue}`);
- }
- dictCache.set(cacheKey, translatedValue);
- // 触发页面更新
- if (updateCallback) {
- updateCallback();
- }
- } catch (error) {
- console.error(`字典翻译失败 [${cbName}:${value}]:`, error);
- dictCache.set(cacheKey, value);
- }
- };
- /**
- * 格式化字段值(处理字典翻译、日期格式等)- H5版本
- * @param {Object} fieldObj - 字段对象 {field, value}
- * @param {Map} dictCache - 字典缓存
- * @param {Function} getDictTranslationFn - 字典翻译函数
- * @returns {string} 格式化后的值
- */
- const formatFieldValue = (fieldObj, dictCache, getDictTranslationFn) => {
- if (!fieldObj || !fieldObj.field || fieldObj.value === undefined) {
- return "";
- }
- const { field, value } = fieldObj;
- // 空值处理
- if (value === null || value === undefined || value === "") {
- return "";
- }
- // 如果字段有字典配置,进行字典翻译
- if (field.cbName) {
- const cacheKey = `${field.cbName}_${value}`;
- // 先从缓存中查找
- if (dictCache.has(cacheKey)) {
- return dictCache.get(cacheKey);
- }
- // 缓存中没有,异步获取翻译
- if (getDictTranslationFn) {
- getDictTranslationFn(field.cbName, value, cacheKey, dictCache);
- }
- // 返回原值作为临时显示
- return value;
- }
- // 时间格式化(优先检查fmt字段)
- if (field.fmt) {
- return h5FormatDate(value, field.fmt);
- }
- // 日期格式化(兼容旧逻辑)
- if (
- field.type === "date" ||
- field.name.toLowerCase().includes("date") ||
- field.name.toLowerCase().includes("time")
- ) {
- return h5FormatDate(value);
- }
- // 数字格式化
- if (field.type === "number" && typeof value === "number") {
- return value.toLocaleString();
- }
- // 布尔值格式化
- if (field.type === "boolean" || typeof value === "boolean") {
- return value ? "是" : "否";
- }
- // 默认返回字符串
- return String(value);
- };
- /**
- * 规范化日期字符串,兼容异常空白符和乱码分隔符
- * @param {string|Date|number} value - 原始日期值
- * @returns {string} 规范化后的日期字符串
- */
- const normalizeDateInput = (value) => {
- if (value === null || value === undefined) return "";
- return (
- String(value)
- // 功能说明:兼容接口里被错误转码的窄空格(如  PM),避免标题时间无法格式化 by xu 2026-03-06
- .replace(/ /g, " ")
- .replace(/[\u00A0\u1680\u180E\u2000-\u200D\u202F\u205F\u3000]/g, " ")
- .replace(/(\d)(AM|PM)$/i, "$1 $2")
- .replace(/\s+/g, " ")
- .trim()
- );
- };
- /**
- * 解析特殊日期格式:Jul 4, 2025, 6:00:00 AM
- * @param {string} dateStr - 日期字符串
- * @returns {object|null} 解析后的日期对象或null
- */
- const parseSpecialDateFormat = (dateStr) => {
- try {
- const normalizedDateStr = normalizeDateInput(dateStr);
- // 匹配格式:Jul 4, 2025, 6:00:00 AM
- const regex =
- /^(\w{3})\s+(\d{1,2}),\s+(\d{4}),\s+(\d{1,2}):(\d{2}):(\d{2})\s+(AM|PM)$/i;
- const match = normalizedDateStr.match(regex);
- if (!match) return null;
- const [, monthStr, day, year, hour, minute, second, ampmRaw] = match;
- const ampm = String(ampmRaw).toUpperCase();
- // 月份映射
- const months = {
- Jan: 0,
- Feb: 1,
- Mar: 2,
- Apr: 3,
- May: 4,
- Jun: 5,
- Jul: 6,
- Aug: 7,
- Sep: 8,
- Oct: 9,
- Nov: 10,
- Dec: 11,
- };
- const month = months[monthStr];
- if (month === undefined) return null;
- // 处理12小时制
- let hour24 = parseInt(hour);
- if (ampm === "PM" && hour24 !== 12) {
- hour24 += 12;
- } else if (ampm === "AM" && hour24 === 12) {
- hour24 = 0;
- }
- return {
- year: parseInt(year),
- month: month,
- day: parseInt(day),
- hour: hour24,
- minute: parseInt(minute),
- second: parseInt(second),
- };
- } catch (error) {
- console.warn("解析特殊日期格式失败:", dateStr, error);
- return null;
- }
- };
- /**
- * 格式化日期对象
- * @param {object} dateObj - 日期对象 {year, month, day, hour, minute, second}
- * @param {string} format - 格式字符串
- * @returns {string} 格式化后的字符串
- */
- const formatDateObject = (dateObj, format) => {
- const { year, month, day, hour, minute, second } = dateObj;
- return format
- .replace(/YYYY/g, year)
- .replace(/yyyy/g, year)
- .replace(/MM/g, String(month + 1).padStart(2, "0"))
- .replace(/DD/g, String(day).padStart(2, "0"))
- .replace(/dd/g, String(day).padStart(2, "0"))
- .replace(/HH/g, String(hour).padStart(2, "0"))
- .replace(/hh/g, String(hour).padStart(2, "0"))
- .replace(/mm/g, String(minute).padStart(2, "0"))
- .replace(/ss/g, String(second).padStart(2, "0"));
- };
- /**
- * 增强的日期格式化函数 - H5版本
- * @param {string|Date} date - 日期,支持多种格式如 "Jul 4, 2025, 6:00:00 AM"
- * @param {string} format - 格式,如 'YYYY-MM-DD HH:mm:ss'
- * @returns {string} 格式化后的日期
- */
- const h5FormatDate = (date, format = "YYYY-MM-DD HH:mm:ss") => {
- if (!date) return "";
- try {
- const normalizedDate = normalizeDateInput(date);
- console.log(
- `🔧 h5FormatDate 开始处理:`,
- normalizedDate,
- "目标格式:",
- format
- );
- // 手动解析特殊格式:Jul 4, 2025, 6:00:00 AM
- const parseResult = parseSpecialDateFormat(normalizedDate);
- if (parseResult) {
- console.log(`🔧 手动解析成功:`, parseResult);
- const result = formatDateObject(parseResult, format);
- console.log(`✅ 手动格式化结果:`, result);
- return result;
- }
- // 使用 Day.js 解析日期(更强大的日期解析能力)
- if (typeof window !== "undefined" && window.dayjs) {
- const dayObj = window.dayjs(normalizedDate);
- console.log(`🔧 使用 Day.js 解析:`, dayObj.isValid(), dayObj.toString());
- if (dayObj.isValid()) {
- const result = dayObj.format(format);
- console.log(`✅ Day.js 格式化结果:`, result);
- return result;
- }
- }
- // 降级到原生 Date(如果 Day.js 未加载)
- console.log(`🔧 Day.js 未加载,使用原生 Date`);
- const d = new Date(normalizedDate);
- console.log(`🔧 解析后的日期对象:`, d, "是否有效:", !isNaN(d.getTime()));
- // 检查日期是否有效
- if (isNaN(d.getTime())) {
- console.warn("❌ 无效日期格式:", normalizedDate);
- return normalizedDate; // 无效日期返回原值
- }
- const year = d.getFullYear();
- const month = String(d.getMonth() + 1).padStart(2, "0");
- const day = String(d.getDate()).padStart(2, "0");
- const hours = String(d.getHours()).padStart(2, "0");
- const minutes = String(d.getMinutes()).padStart(2, "0");
- const seconds = String(d.getSeconds()).padStart(2, "0");
- // 支持多种格式模式
- let result = format
- .replace(/YYYY/g, year)
- .replace(/yyyy/g, year)
- .replace(/MM/g, month)
- .replace(/DD/g, day)
- .replace(/dd/g, day)
- .replace(/HH/g, hours)
- .replace(/hh/g, hours)
- .replace(/mm/g, minutes)
- .replace(/ss/g, seconds);
- console.log(`日期格式化: ${date} -> ${result} (格式: ${format})`);
- return result;
- } catch (error) {
- console.error("日期格式化异常:", date, format, error);
- return date; // 异常时返回原值
- }
- };
- /**
- * 异步格式化字段值 - 支持字典转换
- * @param {object} fieldData - 字段数据 {field, value}
- * @param {Map} dictCache - 字典缓存
- * @returns {Promise<string>} 格式化后的值
- */
- const formatFieldValueAsync = async (fieldData, dictCache) => {
- if (!fieldData || !fieldData.field) {
- return fieldData?.value || "";
- }
- const { field, value } = fieldData;
- // 空值处理
- if (value === null || value === undefined || value === "") {
- return "";
- }
- // 优先处理时间格式化(如果字段有fmt属性)
- if (field.fmt) {
- try {
- console.log(
- `🕐 格式化时间字段 [${field.name}]:`,
- value,
- "格式:",
- field.fmt
- );
- console.log(`🔧 调用 h5FormatDate 前...`);
- const formattedTime = h5FormatDate(value, field.fmt);
- console.log(`🔧 调用 h5FormatDate 后,结果:`, formattedTime);
- console.log(`✅ 时间格式化结果:`, formattedTime);
- return formattedTime;
- } catch (error) {
- console.error("❌ 时间格式化失败:", field.name, value, error);
- // 格式化失败,返回原值
- return value;
- }
- }
- // 如果字段有字典配置,进行字典转换
- if (field.cbName) {
- const cacheKey = `${field.cbName}_${value}`;
- // 先从缓存中查找
- if (dictCache && dictCache.has(cacheKey)) {
- return dictCache.get(cacheKey);
- }
- // 缓存中没有,异步获取翻译
- try {
- const result = await request.post(
- `/service?ssServ=loadObjpOpt&objectpickerdropdown1=1`,
- {
- objectpickerparam: JSON.stringify({
- input: "false",
- codebook: field.cbName,
- }),
- objectpickertype: 2,
- objectpickervalue: value,
- },
- {
- loading: false,
- formData: true,
- }
- );
- if (
- result &&
- result.data &&
- result.data.result &&
- result.data.result[value]
- ) {
- const translatedValue = result.data.result[value];
- // 缓存结果
- if (dictCache) {
- dictCache.set(cacheKey, translatedValue);
- }
- return translatedValue;
- }
- } catch (error) {
- console.warn("字典转换失败:", field.cbName, value, error);
- }
- // 转换失败,返回原值
- return value;
- }
- // 日期格式化
- if (field.type === 3 && field.fmt) {
- return h5FormatDate(value, field.fmt);
- }
- // 数字格式化
- if (field.type === 2 && typeof value === "number") {
- return value.toLocaleString();
- }
- // 默认返回字符串
- return value.toString();
- };
- /**
- * 获取字典所有选项 - 用于下拉菜单
- * @param {string} cbName - 字典名称
- * @param {Map} dictCache - 字典缓存
- * @returns {Promise<Array>} 选项列表 [{n: '显示名', v: '值'}]
- */
- const getDictOptions = async (cbName, dictCache) => {
- const cacheKey = `options_${cbName}`;
- // 检查缓存
- if (dictCache && dictCache.has(cacheKey)) {
- return dictCache.get(cacheKey);
- }
- try {
- console.log(`🔍 获取字典选项 [${cbName}]`);
- const result = await request.post(
- `/service?ssServ=loadObjpOpt&objectpickerdropdown1=1`,
- {
- objectpickerparam: JSON.stringify({
- input: "false",
- codebook: cbName,
- }),
- objectpickertype: 1,
- objectpickersearchAll: 1,
- },
- {
- loading: false,
- formData: true,
- }
- );
- console.log(`字典选项 [${cbName}] API返回:`, result);
- if (result && result.data && result.data.result) {
- const options = Object.entries(result.data.result).map(
- ([value, label]) => ({
- n: label,
- v: value,
- })
- );
- // 缓存结果
- if (dictCache) {
- dictCache.set(cacheKey, options);
- }
- return options;
- }
- return [];
- } catch (error) {
- console.error(`❌ 获取字典选项失败 [${cbName}]:`, error);
- return [];
- }
- };
- /**
- * 格式化对象列表数据 - 处理API返回的objectList
- * @param {Array} objectList - 原始对象列表
- * @param {Map} dictCache - 字典缓存
- * @returns {Promise<Array>} 格式化后的列表
- */
- const formatObjectList = async (objectList, dictCache) => {
- if (!Array.isArray(objectList)) return [];
- const formattedList = [];
- for (const item of objectList) {
- const formattedItem = { ...item };
- // 格式化 first 字段
- if (item.first) {
- formattedItem.firstDisplay = await formatFieldValueAsync(
- item.first,
- dictCache
- );
- } else if (
- item.title &&
- typeof item.title === "object" &&
- item.title.val !== undefined
- ) {
- // 功能说明:兼容 title={val,fmt} 结构,标题字段为日期时间时按 fmt 格式化,避免卡片标题直接显示原始时间串 by xu 2026-03-06
- if (item.title.fmt) {
- formattedItem.firstDisplay = h5FormatDate(
- item.title.val,
- item.title.fmt
- );
- } else {
- formattedItem.firstDisplay =
- item.title.val === undefined || item.title.val === null
- ? ""
- : String(item.title.val);
- }
- } else if (typeof item.title === "string") {
- // 兼容 title 直出字符串结构 by xu 2026-03-03
- formattedItem.firstDisplay = item.title;
- }
- // 格式化 second 字段
- if (item.second) {
- formattedItem.secondDisplay = await formatFieldValueAsync(
- item.second,
- dictCache
- );
- } else {
- // 兼容 abs/desc/summary 结构(移动端接口常见) by xu 2026-03-03
- const secondFallback = item.abs ?? item.desc ?? item.summary;
- if (secondFallback !== undefined && secondFallback !== null) {
- formattedItem.secondDisplay = String(secondFallback);
- }
- }
- // 格式化 third 字段组
- if (item.third && Array.isArray(item.third)) {
- formattedItem.thirdDisplay = [];
- for (const group of item.third) {
- const formattedGroup = [];
- for (const fieldData of group) {
- const displayValue = await formatFieldValueAsync(
- fieldData,
- dictCache
- );
- formattedGroup.push({
- ...fieldData,
- displayValue,
- });
- }
- formattedItem.thirdDisplay.push(formattedGroup);
- }
- } else if (Array.isArray(item.catList)) {
- // 功能说明:兼容 catList 结构,若有 fmt 则按日期格式化,避免列表属性时间字段直接显示 Oracle 原始串 by xu 2026-03-06
- const formattedCatList = [];
- for (const catItem of item.catList) {
- const fieldData = {
- field: {
- desc: String(catItem?.desc || ""),
- fmt: catItem?.fmt || "",
- },
- value: catItem?.val,
- };
- const displayValue = await formatFieldValueAsync(fieldData, dictCache);
- formattedCatList.push({
- field: {
- desc: String(catItem?.desc || ""),
- },
- value: catItem?.val,
- displayValue,
- });
- }
- formattedItem.thirdDisplay = [formattedCatList];
- }
- formattedList.push(formattedItem);
- }
- return formattedList;
- };
- // 导出到全局
- window.H5FieldFormatter = {
- getDictTranslation,
- formatFieldValue,
- formatFieldValueAsync,
- formatDate: h5FormatDate,
- getDictOptions,
- formatObjectList,
- };
- // 兼容性:也导出为全局函数
- window.getDictTranslation = getDictTranslation;
- window.formatFieldValue = formatFieldValue;
- window.formatFieldValueAsync = formatFieldValueAsync;
- window.getDictOptions = getDictOptions;
- window.formatObjectList = formatObjectList;
- console.log("✅ H5字段格式化工具加载完成");
|