|
|
@@ -13,7 +13,7 @@ const CLASS_LABELS = {
|
|
|
ExamClass: '试题分类', ExamSysQuestions: '考试题库', ExamSysPapers: '试卷', ExamType: '考试类型', ExamPoint: '知识点', PaperQuestions: '试卷题目',
|
|
|
Datadiccategory: '数据字典分类', Datadic: '数据字典项',
|
|
|
GradeCate: '多级字典分类', Grade: '多级字典选项',
|
|
|
- Currency: '货币管理',
|
|
|
+ Currency: '货币管理', SysHoliday: '节假日管理',
|
|
|
Product: '商品', StoreProduct: '门店商品', StoreApplication: '门店申请', ShopFareTlp: '运费模板', ShopMoneyRegular: '金额规则', PayPlat: '支付平台',
|
|
|
GuestBar: '互动社区', Guestbook: '留言', Guestcate: '留言分类', Feedback: '反馈', Baike: '百科', Search: '搜索记录', Agency: '代理机构', DeliveryCenter: '交付中心'
|
|
|
};
|
|
|
@@ -41,7 +41,8 @@ const CLASS_SYSTEM_FIELDS = {
|
|
|
Datadic: new Set(['dicid','diccate','sourceKey']),
|
|
|
GradeCate: new Set(['cateId','sourceKey']),
|
|
|
Grade: new Set(['gradeId','cate','parentId','grade','sourceKey']),
|
|
|
- Currency: new Set(['id','sourceKey'])
|
|
|
+ Currency: new Set(['id','sourceKey']),
|
|
|
+ SysHoliday: new Set(['id','cdate','cadminId','cuserId','sourceKey'])
|
|
|
};
|
|
|
|
|
|
function inputOf(request) {
|
|
|
@@ -907,6 +908,30 @@ async function handler(request, response) {
|
|
|
if (String(input.className || '') !== 'Currency' || String(input.action || '') !== 'delete') fail(400, '不支持的货币批量操作'); const requestedIds = Array.isArray(input.objectIds) ? input.objectIds : [input.objectId]; const objectIds = [...new Set(requestedIds.map((value) => String(value || '').trim()).filter(Boolean))]; if (!objectIds.length || objectIds.length > 100) fail(400, '每次请选择 1 至 100 条货币记录');
|
|
|
const fields = await schemaFor('Currency'); const query = new Parse.Query('Currency'); applyTenant(query, fields, context, input.companyId); query.containedIn('objectId', objectIds); query.limit(objectIds.length); const targets = await query.find({ useMasterKey: true }); if (targets.length !== objectIds.length) fail(404, '部分货币记录不存在或不属于当前帐套'); await Parse.Object.destroyAll(targets, { useMasterKey: true }); for (const target of targets) await audit({ ...context, company: target.get('company') || context.company }, 'currency-delete', 'Currency', target.id); return response.json({ success: true, data: { action: 'delete', updated: targets.length, results: [] } });
|
|
|
}
|
|
|
+ if (operation === 'saveHoliday') {
|
|
|
+ const objectId = String(input.objectId || ''); const payload = input.fields && typeof input.fields === 'object' ? input.fields : {};
|
|
|
+ if (!objectId) fail(501, 'migration_blocked: SysHoliday.id 与 Parse 对象保留 id 冲突,且 PostgreSQL 物理表缺少可写旧 ID 列,不能安全新增节假日');
|
|
|
+ const name = String(payload.name || '').trim(); const htype = String(payload.htype || '').trim(); const hdate = String(payload.hdate || '').trim();
|
|
|
+ const hdateStart = Number(payload.hdateStart); const hdateEnd = Number(payload.hdateEnd); const zstatus = Number(payload.zstatus);
|
|
|
+ const strings = { ztype: String(payload.ztype || '').trim(), himage: String(payload.himage || '').trim(), remind: String(payload.remind || '').trim(), heffect: String(payload.heffect || '').trim(), hcontent: String(payload.hcontent || '').trim() };
|
|
|
+ if (!name || name.length > 100) fail(400, '节假日名称长度应为 1 至 100 位');
|
|
|
+ if (!['公历','农历'].includes(htype)) fail(400, '节假日类型只能是公历或农历');
|
|
|
+ if (!/^(0[1-9]|1[0-2])月(0[1-9]|[12][0-9]|3[01])日$/.test(hdate)) fail(400, '节假日日期必须使用 MM月DD日 格式');
|
|
|
+ if (!Number.isInteger(hdateStart) || hdateStart < 0 || hdateStart > 365 || !Number.isInteger(hdateEnd) || hdateEnd < 0 || hdateEnd > 365) fail(400, '提前与延后影响天数必须是 0 至 365 的整数');
|
|
|
+ if (![0,99].includes(zstatus)) fail(400, '节假日状态只能是停用或启用');
|
|
|
+ if (strings.ztype.length > 100 || strings.himage.length > 500 || strings.remind.length > 1000 || strings.heffect.length > 500 || strings.hcontent.length > 4000) fail(400, '节假日文本字段超过允许长度');
|
|
|
+ const fields = await schemaFor('SysHoliday'); const query = new Parse.Query('SysHoliday'); applyTenant(query, fields, context, input.companyId); const target = await query.get(objectId, { useMasterKey: true });
|
|
|
+ const duplicateQuery = new Parse.Query('SysHoliday'); applyTenant(duplicateQuery, fields, context, input.companyId); duplicateQuery.limit(1000); const duplicates = await duplicateQuery.find({ useMasterKey: true });
|
|
|
+ if (duplicates.some((entry) => entry.id !== objectId && String(entry.get('name') || '').trim().toLowerCase() === name.toLowerCase() && String(entry.get('htype') || '') === htype && String(entry.get('hdate') || '') === hdate)) fail(409, '同一帐套的节假日名称、类型和日期不能完全重复');
|
|
|
+ target.set('name', name); target.set('htype', htype); target.set('hdate', hdate); target.set('hdateStart', hdateStart); target.set('hdateEnd', hdateEnd); target.set('zstatus', zstatus);
|
|
|
+ for (const [field, value] of Object.entries(strings)) target.set(field, value);
|
|
|
+ try { await target.save(null, { useMasterKey: true }); } catch (error) { fail(422, '节假日写入失败: ' + String(error && error.message || error)); }
|
|
|
+ await target.fetch({ useMasterKey: true }); await audit({ ...context, company: target.get('company') || context.company }, 'update-holiday', 'SysHoliday', target.id); return response.json({ success: true, data: serializeObject(target) });
|
|
|
+ }
|
|
|
+ if (operation === 'holidayBatch') {
|
|
|
+ if (String(input.className || '') !== 'SysHoliday' || String(input.action || '') !== 'delete') fail(400, '不支持的节假日批量操作'); const requestedIds = Array.isArray(input.objectIds) ? input.objectIds : [input.objectId]; const objectIds = [...new Set(requestedIds.map((value) => String(value || '').trim()).filter(Boolean))]; if (!objectIds.length || objectIds.length > 100) fail(400, '每次请选择 1 至 100 条节假日记录');
|
|
|
+ const fields = await schemaFor('SysHoliday'); const query = new Parse.Query('SysHoliday'); applyTenant(query, fields, context, input.companyId); query.containedIn('objectId', objectIds); query.limit(objectIds.length); const targets = await query.find({ useMasterKey: true }); if (targets.length !== objectIds.length) fail(404, '部分节假日记录不存在或不属于当前帐套'); await Parse.Object.destroyAll(targets, { useMasterKey: true }); for (const target of targets) await audit({ ...context, company: target.get('company') || context.company }, 'holiday-delete', 'SysHoliday', target.id); return response.json({ success: true, data: { action: 'delete', updated: targets.length, results: [] } });
|
|
|
+ }
|
|
|
if (operation === 'saveExamClass') {
|
|
|
const objectId = String(input.objectId || '');
|
|
|
const payload = input.fields && typeof input.fields === 'object' ? input.fields : {};
|
|
|
@@ -1170,7 +1195,7 @@ async function handler(request, response) {
|
|
|
const classWritable = !READ_ONLY_CLASSES.has(className);
|
|
|
if (operation === 'schema') {
|
|
|
const fieldList = Object.entries(fields).filter(([name]) => !HIDDEN_FIELDS.has(name) && !/(?:password|secret|sessiontoken|masterkey|privatekey)/i.test(name)).map(([name, field]) => ({ name, type: field.type, targetClass: field.targetClass, required: field.required === true, writable: classWritable && !isSystemField(className, name) && GENERIC_WRITE_TYPES.has(field.type) }));
|
|
|
- return response.json({ success: true, data: { className, label: CLASS_LABELS[className] || className, fields: fieldList, writable: classWritable, creatable: classWritable && !['CommonModel','Model','ModelField','Guestbook','Currency'].includes(className), supportsSoftDelete: Boolean(fields.isDeleted) } });
|
|
|
+ return response.json({ success: true, data: { className, label: CLASS_LABELS[className] || className, fields: fieldList, writable: classWritable, creatable: classWritable && !['CommonModel','Model','ModelField','Guestbook','Currency','SysHoliday'].includes(className), supportsSoftDelete: Boolean(fields.isDeleted) } });
|
|
|
}
|
|
|
if (operation === 'list') {
|
|
|
const page = Math.max(1, Number(input.page) || 1); const pageSize = Math.min(100, Math.max(1, Number(input.pageSize) || 20));
|
|
|
@@ -1203,6 +1228,7 @@ async function handler(request, response) {
|
|
|
if (className === 'Datadiccategory' || className === 'Datadic') fail(400, '数据字典必须走专用保存流程');
|
|
|
if (className === 'GradeCate' || className === 'Grade') fail(400, '多级数据字典必须走专用保存流程');
|
|
|
if (className === 'Currency') fail(400, '货币必须走专用保存流程');
|
|
|
+ if (className === 'SysHoliday') fail(400, '节假日必须走专用保存流程');
|
|
|
if (className === 'CommonModel' && !objectId) fail(400, '内容新增必须同时写入模型附表,不能走通用保存');
|
|
|
let object;
|
|
|
if (objectId) { const query = new Parse.Query(className); applyTenant(query, fields, context, input.companyId); object = await query.get(objectId, { useMasterKey: true }); } else object = new Parse.Object(className);
|