家谱现有接口调试50%
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* 日期时间工具类。
|
||||
*
|
||||
* 说明:
|
||||
* - 页面只需要展示日期时,统一使用这里的方法,避免每个页面重复处理格式。
|
||||
* - 后端常见日期格式为 `YYYY-MM-DD` 或 `YYYY-MM-DD HH:mm:ss`。
|
||||
* - 纯日期字符串用本地时区解析,避免浏览器按 UTC 解析导致日期偏移。
|
||||
*/
|
||||
class DateUtil {
|
||||
/**
|
||||
* 转为“5月9日”格式。
|
||||
*
|
||||
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatDateToMonthDay(dateStr) {
|
||||
try {
|
||||
// 第一步:把传入的字符串或 Date 对象统一转成 Date。
|
||||
const date = DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效日期直接返回空字符串,页面不显示错误内容。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:取月份和日期,拼接成中文展示格式。
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
return `${month}月${day}日`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为“2026年5月9日”格式。
|
||||
*
|
||||
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatDateToYearMonthDay(dateStr) {
|
||||
try {
|
||||
// 第一步:统一解析日期。
|
||||
const date = DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效日期不继续格式化。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:分别取年月日,拼成完整中文日期。
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
return `${year}年${month}月${day}日`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为“YYYY-MM-DD”格式,适合列表右侧日期展示。
|
||||
*
|
||||
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatDateToYMD(dateStr) {
|
||||
try {
|
||||
// 第一步:统一解析日期。
|
||||
const date = DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效日期返回空字符串。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:月份和日期补零,保证列表展示宽度稳定。
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为“YYYY-MM-DD HH:mm:ss”格式,适合资金流水、订单时间等完整时间展示。
|
||||
*
|
||||
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatDateTimeToYMDHMS(dateStr) {
|
||||
try {
|
||||
// 第一步:统一解析日期。
|
||||
const date = DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效日期返回空字符串,避免页面显示 Invalid Date。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:分别补齐年月日时分秒,保证表格宽度稳定。
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
const second = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
// 第四步:拼接成后端和页面都常用的完整时间格式。
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为“HH:mm:ss”格式,适合日志或轮询状态时间展示。
|
||||
*
|
||||
* @param {string|number|Date} dateStr 后端时间、时间戳或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
/**
|
||||
* 转为“YYYY-MM-DD HH:mm”格式,适合评论发布时间等不需要精确到秒的场景。
|
||||
*
|
||||
* @param {string|Date} dateStr 后端时间字符串或 Date 对象
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatDateTimeToYMDHM(dateStr) {
|
||||
try {
|
||||
// 第一步:统一解析传入的时间。
|
||||
const date = DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效时间返回空字符串,避免页面显示 Invalid Date。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:只补齐到分钟,不展示秒。
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minute}`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static formatTimeToHMS(dateStr) {
|
||||
try {
|
||||
// 第一步:时间戳直接转 Date,字符串和 Date 继续走统一解析。
|
||||
const date = typeof dateStr === 'number' ? new Date(dateStr) : DateUtil._parseDate(dateStr);
|
||||
|
||||
// 第二步:无效时间返回空字符串。
|
||||
if (!DateUtil._isValidDate(date)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 第三步:补齐时分秒,保持展示稳定。
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
const second = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
return `${hour}:${minute}:${second}`;
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间。
|
||||
*
|
||||
* @returns {Date}
|
||||
*/
|
||||
static getCurrentDate() {
|
||||
return new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个日期是否为同一天。
|
||||
*
|
||||
* @param {string|Date} date1 第一个日期
|
||||
* @param {string|Date} date2 第二个日期
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isSameDay(date1, date2) {
|
||||
try {
|
||||
// 第一步:两个入参都先转成 Date。
|
||||
const d1 = DateUtil._parseDate(date1);
|
||||
const d2 = DateUtil._parseDate(date2);
|
||||
|
||||
// 第二步:任意一个日期无效,就判定不是同一天。
|
||||
if (!DateUtil._isValidDate(d1) || !DateUtil._isValidDate(d2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 第三步:同时比较年、月、日。
|
||||
return d1.getFullYear() === d2.getFullYear()
|
||||
&& d1.getMonth() === d2.getMonth()
|
||||
&& d1.getDate() === d2.getDate();
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一解析日期。
|
||||
*
|
||||
* @param {string|Date} dateStr 日期字符串或 Date 对象
|
||||
* @returns {Date|null}
|
||||
*/
|
||||
static _parseDate(dateStr) {
|
||||
// 第一步:如果已经是 Date 对象,直接返回。
|
||||
if (dateStr instanceof Date) {
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
// 第二步:非字符串不尝试解析。
|
||||
if (typeof dateStr !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 第三步:去掉首尾空格,兼容接口偶发空白。
|
||||
const value = dateStr.trim();
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 第四步:纯日期用斜杠格式解析,避免浏览器按 UTC 导致日期前后偏移。
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
||||
return new Date(value.replace(/-/g, '/'));
|
||||
}
|
||||
|
||||
// 第五步:带时间的字符串交给浏览器 Date 解析。
|
||||
return new Date(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 Date 对象是否有效。
|
||||
*
|
||||
* @param {Date|null} date 日期对象
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static _isValidDate(date) {
|
||||
return date instanceof Date && !Number.isNaN(date.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = DateUtil;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
window.DateUtil = DateUtil;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
(function (root, factory) {
|
||||
// 表单工具只处理跨页面通用转换,具体业务字段留在页面脚本中组织。
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory();
|
||||
return;
|
||||
}
|
||||
|
||||
root.FormUtil = factory();
|
||||
})(typeof globalThis !== 'undefined' ? globalThis : window, function () {
|
||||
'use strict';
|
||||
|
||||
function trimOrUndefined(value) {
|
||||
if (value === undefined || value === null) return undefined;
|
||||
|
||||
var text = String(value).trim();
|
||||
return text ? text : undefined;
|
||||
}
|
||||
|
||||
function toNumberOrUndefined(value) {
|
||||
var text = trimOrUndefined(value);
|
||||
if (text === undefined) return undefined;
|
||||
|
||||
var numberValue = Number(text);
|
||||
return Number.isNaN(numberValue) ? undefined : numberValue;
|
||||
}
|
||||
|
||||
function toBoolean(value) {
|
||||
if (value === true || value === false) return value;
|
||||
|
||||
var text = trimOrUndefined(value);
|
||||
if (text === undefined) return false;
|
||||
|
||||
return !['0', 'false', 'off', 'no'].includes(text.toLowerCase());
|
||||
}
|
||||
|
||||
function getControlValue(control) {
|
||||
if (!control || control.disabled || !control.name) return undefined;
|
||||
if (control.type === 'checkbox') return control.checked ? (control.value || 'on') : undefined;
|
||||
if (control.type === 'radio') return control.checked ? control.value : undefined;
|
||||
return control.value;
|
||||
}
|
||||
|
||||
function getFormValues(form) {
|
||||
var values = {};
|
||||
if (!form || !form.elements) return values;
|
||||
|
||||
Array.prototype.forEach.call(form.elements, function (control) {
|
||||
var value = getControlValue(control);
|
||||
if (value !== undefined) values[control.name] = value;
|
||||
});
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
return {
|
||||
trimOrUndefined: trimOrUndefined,
|
||||
toNumberOrUndefined: toNumberOrUndefined,
|
||||
toBoolean: toBoolean,
|
||||
getFormValues: getFormValues
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
(function (root, factory) {
|
||||
// 消息工具同时支持浏览器页面和 Node 测试,避免页面脚本直接使用原生 alert。
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory(root);
|
||||
return;
|
||||
}
|
||||
|
||||
root.MessageUtil = factory(root);
|
||||
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_OPTIONS = {
|
||||
skin: 'auth-layer-message',
|
||||
time: 2200
|
||||
};
|
||||
|
||||
function show(message, options) {
|
||||
var text = String(message || '');
|
||||
var settings = Object.assign({}, DEFAULT_OPTIONS, options || {});
|
||||
|
||||
if (root.layui && root.layui.layer && root.layui.layer.msg) {
|
||||
root.layui.layer.msg(text, settings);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.console && root.console.warn) {
|
||||
root.console.warn(text);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
(function (root, factory) {
|
||||
// 请求工具封装 URL、Header 和响应解包,业务路径由 api-client 统一提供。
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory(root);
|
||||
return;
|
||||
}
|
||||
|
||||
root.RequestUtil = factory(root);
|
||||
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
|
||||
'use strict';
|
||||
|
||||
function trimSlashes(value) {
|
||||
return String(value || '').replace(/^\/+|\/+$/g, '');
|
||||
}
|
||||
|
||||
function joinUrl(baseUrl, path) {
|
||||
var base = String(baseUrl || '').replace(/\/+$/g, '');
|
||||
var cleanPath = '/' + trimSlashes(path);
|
||||
return base + cleanPath;
|
||||
}
|
||||
|
||||
function appendQuery(url, query) {
|
||||
if (!query) return url;
|
||||
|
||||
var params = new URLSearchParams();
|
||||
Object.keys(query).forEach(function (key) {
|
||||
var value = query[key];
|
||||
if (value === undefined || value === null || value === '') return;
|
||||
params.append(key, value);
|
||||
});
|
||||
|
||||
var queryText = params.toString();
|
||||
return queryText ? url + '?' + queryText : url;
|
||||
}
|
||||
|
||||
function isFormData(body) {
|
||||
return typeof FormData !== 'undefined' && body instanceof FormData;
|
||||
}
|
||||
|
||||
function createHttpError(message, detail) {
|
||||
var error = new Error(message);
|
||||
Object.keys(detail || {}).forEach(function (key) {
|
||||
error[key] = detail[key];
|
||||
});
|
||||
return error;
|
||||
}
|
||||
|
||||
async function parseJson(response) {
|
||||
try {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function unwrapResponse(payload) {
|
||||
if (!payload || typeof payload !== 'object') return payload;
|
||||
|
||||
if (payload.code !== undefined && payload.code !== 200) {
|
||||
throw createHttpError(payload.msg || '接口请求失败', {
|
||||
code: payload.code,
|
||||
response: payload
|
||||
});
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'data')) return payload.data;
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'rows')) {
|
||||
return {
|
||||
rows: payload.rows,
|
||||
total: payload.total
|
||||
};
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
function createRequester(options) {
|
||||
var settings = options || {};
|
||||
var fetchImpl = settings.fetchImpl || root.fetch;
|
||||
|
||||
return async function request(method, path, requestOptions) {
|
||||
var req = requestOptions || {};
|
||||
var headers = Object.assign({}, req.headers || {});
|
||||
var token = settings.getToken ? settings.getToken() : '';
|
||||
var tokenHeaderName = settings.tokenHeaderName || 'Authorization';
|
||||
var url = appendQuery(joinUrl(settings.baseUrl, path), req.query);
|
||||
var body = req.body;
|
||||
|
||||
headers.clientid = settings.clientId;
|
||||
if (token && req.auth !== false) headers[tokenHeaderName] = 'Bearer ' + token;
|
||||
|
||||
if (body !== undefined && body !== null && !isFormData(body)) {
|
||||
headers['Content-Type'] = headers['Content-Type'] || 'application/json';
|
||||
body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
var response = await fetchImpl(url, {
|
||||
method: method,
|
||||
headers: headers,
|
||||
body: body
|
||||
});
|
||||
var payload = await parseJson(response);
|
||||
|
||||
if (!response.ok) {
|
||||
throw createHttpError((payload && payload.msg) || '接口请求失败', {
|
||||
status: response.status,
|
||||
response: payload
|
||||
});
|
||||
}
|
||||
|
||||
return unwrapResponse(payload);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createRequester: createRequester,
|
||||
joinUrl: joinUrl,
|
||||
appendQuery: appendQuery
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
(function (root, factory) {
|
||||
// 存储工具同时支持浏览器页面和 Node 测试。
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory();
|
||||
return;
|
||||
}
|
||||
|
||||
root.StorageUtil = factory();
|
||||
})(typeof globalThis !== 'undefined' ? globalThis : window, function () {
|
||||
'use strict';
|
||||
|
||||
function read(storage, key) {
|
||||
try {
|
||||
return storage && storage.getItem(key);
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function write(storage, key, value) {
|
||||
try {
|
||||
if (storage) storage.setItem(key, value);
|
||||
} catch (error) {
|
||||
// localStorage 可能因为隐私模式或配额限制失败,调用方无需因此中断页面。
|
||||
}
|
||||
}
|
||||
|
||||
function remove(storage, key) {
|
||||
try {
|
||||
if (storage) storage.removeItem(key);
|
||||
} catch (error) {
|
||||
// 删除失败时保持静默,避免影响退出登录等后续流程。
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
read: read,
|
||||
write: write,
|
||||
remove: remove
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user