1
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
1. 在 MySQL 中建空库,例如:`CREATE DATABASE your_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`
|
1. 在 MySQL 中建空库,例如:`CREATE DATABASE your_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`
|
||||||
2. `USE your_db;`
|
2. `USE your_db;`
|
||||||
3. 执行 **`sql/init.sql`**(与 `migrations/init.sql` 内容一致)。会 `DROP`/`CREATE` 系统表并写入:默认租户、**超级管理员角色**、用户 **`admin` / `123456`**(MD5 与框架一致)、`sys_title` / `sys_logo`、菜单等。**库名须与下一步 `config.development.js` 里的 `db.database` 一致。**
|
3. 执行 **`sql/init.sql`**(与 `migrations/init.sql` 内容一致)。会 `DROP`/`CREATE` 系统表并写入:默认租户、**超级管理员角色**、用户 **`admin` / `123456`**、**`zc` / `zc123`**(MD5 与框架一致)、`sys_title` / `sys_logo`、菜单等。**库名须与下一步 `config.development.js` 里的 `db.database` 一致。**
|
||||||
4. 需要「演示数据」列表时,再执行 **`sql/tpl_demo.sql`**。
|
4. 需要「演示数据」列表时,再执行 **`sql/tpl_demo.sql`**。
|
||||||
|
|
||||||
### 3. 配置 `config/config.development.js`
|
### 3. 配置 `config/config.development.js`
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
### 6. 登录与排错
|
### 6. 登录与排错
|
||||||
|
|
||||||
- 默认:**`admin` / `123456`**;租户可不传或按 `sys_tenant.code`(如 `default`)。
|
- 默认:**`admin` / `123456`** ;租户可不传或按 `sys_tenant.code`(如 `default`)。
|
||||||
- **`sys_file` 加载失败**:检查 `aliyun` 字段是否非空或已配置环境变量。
|
- **`sys_file` 加载失败**:检查 `aliyun` 字段是否非空或已配置环境变量。
|
||||||
- **连库失败**:核对 `db`、防火墙、是否已执行 `init.sql`。
|
- **连库失败**:核对 `db`、防火墙、是否已执行 `init.sql`。
|
||||||
|
|
||||||
|
|||||||
@@ -1,461 +0,0 @@
|
|||||||
// 通用表格页面混入
|
|
||||||
import dynamicModelApi from '@/api/entity/dynamicModelApi.js';
|
|
||||||
import { mapFormFieldsToEditColumns } from '@/utils/formEditColumns.js';
|
|
||||||
import { getForeignRowLabel, rowsToIdOptions } from '@/utils/foreignRowLabel.js';
|
|
||||||
import { orderActionBtnsViewEditFirst } from '@/utils/actionBtnOrder.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
created() {
|
|
||||||
this.ensure_meta_shape();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/** 操作列:查看、编辑排在最左侧相邻,其余按钮顺序在后 */
|
|
||||||
renderRowActionBtns(h, btns) {
|
|
||||||
return window.framework.uiTool.getBtn(h, orderActionBtnsViewEditFirst(btns));
|
|
||||||
},
|
|
||||||
|
|
||||||
field_display_name(f) {
|
|
||||||
if (!f) return "";
|
|
||||||
return f.label || f.title || f.key || "";
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 按 meta.formFields 整理行数据,供 editModal 绑定(InputNumber 不能接收 "")。
|
|
||||||
* 外键数字字段空值用 undefined;其它 number 空值或非数字用 0。
|
|
||||||
*/
|
|
||||||
normalizeRowForEditModal(row) {
|
|
||||||
if (!row || typeof row !== 'object') return row;
|
|
||||||
const fields =
|
|
||||||
this.meta && Array.isArray(this.meta.formFields) ? this.meta.formFields : [];
|
|
||||||
if (!fields.length) return { ...row };
|
|
||||||
const o = { ...row };
|
|
||||||
for (const f of fields) {
|
|
||||||
if (!f || f.form === false || f.type !== 'number') continue;
|
|
||||||
const k = f.key;
|
|
||||||
const v = o[k];
|
|
||||||
if (/_id$/.test(k)) {
|
|
||||||
if (v === '' || v === null || v === undefined) {
|
|
||||||
o[k] = undefined;
|
|
||||||
} else {
|
|
||||||
const n = Number(v);
|
|
||||||
o[k] = Number.isNaN(n) ? undefined : n;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (v === '' || v === null || v === undefined) {
|
|
||||||
o[k] = 0;
|
|
||||||
} else {
|
|
||||||
const n = Number(v);
|
|
||||||
o[k] = Number.isNaN(n) ? 0 : n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 兼容页面只定义 fields 的场景,统一补齐 formFields / columns
|
|
||||||
ensure_meta_shape() {
|
|
||||||
if (!this.meta || typeof this.meta !== 'object') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fields = Array.isArray(this.meta.formFields)
|
|
||||||
? this.meta.formFields
|
|
||||||
: (Array.isArray(this.meta.fields) ? this.meta.fields : []);
|
|
||||||
|
|
||||||
// code 字段:后端自动生成,表单中不显示
|
|
||||||
fields.forEach((f) => {
|
|
||||||
if (f && f.key === 'code') {
|
|
||||||
f.form = false;
|
|
||||||
f.required = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!Array.isArray(this.meta.formFields)) {
|
|
||||||
const formFields = fields.filter((f) => f && f.form !== false);
|
|
||||||
this.$set(this.meta, 'formFields', formFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(this.meta.columns)) {
|
|
||||||
const columns = fields
|
|
||||||
.filter((f) => f && f.list)
|
|
||||||
.map((f) => ({
|
|
||||||
key: f.key,
|
|
||||||
title: f.label || f.title,
|
|
||||||
minWidth: f.minWidth,
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.$set(this.meta, 'columns', columns);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的编辑列配置生成方法(实现见 utils/formEditColumns.js)
|
|
||||||
generateEditColumns(formFields, selectSources) {
|
|
||||||
return mapFormFieldsToEditColumns(formFields, selectSources);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准列表列:外键列显示关联名称(select_sources)、布尔、日期等
|
|
||||||
* meta 需含 columns,以及 fields 或 formFields(带 type)
|
|
||||||
*/
|
|
||||||
buildListColumnsFromMeta(meta, selectSources) {
|
|
||||||
if (!meta || !Array.isArray(meta.columns)) return [];
|
|
||||||
const allFields = meta.fields || meta.formFields || [];
|
|
||||||
return this.generateListColumns(meta.columns, allFields, selectSources);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的列表列配置生成方法
|
|
||||||
generateListColumns(columns, allFields, selectSources) {
|
|
||||||
if (!columns || !Array.isArray(columns)) return [];
|
|
||||||
|
|
||||||
const fields = Array.isArray(allFields) ? allFields : [];
|
|
||||||
|
|
||||||
/** 系统统一时间字段(与后端 create_time / last_modify_time 一致),排在业务列之后、操作列之前 */
|
|
||||||
const colList = [...columns];
|
|
||||||
const keySet = new Set(colList.map((c) => c && c.key).filter(Boolean));
|
|
||||||
if (!keySet.has('create_time')) {
|
|
||||||
colList.push({ key: 'create_time', title: '创建时间', minWidth: 160 });
|
|
||||||
keySet.add('create_time');
|
|
||||||
}
|
|
||||||
if (!keySet.has('last_modify_time')) {
|
|
||||||
colList.push({ key: 'last_modify_time', title: '最后修改时间', minWidth: 160 });
|
|
||||||
keySet.add('last_modify_time');
|
|
||||||
}
|
|
||||||
|
|
||||||
const boolKeys = new Set(fields.filter((f) => f.type === 'bool').map((f) => f.key));
|
|
||||||
const selectKeys = new Set(fields.filter((f) => f.type === 'select').map((f) => f.key));
|
|
||||||
|
|
||||||
return colList.map((c) => {
|
|
||||||
// 外键:已加载下拉数据时显示名称(含仓库/库区/巷道及 mat_sku 等)
|
|
||||||
if (
|
|
||||||
selectSources &&
|
|
||||||
selectSources[c.key] &&
|
|
||||||
Array.isArray(selectSources[c.key]) &&
|
|
||||||
selectSources[c.key].length &&
|
|
||||||
/_id$/.test(c.key)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
...c,
|
|
||||||
render: (h, params) => {
|
|
||||||
const id = params.row[c.key];
|
|
||||||
const source = selectSources[c.key];
|
|
||||||
const item = source && source.find((w) => String(w.key) === String(id));
|
|
||||||
return h('span', item ? item.value : id != null && id !== '' ? String(id) : '-');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理选择字段显示(status 按字段 source_key)
|
|
||||||
if (selectKeys.has(c.key)) {
|
|
||||||
const fieldDef = fields.find((f) => f.key === c.key);
|
|
||||||
const source_key = fieldDef && fieldDef.source_key;
|
|
||||||
return {
|
|
||||||
...c,
|
|
||||||
render: (h, params) => {
|
|
||||||
const value = params.row[c.key];
|
|
||||||
let source;
|
|
||||||
if (source_key && selectSources && selectSources[source_key]) {
|
|
||||||
source = selectSources[source_key];
|
|
||||||
} else if (c.key === 'type') {
|
|
||||||
source = selectSources && selectSources.warehouse_type_options;
|
|
||||||
} else if (c.key === 'tray_type_id') {
|
|
||||||
source = selectSources && selectSources.tray_type_id;
|
|
||||||
} else if (c.key === 'lock_type') {
|
|
||||||
source = selectSources && selectSources.lock_type_options;
|
|
||||||
} else if (c.key === 'status' && source_key) {
|
|
||||||
source = selectSources && selectSources[source_key];
|
|
||||||
} else if (c.key === 'status') {
|
|
||||||
source = selectSources && selectSources.tray_status_options;
|
|
||||||
} else {
|
|
||||||
source = selectSources && selectSources.yes_no_options;
|
|
||||||
}
|
|
||||||
const option = source && source.find((opt) => String(opt.key) === String(value));
|
|
||||||
return h('span', option ? option.value : value);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理布尔字段显示
|
|
||||||
if (boolKeys.has(c.key)) {
|
|
||||||
return {
|
|
||||||
...c,
|
|
||||||
render: (h, params) => {
|
|
||||||
const v = params.row[c.key];
|
|
||||||
const on = v === true || v === 1 || v === '1';
|
|
||||||
return h('Tag', { props: { color: on ? 'green' : 'default' } }, on ? '是' : '否');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理日期字段显示
|
|
||||||
if (this.isDateLikeColumnKey && this.isDateLikeColumnKey(c.key)) {
|
|
||||||
return {
|
|
||||||
...c,
|
|
||||||
render: (h, params) => {
|
|
||||||
const raw =
|
|
||||||
c.key === 'create_time' || c.key === 'last_modify_time'
|
|
||||||
? this.pickRowTimeCell(params.row, c.key)
|
|
||||||
: params.row[c.key];
|
|
||||||
return h('span', this.formatCellDate(raw, c.key));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...c };
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 从 Vuex store (wms_dict) 获取字典选项
|
|
||||||
getDictOptions(key) {
|
|
||||||
if (!this.$store || !this.$store.state.wms_dict) return [];
|
|
||||||
return this.$store.state.wms_dict[key] || [];
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的数据源加载方法(从 store 读取字典,不再请求 sys_parameter)
|
|
||||||
async loadSelectSources(formFields, idFieldToModelFn, getRowLabelFn) {
|
|
||||||
const sources = {};
|
|
||||||
|
|
||||||
sources.yes_no_options = this.getDictOptions('yes_no');
|
|
||||||
sources.warehouse_type_options = this.getDictOptions('warehouse_type');
|
|
||||||
sources.lock_type_options = this.getDictOptions('lock_type');
|
|
||||||
sources.tray_status_options = this.getDictOptions('tray_status');
|
|
||||||
sources.tray_type_status_options = this.getDictOptions('tray_type_status');
|
|
||||||
sources.receiving_status_options = this.getDictOptions('receiving_status');
|
|
||||||
sources.inbound_status_options = this.getDictOptions('inbound_status');
|
|
||||||
sources.send_status_options = this.getDictOptions('send_status');
|
|
||||||
sources.outbound_status_options = this.getDictOptions('outbound_status');
|
|
||||||
sources.move_status_options = this.getDictOptions('move_status');
|
|
||||||
sources.damage_status_options = this.getDictOptions('damage_status');
|
|
||||||
sources.count_status_options = this.getDictOptions('count_status');
|
|
||||||
sources.receiving_type_options = this.getDictOptions('receiving_type');
|
|
||||||
sources.send_type_options = this.getDictOptions('send_type');
|
|
||||||
sources.fee_charge_type_options = this.getDictOptions('fee_charge_type_options');
|
|
||||||
sources.fee_generate_type_options = this.getDictOptions('fee_generate_type_options');
|
|
||||||
sources.fee_collection_type_options = this.getDictOptions('fee_collection_type_options');
|
|
||||||
sources.fee_item_inbound_options = this.getDictOptions('fee_item_inbound_options');
|
|
||||||
sources.fee_item_outbound_options = this.getDictOptions('fee_item_outbound_options');
|
|
||||||
sources.packaging_status_options = this.getDictOptions('packaging_status_options');
|
|
||||||
|
|
||||||
// 加载外键数据
|
|
||||||
const idFields = formFields
|
|
||||||
.filter((f) => f.type === 'number' && /_id$/.test(f.key))
|
|
||||||
.map((f) => f.key);
|
|
||||||
|
|
||||||
for (const k of idFields) {
|
|
||||||
const model = idFieldToModelFn(k);
|
|
||||||
if (!model) {
|
|
||||||
sources[k] = [];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await dynamicModelApi.all(model);
|
|
||||||
const rows = res && res.code === 0 && res.data ? res.data : [];
|
|
||||||
sources[k] = rowsToIdOptions(rows, getRowLabelFn || getForeignRowLabel);
|
|
||||||
} catch (e) {
|
|
||||||
sources[k] = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sources;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的空表单构建方法
|
|
||||||
generateEmptyForm(formFields) {
|
|
||||||
const o = {};
|
|
||||||
if (!formFields) return o;
|
|
||||||
|
|
||||||
for (const f of formFields) {
|
|
||||||
if (f.type === 'bool') o[f.key] = false;
|
|
||||||
else if (f.type === 'number') {
|
|
||||||
// 外键用 Select 时,0 易被当成「已选」且无法匹配 Option,校验与展示都不直观
|
|
||||||
o[f.key] = /_id$/.test(f.key) ? undefined : 0;
|
|
||||||
} else if (f.type === 'select') {
|
|
||||||
if (f.key === 'lock_type') o[f.key] = 0;
|
|
||||||
else if (f.data_type === 'number' && /_id$/.test(f.key)) o[f.key] = undefined;
|
|
||||||
else o[f.key] = '';
|
|
||||||
} else o[f.key] = '';
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的日期相关方法
|
|
||||||
isDateLikeColumnKey(key) {
|
|
||||||
if (!key) return false;
|
|
||||||
return (
|
|
||||||
key === 'stat_date' ||
|
|
||||||
key === 'create_time' ||
|
|
||||||
key === 'last_modify_time' ||
|
|
||||||
/_time$/.test(key) ||
|
|
||||||
/_date$/.test(key)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 列表「创建时间 / 最后修改时间」与后端 Sequelize 字段对齐:
|
|
||||||
|
|
||||||
*/
|
|
||||||
pickRowTimeCell(row, key) {
|
|
||||||
if (!row || !key) return undefined;
|
|
||||||
if (key === 'create_time') {
|
|
||||||
return row.create_time;
|
|
||||||
}
|
|
||||||
if (key === 'last_modify_time') {
|
|
||||||
return row.last_modify_time;
|
|
||||||
}
|
|
||||||
return row[key];
|
|
||||||
},
|
|
||||||
|
|
||||||
formatCellDate(v, key) {
|
|
||||||
if (v === null || v === undefined || v === '') return '-';
|
|
||||||
const d = v instanceof Date ? v : new Date(v);
|
|
||||||
if (Number.isNaN(d.getTime())) return String(v);
|
|
||||||
const pad = (n) => String(n).padStart(2, '0');
|
|
||||||
const y = d.getFullYear();
|
|
||||||
const m = pad(d.getMonth() + 1);
|
|
||||||
const day = pad(d.getDate());
|
|
||||||
const hh = pad(d.getHours());
|
|
||||||
const mm = pad(d.getMinutes());
|
|
||||||
const dateOnly = key === 'stat_date' || (key && /_date$/.test(key) && !/_time$/.test(key));
|
|
||||||
if (dateOnly) return y + '-' + m + '-' + day;
|
|
||||||
return y + '-' + m + '-' + day + ' ' + hh + ':' + mm;
|
|
||||||
},
|
|
||||||
|
|
||||||
/** 外键行展示文案;实现见 @/utils/foreignRowLabel.js */
|
|
||||||
getRowLabel(row) {
|
|
||||||
return getForeignRowLabel(row);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的数据规范化方法
|
|
||||||
generatePayload(raw, formFields) {
|
|
||||||
const o = { ...raw };
|
|
||||||
if (!formFields) return o;
|
|
||||||
|
|
||||||
const typeByKey = {};
|
|
||||||
const selectDataTypeByKey = {};
|
|
||||||
for (const f of formFields) {
|
|
||||||
if (!f || !f.key) continue;
|
|
||||||
typeByKey[f.key] = f.type;
|
|
||||||
if (f.data_type) selectDataTypeByKey[f.key] = f.data_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const k of Object.keys(o)) {
|
|
||||||
const t = typeByKey[k];
|
|
||||||
let v = o[k];
|
|
||||||
|
|
||||||
if (t === 'number') {
|
|
||||||
if (v === '' || v === null || v === undefined) {
|
|
||||||
o[k] = null;
|
|
||||||
} else {
|
|
||||||
const n = Number(v);
|
|
||||||
o[k] = Number.isNaN(n) ? v : n;
|
|
||||||
}
|
|
||||||
} else if (t === 'bool') {
|
|
||||||
o[k] = v === true || v === 1 || v === '1';
|
|
||||||
} else if (t === 'select') {
|
|
||||||
const numSelect = k === 'lock_type' || selectDataTypeByKey[k] === 'number';
|
|
||||||
if (numSelect) {
|
|
||||||
if (v === '' || v === null || v === undefined) {
|
|
||||||
o[k] = null;
|
|
||||||
} else {
|
|
||||||
const n = Number(v);
|
|
||||||
o[k] = Number.isNaN(n) ? v : n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (t === 'date' || t === 'datetime') {
|
|
||||||
if (v instanceof Date) {
|
|
||||||
const pad = (n) => String(n).padStart(2, '0');
|
|
||||||
if (t === 'date') {
|
|
||||||
o[k] = v.getFullYear() + '-' + pad(v.getMonth() + 1) + '-' + pad(v.getDate());
|
|
||||||
} else {
|
|
||||||
o[k] = v.getFullYear() + '-' + pad(v.getMonth() + 1) + '-' + pad(v.getDate()) +
|
|
||||||
' ' + pad(v.getHours()) + ':' + pad(v.getMinutes()) + ':' + pad(v.getSeconds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
},
|
|
||||||
|
|
||||||
// 通用的表单验证规则生成方法(与 iView Form / async-validator 约定一致:输入类 blur,选择类 change)
|
|
||||||
generateEditRules(formFields) {
|
|
||||||
if (!formFields) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const rules = {};
|
|
||||||
for (const f of formFields) {
|
|
||||||
if (f.form === false) continue;
|
|
||||||
if (!f.required) continue;
|
|
||||||
if (f.type === 'bool') continue;
|
|
||||||
const fieldTitle = f.label || f.title || f.key;
|
|
||||||
|
|
||||||
if (f.type === 'date' || f.type === 'datetime') {
|
|
||||||
rules[f.key] = [
|
|
||||||
{ required: true, type: 'date', message: '请选择' + fieldTitle, trigger: 'change' }
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数字 id 用 Select 渲染(如 tenant_id:type=select + data_type=number),Option 常为字符串;
|
|
||||||
// 仅用 async-validator required 易与 iView 绑定不一致导致「已选仍报错」
|
|
||||||
if (f.type === 'select' && f.data_type === 'number' && /_id$/.test(f.key)) {
|
|
||||||
rules[f.key] = [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
trigger: 'change',
|
|
||||||
validator(rule, value, callback) {
|
|
||||||
const n = value === '' || value === null || value === undefined ? NaN : Number(value);
|
|
||||||
if (Number.isNaN(n) || n === 0) {
|
|
||||||
callback(new Error('请选择' + fieldTitle));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.type === 'select') {
|
|
||||||
rules[f.key] = [
|
|
||||||
{ required: true, message: '请选择' + fieldTitle, trigger: 'change' }
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 外键:generateEditColumns 里用 Select,值为数字 id,但 Option 上可能是字符串;不能用 type:'number' 直接校验
|
|
||||||
if (f.type === 'number' && /_id$/.test(f.key)) {
|
|
||||||
rules[f.key] = [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
trigger: 'change',
|
|
||||||
validator(rule, value, callback) {
|
|
||||||
const n = value === '' || value === null || value === undefined ? NaN : Number(value);
|
|
||||||
if (Number.isNaN(n) || n === 0) {
|
|
||||||
callback(new Error('请选择' + fieldTitle));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f.type === 'number') {
|
|
||||||
rules[f.key] = [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
type: 'number',
|
|
||||||
message: '请填写' + fieldTitle,
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rules[f.key] = [{ required: true, message: '请填写' + fieldTitle, trigger: 'blur' }];
|
|
||||||
}
|
|
||||||
return rules;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -32,11 +32,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import tplDemoServer from "@/api/demo/tplDemoServer.js";
|
import tplDemoServer from "@/api/demo/tplDemoServer.js";
|
||||||
import tableMixin from "@/mixins/tableMixin.js";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TplDemoPage",
|
name: "TplDemoPage",
|
||||||
mixins: [tableMixin],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
select_sources: {},
|
select_sources: {},
|
||||||
|
|||||||
21
sql/init.sql
21
sql/init.sql
@@ -1,8 +1,7 @@
|
|||||||
-- Active: 1775110656953@@101.132.75.138@3306@framework_project_web
|
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- 前后端项目模板 · 初始化库表与基础数据(MySQL 5.7+ / 8.x,utf8mb4)
|
-- 前后端项目模板 · 初始化库表与基础数据(MySQL 5.7+ / 8.x,utf8mb4)
|
||||||
-- 执行前请创建空库并 USE 到目标 database(库名须与 config/config.development.js 里 db.database 一致);会 DROP 后重建系统表,请勿在生产库直接全量执行。
|
-- 执行前请创建空库并 USE 到目标 database(库名须与 config/config.development.js 里 db.database 一致);会 DROP 后重建系统表,请勿在生产库直接全量执行。
|
||||||
-- 默认管理员:admin / 123456(密码为 MD5 小写十六进制,与 node_core tokenService.getMd5 一致)
|
-- 默认账号:admin / 123456;zc / zc123(密码为 MD5 小写十六进制,与 node_core tokenService.getMd5 一致)
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
|
|
||||||
SET NAMES utf8mb4;
|
SET NAMES utf8mb4;
|
||||||
@@ -123,6 +122,10 @@ VALUES (1, '超级管理员', 1, CAST('[]' AS JSON), 0);
|
|||||||
INSERT INTO `sys_user` (`id`, `name`, `password`, `roleId`, `tenant_id`, `is_delete`)
|
INSERT INTO `sys_user` (`id`, `name`, `password`, `roleId`, `tenant_id`, `is_delete`)
|
||||||
VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, 1, 0);
|
VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, 1, 0);
|
||||||
|
|
||||||
|
-- 用户 zc / zc123 → MD5(同为超级管理员角色)
|
||||||
|
INSERT INTO `sys_user` (`id`, `name`, `password`, `roleId`, `tenant_id`, `is_delete`)
|
||||||
|
VALUES (2, 'zc', 'd3df61764ee9a26091f714b88958caef', 1, 1, 0);
|
||||||
|
|
||||||
-- 站点标题与 Logo(与 admin_core paramSetupServer / sys_title 页一致)
|
-- 站点标题与 Logo(与 admin_core paramSetupServer / sys_title 页一致)
|
||||||
INSERT INTO `sys_parameter` (`key`, `value`, `remark`, `is_modified`, `is_delete`) VALUES
|
INSERT INTO `sys_parameter` (`key`, `value`, `remark`, `is_modified`, `is_delete`) VALUES
|
||||||
('sys_title', '管理系统', '登录页与顶栏标题', 0, 0),
|
('sys_title', '管理系统', '登录页与顶栏标题', 0, 0),
|
||||||
@@ -131,15 +134,25 @@ INSERT INTO `sys_parameter` (`key`, `value`, `remark`, `is_modified`, `is_delete
|
|||||||
-- ----------------------------------------------------------------------------- 菜单(与 admin_core defaultMenus 对齐,便于权限与动态路由)
|
-- ----------------------------------------------------------------------------- 菜单(与 admin_core defaultMenus 对齐,便于权限与动态路由)
|
||||||
INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `icon`, `path`, `type`, `model_id`, `form_id`, `component`, `api_path`, `is_show_menu`, `is_show`, `sort`, `is_delete`) VALUES
|
INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `icon`, `path`, `type`, `model_id`, `form_id`, `component`, `api_path`, `is_show_menu`, `is_show`, `sort`, `is_delete`) VALUES
|
||||||
(1, '首页', 0, 'md-home', '/home', '页面', 0, 0, 'home/index', '', 1, 1, 1, 0),
|
(1, '首页', 0, 'md-home', '/home', '页面', 0, 0, 'home/index', '', 1, 1, 1, 0),
|
||||||
|
(200, '业务演示', 0, 'md-bulb', '/demo', '菜单', 0, 0, '', '', 1, 1, 4, 0),
|
||||||
|
(201, '演示数据', 200, 'md-grid', '/demo/tpl-demo', '页面', 0, 0, 'demo/tpl_demo', '', 1, 1, 1, 0),
|
||||||
(5, '系统管理', 0, 'md-settings', '/system', '菜单', 0, 0, '', '', 1, 1, 2, 0),
|
(5, '系统管理', 0, 'md-settings', '/system', '菜单', 0, 0, '', '', 1, 1, 2, 0),
|
||||||
(11, '用户管理', 5, 'md-person', '/system/user', '页面', 0, 0, 'system/sys_user', '', 1, 1, 1, 0),
|
(11, '用户管理', 5, 'md-person', '/system/user', '页面', 0, 0, 'system/sys_user', '', 1, 1, 1, 0),
|
||||||
(12, '角色管理', 5, 'md-people', '/system/role', '页面', 0, 0, 'system/sys_role', '', 1, 1, 2, 0),
|
(12, '角色管理', 5, 'md-people', '/system/role', '页面', 0, 0, 'system/sys_role', '', 1, 1, 2, 0),
|
||||||
(13, '系统日志', 5, 'md-list', '/system/log', '页面', 0, 0, 'system/sys_log', '', 1, 1, 3, 0),
|
(13, '系统日志', 5, 'md-list', '/system/log', '页面', 0, 0, 'system/sys_log', '', 1, 1, 3, 0),
|
||||||
(15, '参数设置', 5, 'md-options', '/system/param', '页面', 0, 0, 'system/sys_param_setup', '', 1, 1, 4, 0),
|
(14, '操作日志', 5, 'md-pulse', '/system/log-operate', '页面', 0, 0, 'system/sys_log_operate', '', 1, 1, 4, 0),
|
||||||
|
(15, '参数设置', 5, 'md-options', '/system/param', '页面', 0, 0, 'system/sys_param_setup', '', 1, 1, 5, 0),
|
||||||
(120, '高级管理', 0, 'md-construct', '/system', '菜单', 0, 0, '', '', 1, 1, 3, 0),
|
(120, '高级管理', 0, 'md-construct', '/system', '菜单', 0, 0, '', '', 1, 1, 3, 0),
|
||||||
(122, '菜单管理', 120, 'md-menu', '/system/menu', '页面', 0, 0, 'system/sys_menu', '', 1, 1, 1, 0),
|
(122, '菜单管理', 120, 'md-menu', '/system/menu', '页面', 0, 0, 'system/sys_menu', '', 1, 1, 1, 0),
|
||||||
(124, '系统标题', 120, 'md-text', '/system/title', '页面', 0, 0, 'system/sys_title', '', 1, 1, 2, 0),
|
(124, '系统标题', 120, 'md-text', '/system/title', '页面', 0, 0, 'system/sys_title', '', 1, 1, 2, 0),
|
||||||
(125, '租户管理', 120, 'md-git-branch', '/system/tenant', '页面', 0, 0, 'system/sys_tenant', '', 1, 1, 3, 0);
|
(125, '租户管理', 120, 'md-git-branch', '/system/tenant', '页面', 0, 0, 'system/sys_tenant', '', 1, 1, 3, 0),
|
||||||
|
(126, '同步框架', 120, 'md-cloud-download', '/system/framework-sync', '页面', 0, 0, 'system/sys_framework_sync', '', 1, 1, 4, 0);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------- sys_log 示例数据(表结构见上;content 与 Sequelize JSON 包装一致,含 value 键)
|
||||||
|
INSERT INTO `sys_log` (`table_name`, `operate`, `content`, `is_delete`) VALUES
|
||||||
|
('sys_user', '登录', JSON_OBJECT('value', '<p>初始化示例:管理员 <span class="bold">admin</span> 登录系统</p>'), 0),
|
||||||
|
('sys_menu', '新增', JSON_OBJECT('value', '<p>初始化菜单与权限数据已写入 <span class="bold">sys_menu</span></p>'), 0),
|
||||||
|
('sys_parameter', '修改', JSON_OBJECT('value', '<p><span class="bold">sys_title</span> 默认值为「管理系统」</p>'), 0);
|
||||||
|
|
||||||
-- =============================================================================
|
-- =============================================================================
|
||||||
-- 说明:
|
-- 说明:
|
||||||
|
|||||||
Reference in New Issue
Block a user