8642 lines
391 KiB
SQL
8642 lines
391 KiB
SQL
-- -------------------------------------------------
|
||
-- RuoYi-Vue complete database script
|
||
-- Generated for this repository by merging sql/ base scripts
|
||
-- and adding generator-platform extension tables required by current Mapper files.
|
||
-- -------------------------------------------------
|
||
|
||
SET NAMES utf8mb4;
|
||
SET FOREIGN_KEY_CHECKS = 0;
|
||
|
||
-- =================================================
|
||
-- RuoYi base tables and seed data
|
||
-- Source: sql/ry_20240629.sql
|
||
-- =================================================
|
||
-- ----------------------------
|
||
-- 1、部门表
|
||
-- ----------------------------
|
||
drop table if exists sys_dept;
|
||
create table sys_dept (
|
||
dept_id bigint(20) not null auto_increment comment '部门id',
|
||
parent_id bigint(20) default 0 comment '父部门id',
|
||
ancestors varchar(50) default '' comment '祖级列表',
|
||
dept_name varchar(30) default '' comment '部门名称',
|
||
order_num int(4) default 0 comment '显示顺序',
|
||
leader varchar(20) default null comment '负责人',
|
||
phone varchar(11) default null comment '联系电话',
|
||
email varchar(50) default null comment '邮箱',
|
||
status char(1) default '0' comment '部门状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
primary key (dept_id)
|
||
) engine=innodb auto_increment=200 comment = '部门表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-部门表数据
|
||
-- ----------------------------
|
||
insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||
|
||
|
||
-- ----------------------------
|
||
-- 2、用户信息表
|
||
-- ----------------------------
|
||
drop table if exists sys_user;
|
||
create table sys_user (
|
||
user_id bigint(20) not null auto_increment comment '用户ID',
|
||
dept_id bigint(20) default null comment '部门ID',
|
||
user_name varchar(30) not null comment '用户账号',
|
||
nick_name varchar(30) not null comment '用户昵称',
|
||
user_type varchar(2) default '00' comment '用户类型(00系统用户)',
|
||
email varchar(50) default '' comment '用户邮箱',
|
||
phonenumber varchar(11) default '' comment '手机号码',
|
||
sex char(1) default '0' comment '用户性别(0男 1女 2未知)',
|
||
avatar varchar(100) default '' comment '头像地址',
|
||
password varchar(100) default '' comment '密码',
|
||
status char(1) default '0' comment '帐号状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||
login_ip varchar(128) default '' comment '最后登录IP',
|
||
login_date datetime comment '最后登录时间',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (user_id)
|
||
) engine=innodb auto_increment=100 comment = '用户信息表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-用户信息表数据
|
||
-- ----------------------------
|
||
insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员');
|
||
insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 3、岗位信息表
|
||
-- ----------------------------
|
||
drop table if exists sys_post;
|
||
create table sys_post
|
||
(
|
||
post_id bigint(20) not null auto_increment comment '岗位ID',
|
||
post_code varchar(64) not null comment '岗位编码',
|
||
post_name varchar(50) not null comment '岗位名称',
|
||
post_sort int(4) not null comment '显示顺序',
|
||
status char(1) not null comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (post_id)
|
||
) engine=innodb comment = '岗位信息表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-岗位信息表数据
|
||
-- ----------------------------
|
||
insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, '');
|
||
insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, '');
|
||
insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, '');
|
||
insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, '');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 4、角色信息表
|
||
-- ----------------------------
|
||
drop table if exists sys_role;
|
||
create table sys_role (
|
||
role_id bigint(20) not null auto_increment comment '角色ID',
|
||
role_name varchar(30) not null comment '角色名称',
|
||
role_key varchar(100) not null comment '角色权限字符串',
|
||
role_sort int(4) not null comment '显示顺序',
|
||
data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
|
||
menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示',
|
||
dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示',
|
||
status char(1) not null comment '角色状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (role_id)
|
||
) engine=innodb auto_increment=100 comment = '角色信息表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-角色信息表数据
|
||
-- ----------------------------
|
||
insert into sys_role values('1', '超级管理员', 'admin', 1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员');
|
||
insert into sys_role values('2', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '普通角色');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 5、菜单权限表
|
||
-- ----------------------------
|
||
drop table if exists sys_menu;
|
||
create table sys_menu (
|
||
menu_id bigint(20) not null auto_increment comment '菜单ID',
|
||
menu_name varchar(50) not null comment '菜单名称',
|
||
parent_id bigint(20) default 0 comment '父菜单ID',
|
||
order_num int(4) default 0 comment '显示顺序',
|
||
path varchar(200) default '' comment '路由地址',
|
||
component varchar(255) default null comment '组件路径',
|
||
query varchar(255) default null comment '路由参数',
|
||
route_name varchar(50) default '' comment '路由名称',
|
||
is_frame int(1) default 1 comment '是否为外链(0是 1否)',
|
||
is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)',
|
||
menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)',
|
||
visible char(1) default 0 comment '菜单状态(0显示 1隐藏)',
|
||
status char(1) default 0 comment '菜单状态(0正常 1停用)',
|
||
perms varchar(100) default null comment '权限标识',
|
||
icon varchar(100) default '#' comment '菜单图标',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default '' comment '备注',
|
||
primary key (menu_id)
|
||
) engine=innodb auto_increment=2000 comment = '菜单权限表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-菜单信息表数据
|
||
-- ----------------------------
|
||
-- 一级菜单
|
||
insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录');
|
||
insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录');
|
||
insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录');
|
||
insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null, '', '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, '若依官网地址');
|
||
-- 二级菜单
|
||
insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单');
|
||
insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单');
|
||
insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', sysdate(), '', null, '菜单管理菜单');
|
||
insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', sysdate(), '', null, '部门管理菜单');
|
||
insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', sysdate(), '', null, '岗位管理菜单');
|
||
insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单');
|
||
insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单');
|
||
insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单');
|
||
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单');
|
||
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单');
|
||
insert into sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', sysdate(), '', null, '定时任务菜单');
|
||
insert into sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', sysdate(), '', null, '数据监控菜单');
|
||
insert into sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', sysdate(), '', null, '服务监控菜单');
|
||
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单');
|
||
insert into sys_menu values('114', '缓存列表', '2', '6', 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', sysdate(), '', null, '缓存列表菜单');
|
||
insert into sys_menu values('115', '表单构建', '3', '1', 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单');
|
||
insert into sys_menu values('116', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单');
|
||
insert into sys_menu values('117', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单');
|
||
insert into sys_menu values('118', '代码生成平台', '0', '5', 'generator', null, '', '', 1, 0, 'M', '0', '0', '', 'code', 'admin', sysdate(), '', null, '代码生成平台目录');
|
||
insert into sys_menu values('119', '项目管理', '118', '1', 'project', 'generator/project/index', '', '', 1, 0, 'C', '0', '0', 'generator:project:list', 'project', 'admin', sysdate(), '', null, '项目管理菜单');
|
||
insert into sys_menu values('120', '数据源管理', '118', '2', 'datasource', 'generator/datasource/index','', '', 1, 0, 'C', '0', '0', 'generator:datasource:list', 'druid', 'admin', sysdate(), '', null, '数据源管理菜单');
|
||
insert into sys_menu values('121', '模板管理', '118', '3', 'template', 'generator/template/index', '', '', 1, 0, 'C', '0', '0', 'generator:template:list', 'code', 'admin', sysdate(), '', null, '模板管理菜单');
|
||
insert into sys_menu values('122', '项目结构', '118', '4', 'structure', 'generator/structure/index', '', '', 1, 0, 'C', '0', '0', 'generator:structure:list', 'tree', 'admin', sysdate(), '', null, '项目结构菜单');
|
||
insert into sys_menu values('123', '功能模块', '118', '5', 'module', 'generator/module/index', '', '', 1, 0, 'C', '0', '0', 'generator:module:list', 'tree-table', 'admin', sysdate(), '', null, '功能模块菜单');
|
||
insert into sys_menu values('124', '代码片段', '118', '6', 'snippet', 'generator/snippet/index', '', '', 1, 0, 'C', '0', '0', 'generator:snippet:list', 'list', 'admin', sysdate(), '', null, '代码片段菜单');
|
||
insert into sys_menu values('125', '源码库管理', '118', '7', 'sourceProject', 'generator/sourceProject/index', '', '', 1, 0, 'C', '0', '0', 'generator:sourceProject:list', 'code', 'admin', sysdate(), '', null, '源码库管理菜单');
|
||
insert into sys_menu values('126', '源码购买记录', '118', '8', 'sourcePurchase', 'generator/sourcePurchase/index', '', '', 1, 0, 'C', '0', '0', 'generator:sourcePurchase:list', 'money', 'admin', sysdate(), '', null, '源码购买记录菜单');
|
||
insert into sys_menu values('127', '模板反向生成', '118', '9', 'templateImport', 'generator/templateImport/index', '', '', 1, 0, 'C', '0', '0', 'generator:template:import', 'upload', 'admin', sysdate(), '', null, '模板反向生成菜单');
|
||
insert into sys_menu values('128', 'AI用量统计', '118', '10', 'aiUsage', 'generator/aiUsage/index', '', '', 1, 0, 'C', '0', '0', 'generator:aiUsage:list', 'chart', 'admin', sysdate(), '', null, 'AI用量统计菜单');
|
||
insert into sys_menu values('129', '模板包管理', '118', '11', 'templateBundle', 'generator/templateBundle/index', '', '', 1, 0, 'C', '0', '0', 'generator:templateBundle:list', 'code', 'admin', sysdate(), '', null, '模板包管理菜单');
|
||
insert into sys_menu values('130', '页面主题管理', '118', '12', 'pageTheme', 'generator/pageTheme/index', '', '', 1, 0, 'C', '0', '0', 'generator:pageTheme:list', 'theme', 'admin', sysdate(), '', null, '页面主题管理菜单');
|
||
insert into sys_menu values('131', '布局模板管理', '118', '13', 'pageLayout', 'generator/pageLayout/index', '', '', 1, 0, 'C', '0', '0', 'generator:pageLayout:list', 'component', 'admin', sysdate(), '', null, '布局模板管理菜单');
|
||
insert into sys_menu values('132', 'Prompt 中心', '118', '14', 'promptRegistry', 'generator/prompt/index', '', '', 1, 0, 'C', '0', '0', 'generator:prompt:list', 'message', 'admin', sysdate(), '', null, 'Prompt 模板、版本、调试与 A/B 测试管理');
|
||
-- 三级菜单
|
||
insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单');
|
||
insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单');
|
||
-- 用户管理按钮
|
||
insert into sys_menu values('1000', '用户查询', '100', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1001', '用户新增', '100', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1002', '用户修改', '100', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1003', '用户删除', '100', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1004', '用户导出', '100', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1005', '用户导入', '100', '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1006', '重置密码', '100', '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, '');
|
||
-- 角色管理按钮
|
||
insert into sys_menu values('1007', '角色查询', '101', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1008', '角色新增', '101', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1009', '角色修改', '101', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1010', '角色删除', '101', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1011', '角色导出', '101', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 菜单管理按钮
|
||
insert into sys_menu values('1012', '菜单查询', '102', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1013', '菜单新增', '102', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1014', '菜单修改', '102', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1015', '菜单删除', '102', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', sysdate(), '', null, '');
|
||
-- 部门管理按钮
|
||
insert into sys_menu values('1016', '部门查询', '103', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1017', '部门新增', '103', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1018', '部门修改', '103', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1019', '部门删除', '103', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', sysdate(), '', null, '');
|
||
-- 岗位管理按钮
|
||
insert into sys_menu values('1020', '岗位查询', '104', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1021', '岗位新增', '104', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1022', '岗位修改', '104', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1023', '岗位删除', '104', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1024', '岗位导出', '104', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 字典管理按钮
|
||
insert into sys_menu values('1025', '字典查询', '105', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1026', '字典新增', '105', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1027', '字典修改', '105', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1028', '字典删除', '105', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1029', '字典导出', '105', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 参数设置按钮
|
||
insert into sys_menu values('1030', '参数查询', '106', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1031', '参数新增', '106', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1032', '参数修改', '106', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1033', '参数删除', '106', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1034', '参数导出', '106', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 通知公告按钮
|
||
insert into sys_menu values('1035', '公告查询', '107', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1036', '公告新增', '107', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1037', '公告修改', '107', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1038', '公告删除', '107', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', sysdate(), '', null, '');
|
||
-- 操作日志按钮
|
||
insert into sys_menu values('1039', '操作查询', '500', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1040', '操作删除', '500', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1041', '日志导出', '500', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 登录日志按钮
|
||
insert into sys_menu values('1042', '登录查询', '501', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1043', '登录删除', '501', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1044', '日志导出', '501', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1045', '账户解锁', '501', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, '');
|
||
-- 在线用户按钮
|
||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, '');
|
||
-- 定时任务按钮
|
||
insert into sys_menu values('1049', '任务查询', '110', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1050', '任务新增', '110', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1051', '任务修改', '110', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1054', '任务导出', '110', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成按钮
|
||
insert into sys_menu values('1055', '生成查询', '116', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1056', '生成修改', '116', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1057', '生成删除', '116', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1058', '导入代码', '116', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1059', '预览代码', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1060', '生成代码', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-项目管理按钮
|
||
insert into sys_menu values('1061', '项目查询', '119', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1062', '项目新增', '119', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1063', '项目修改', '119', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1064', '项目删除', '119', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1065', '项目导出', '119', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:export', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1066', '代码预览', '119', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:preview', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1067', '代码下载', '119', '7', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:project:download', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1068', '项目表查询', '119', '8', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:list', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1069', '项目表详情', '119', '9', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1070', '项目表新增', '119', '10', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1071', '项目表修改', '119', '11', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1072', '项目表删除', '119', '12', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1073', '按项目移除表', '119', '13', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:removeByProjectId', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1074', '按表移除项目', '119', '14', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:projectTable:removeByTableId', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-数据源管理按钮
|
||
insert into sys_menu values('1075', '数据源查询', '120', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1076', '数据源新增', '120', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1077', '数据源修改', '120', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1078', '数据源删除', '120', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:remove','#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1079', '数据源导出', '120', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:export','#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1080', '连接测试', '120', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:datasource:test', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-模板管理按钮
|
||
insert into sys_menu values('1081', '模板查询', '121', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1082', '模板新增', '121', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1083', '模板修改', '121', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1084', '模板删除', '121', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1085', '模板导出', '121', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-项目结构按钮
|
||
insert into sys_menu values('1086', '结构查询', '122', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:structure:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1087', '结构新增', '122', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:structure:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1088', '结构修改', '122', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:structure:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1089', '结构删除', '122', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:structure:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1090', '结构导出', '122', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:structure:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-功能模块按钮
|
||
insert into sys_menu values('1091', '模块查询', '123', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:module:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1092', '模块新增', '123', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:module:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1093', '模块修改', '123', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:module:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1094', '模块删除', '123', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:module:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1095', '模块导出', '123', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:module:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-代码片段按钮
|
||
insert into sys_menu values('1096', '片段查询', '124', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:snippet:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1097', '片段新增', '124', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:snippet:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1098', '片段修改', '124', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:snippet:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1099', '片段删除', '124', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:snippet:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1100', '片段导出', '124', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:snippet:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-源码库管理按钮
|
||
insert into sys_menu values('1101', '源码查询', '125', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourceProject:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1102', '源码新增', '125', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourceProject:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1103', '源码修改', '125', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourceProject:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1104', '源码删除', '125', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourceProject:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1105', '源码导出', '125', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourceProject:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-源码购买记录按钮
|
||
insert into sys_menu values('1106', '购买查询', '126', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourcePurchase:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1107', '购买修改', '126', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourcePurchase:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1108', '购买导出', '126', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:sourcePurchase:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-模板反向生成按钮
|
||
insert into sys_menu values('1109', '模板分析', '127', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:template:import', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-AI用量统计按钮
|
||
insert into sys_menu values('1110', '用量查询', '128', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:aiUsage:list', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-模板包管理按钮
|
||
insert into sys_menu values('1111', '模板包查询', '129', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:templateBundle:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1112', '模板包新增', '129', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:templateBundle:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1113', '模板包修改', '129', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:templateBundle:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1114', '模板包删除', '129', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:templateBundle:remove', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1115', '模板包导出', '129', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:templateBundle:export', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-页面主题管理按钮
|
||
insert into sys_menu values('1116', '页面主题查询', '130', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageTheme:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1117', '页面主题新增', '130', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageTheme:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1118', '页面主题修改', '130', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageTheme:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1119', '页面主题删除', '130', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageTheme:remove', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-布局模板管理按钮
|
||
insert into sys_menu values('1120', '布局模板查询', '131', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageLayout:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1121', '布局模板新增', '131', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageLayout:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1122', '布局模板修改', '131', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageLayout:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1123', '布局模板删除', '131', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:pageLayout:remove', '#', 'admin', sysdate(), '', null, '');
|
||
-- 代码生成平台-Prompt 中心按钮
|
||
insert into sys_menu values('1141', 'Prompt 查询', '132', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:query', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1142', 'Prompt 新增', '132', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:add', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1143', 'Prompt 设置', '132', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:edit', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1144', '版本创建', '132', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:version', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1145', '版本发布', '132', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:publish', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1146', '版本回滚', '132', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:rollback', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1147', '在线调试', '132', '7', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:debug', '#', 'admin', sysdate(), '', null, '');
|
||
insert into sys_menu values('1148', 'A/B 测试', '132', '8', '#', '', '', '', 1, 0, 'F', '0', '0', 'generator:prompt:experiment', '#', 'admin', sysdate(), '', null, '');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 6、用户和角色关联表 用户N-1角色
|
||
-- ----------------------------
|
||
drop table if exists sys_user_role;
|
||
create table sys_user_role (
|
||
user_id bigint(20) not null comment '用户ID',
|
||
role_id bigint(20) not null comment '角色ID',
|
||
primary key(user_id, role_id)
|
||
) engine=innodb comment = '用户和角色关联表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-用户和角色关联表数据
|
||
-- ----------------------------
|
||
insert into sys_user_role values ('1', '1');
|
||
insert into sys_user_role values ('2', '2');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 7、角色和菜单关联表 角色1-N菜单
|
||
-- ----------------------------
|
||
drop table if exists sys_role_menu;
|
||
create table sys_role_menu (
|
||
role_id bigint(20) not null comment '角色ID',
|
||
menu_id bigint(20) not null comment '菜单ID',
|
||
primary key(role_id, menu_id)
|
||
) engine=innodb comment = '角色和菜单关联表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-角色和菜单关联表数据
|
||
-- ----------------------------
|
||
insert into sys_role_menu values ('2', '1');
|
||
insert into sys_role_menu values ('2', '2');
|
||
insert into sys_role_menu values ('2', '3');
|
||
insert into sys_role_menu values ('2', '4');
|
||
insert into sys_role_menu values ('2', '100');
|
||
insert into sys_role_menu values ('2', '101');
|
||
insert into sys_role_menu values ('2', '102');
|
||
insert into sys_role_menu values ('2', '103');
|
||
insert into sys_role_menu values ('2', '104');
|
||
insert into sys_role_menu values ('2', '105');
|
||
insert into sys_role_menu values ('2', '106');
|
||
insert into sys_role_menu values ('2', '107');
|
||
insert into sys_role_menu values ('2', '108');
|
||
insert into sys_role_menu values ('2', '109');
|
||
insert into sys_role_menu values ('2', '110');
|
||
insert into sys_role_menu values ('2', '111');
|
||
insert into sys_role_menu values ('2', '112');
|
||
insert into sys_role_menu values ('2', '113');
|
||
insert into sys_role_menu values ('2', '114');
|
||
insert into sys_role_menu values ('2', '115');
|
||
insert into sys_role_menu values ('2', '116');
|
||
insert into sys_role_menu values ('2', '117');
|
||
insert into sys_role_menu values ('2', '118');
|
||
insert into sys_role_menu values ('2', '119');
|
||
insert into sys_role_menu values ('2', '120');
|
||
insert into sys_role_menu values ('2', '121');
|
||
insert into sys_role_menu values ('2', '122');
|
||
insert into sys_role_menu values ('2', '123');
|
||
insert into sys_role_menu values ('2', '124');
|
||
insert into sys_role_menu values ('2', '500');
|
||
insert into sys_role_menu values ('2', '501');
|
||
insert into sys_role_menu values ('2', '1000');
|
||
insert into sys_role_menu values ('2', '1001');
|
||
insert into sys_role_menu values ('2', '1002');
|
||
insert into sys_role_menu values ('2', '1003');
|
||
insert into sys_role_menu values ('2', '1004');
|
||
insert into sys_role_menu values ('2', '1005');
|
||
insert into sys_role_menu values ('2', '1006');
|
||
insert into sys_role_menu values ('2', '1007');
|
||
insert into sys_role_menu values ('2', '1008');
|
||
insert into sys_role_menu values ('2', '1009');
|
||
insert into sys_role_menu values ('2', '1010');
|
||
insert into sys_role_menu values ('2', '1011');
|
||
insert into sys_role_menu values ('2', '1012');
|
||
insert into sys_role_menu values ('2', '1013');
|
||
insert into sys_role_menu values ('2', '1014');
|
||
insert into sys_role_menu values ('2', '1015');
|
||
insert into sys_role_menu values ('2', '1016');
|
||
insert into sys_role_menu values ('2', '1017');
|
||
insert into sys_role_menu values ('2', '1018');
|
||
insert into sys_role_menu values ('2', '1019');
|
||
insert into sys_role_menu values ('2', '1020');
|
||
insert into sys_role_menu values ('2', '1021');
|
||
insert into sys_role_menu values ('2', '1022');
|
||
insert into sys_role_menu values ('2', '1023');
|
||
insert into sys_role_menu values ('2', '1024');
|
||
insert into sys_role_menu values ('2', '1025');
|
||
insert into sys_role_menu values ('2', '1026');
|
||
insert into sys_role_menu values ('2', '1027');
|
||
insert into sys_role_menu values ('2', '1028');
|
||
insert into sys_role_menu values ('2', '1029');
|
||
insert into sys_role_menu values ('2', '1030');
|
||
insert into sys_role_menu values ('2', '1031');
|
||
insert into sys_role_menu values ('2', '1032');
|
||
insert into sys_role_menu values ('2', '1033');
|
||
insert into sys_role_menu values ('2', '1034');
|
||
insert into sys_role_menu values ('2', '1035');
|
||
insert into sys_role_menu values ('2', '1036');
|
||
insert into sys_role_menu values ('2', '1037');
|
||
insert into sys_role_menu values ('2', '1038');
|
||
insert into sys_role_menu values ('2', '1039');
|
||
insert into sys_role_menu values ('2', '1040');
|
||
insert into sys_role_menu values ('2', '1041');
|
||
insert into sys_role_menu values ('2', '1042');
|
||
insert into sys_role_menu values ('2', '1043');
|
||
insert into sys_role_menu values ('2', '1044');
|
||
insert into sys_role_menu values ('2', '1045');
|
||
insert into sys_role_menu values ('2', '1046');
|
||
insert into sys_role_menu values ('2', '1047');
|
||
insert into sys_role_menu values ('2', '1048');
|
||
insert into sys_role_menu values ('2', '1049');
|
||
insert into sys_role_menu values ('2', '1050');
|
||
insert into sys_role_menu values ('2', '1051');
|
||
insert into sys_role_menu values ('2', '1052');
|
||
insert into sys_role_menu values ('2', '1053');
|
||
insert into sys_role_menu values ('2', '1054');
|
||
insert into sys_role_menu values ('2', '1055');
|
||
insert into sys_role_menu values ('2', '1056');
|
||
insert into sys_role_menu values ('2', '1057');
|
||
insert into sys_role_menu values ('2', '1058');
|
||
insert into sys_role_menu values ('2', '1059');
|
||
insert into sys_role_menu values ('2', '1060');
|
||
insert into sys_role_menu values ('2', '1061');
|
||
insert into sys_role_menu values ('2', '1062');
|
||
insert into sys_role_menu values ('2', '1063');
|
||
insert into sys_role_menu values ('2', '1064');
|
||
insert into sys_role_menu values ('2', '1065');
|
||
insert into sys_role_menu values ('2', '1066');
|
||
insert into sys_role_menu values ('2', '1067');
|
||
insert into sys_role_menu values ('2', '1068');
|
||
insert into sys_role_menu values ('2', '1069');
|
||
insert into sys_role_menu values ('2', '1070');
|
||
insert into sys_role_menu values ('2', '1071');
|
||
insert into sys_role_menu values ('2', '1072');
|
||
insert into sys_role_menu values ('2', '1073');
|
||
insert into sys_role_menu values ('2', '1074');
|
||
insert into sys_role_menu values ('2', '1075');
|
||
insert into sys_role_menu values ('2', '1076');
|
||
insert into sys_role_menu values ('2', '1077');
|
||
insert into sys_role_menu values ('2', '1078');
|
||
insert into sys_role_menu values ('2', '1079');
|
||
insert into sys_role_menu values ('2', '1080');
|
||
insert into sys_role_menu values ('2', '1081');
|
||
insert into sys_role_menu values ('2', '1082');
|
||
insert into sys_role_menu values ('2', '1083');
|
||
insert into sys_role_menu values ('2', '1084');
|
||
insert into sys_role_menu values ('2', '1085');
|
||
insert into sys_role_menu values ('2', '1086');
|
||
insert into sys_role_menu values ('2', '1087');
|
||
insert into sys_role_menu values ('2', '1088');
|
||
insert into sys_role_menu values ('2', '1089');
|
||
insert into sys_role_menu values ('2', '1090');
|
||
insert into sys_role_menu values ('2', '1091');
|
||
insert into sys_role_menu values ('2', '1092');
|
||
insert into sys_role_menu values ('2', '1093');
|
||
insert into sys_role_menu values ('2', '1094');
|
||
insert into sys_role_menu values ('2', '1095');
|
||
insert into sys_role_menu values ('2', '1096');
|
||
insert into sys_role_menu values ('2', '1097');
|
||
insert into sys_role_menu values ('2', '1098');
|
||
insert into sys_role_menu values ('2', '1099');
|
||
insert into sys_role_menu values ('2', '1100');
|
||
|
||
-- ----------------------------
|
||
-- 8、角色和部门关联表 角色1-N部门
|
||
-- ----------------------------
|
||
drop table if exists sys_role_dept;
|
||
create table sys_role_dept (
|
||
role_id bigint(20) not null comment '角色ID',
|
||
dept_id bigint(20) not null comment '部门ID',
|
||
primary key(role_id, dept_id)
|
||
) engine=innodb comment = '角色和部门关联表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-角色和部门关联表数据
|
||
-- ----------------------------
|
||
insert into sys_role_dept values ('2', '100');
|
||
insert into sys_role_dept values ('2', '101');
|
||
insert into sys_role_dept values ('2', '105');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 9、用户与岗位关联表 用户1-N岗位
|
||
-- ----------------------------
|
||
drop table if exists sys_user_post;
|
||
create table sys_user_post
|
||
(
|
||
user_id bigint(20) not null comment '用户ID',
|
||
post_id bigint(20) not null comment '岗位ID',
|
||
primary key (user_id, post_id)
|
||
) engine=innodb comment = '用户与岗位关联表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-用户与岗位关联表数据
|
||
-- ----------------------------
|
||
insert into sys_user_post values ('1', '1');
|
||
insert into sys_user_post values ('2', '2');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 10、操作日志记录
|
||
-- ----------------------------
|
||
drop table if exists sys_oper_log;
|
||
create table sys_oper_log (
|
||
oper_id bigint(20) not null auto_increment comment '日志主键',
|
||
title varchar(50) default '' comment '模块标题',
|
||
business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)',
|
||
method varchar(200) default '' comment '方法名称',
|
||
request_method varchar(10) default '' comment '请求方式',
|
||
operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)',
|
||
oper_name varchar(50) default '' comment '操作人员',
|
||
dept_name varchar(50) default '' comment '部门名称',
|
||
oper_url varchar(255) default '' comment '请求URL',
|
||
oper_ip varchar(128) default '' comment '主机地址',
|
||
oper_location varchar(255) default '' comment '操作地点',
|
||
oper_param varchar(2000) default '' comment '请求参数',
|
||
json_result varchar(2000) default '' comment '返回参数',
|
||
status int(1) default 0 comment '操作状态(0正常 1异常)',
|
||
error_msg varchar(2000) default '' comment '错误消息',
|
||
oper_time datetime comment '操作时间',
|
||
cost_time bigint(20) default 0 comment '消耗时间',
|
||
primary key (oper_id),
|
||
key idx_sys_oper_log_bt (business_type),
|
||
key idx_sys_oper_log_s (status),
|
||
key idx_sys_oper_log_ot (oper_time)
|
||
) engine=innodb auto_increment=100 comment = '操作日志记录';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 11、字典类型表
|
||
-- ----------------------------
|
||
drop table if exists sys_dict_type;
|
||
create table sys_dict_type
|
||
(
|
||
dict_id bigint(20) not null auto_increment comment '字典主键',
|
||
dict_name varchar(100) default '' comment '字典名称',
|
||
dict_type varchar(100) default '' comment '字典类型',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (dict_id),
|
||
unique (dict_type)
|
||
) engine=innodb auto_increment=100 comment = '字典类型表';
|
||
|
||
insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表');
|
||
insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表');
|
||
insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表');
|
||
insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', sysdate(), '', null, '任务状态列表');
|
||
insert into sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', sysdate(), '', null, '任务分组列表');
|
||
insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表');
|
||
insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表');
|
||
insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表');
|
||
insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表');
|
||
insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表');
|
||
insert into sys_dict_type values(11, '源码分类', 'source_project_category', '0', 'admin', sysdate(), '', null, '源码库分类列表');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 12、字典数据表
|
||
-- ----------------------------
|
||
drop table if exists sys_dict_data;
|
||
create table sys_dict_data
|
||
(
|
||
dict_code bigint(20) not null auto_increment comment '字典编码',
|
||
dict_sort int(4) default 0 comment '字典排序',
|
||
dict_label varchar(100) default '' comment '字典标签',
|
||
dict_value varchar(100) default '' comment '字典键值',
|
||
dict_type varchar(100) default '' comment '字典类型',
|
||
css_class varchar(100) default null comment '样式属性(其他样式扩展)',
|
||
list_class varchar(100) default null comment '表格回显样式',
|
||
is_default char(1) default 'N' comment '是否默认(Y是 N否)',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (dict_code)
|
||
) engine=innodb auto_increment=100 comment = '字典数据表';
|
||
|
||
insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男');
|
||
insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女');
|
||
insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知');
|
||
insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单');
|
||
insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单');
|
||
insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||
insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||
insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||
insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||
insert into sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', sysdate(), '', null, '默认分组');
|
||
insert into sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', sysdate(), '', null, '系统分组');
|
||
insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是');
|
||
insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否');
|
||
insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知');
|
||
insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告');
|
||
insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||
insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态');
|
||
insert into sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作');
|
||
insert into sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作');
|
||
insert into sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作');
|
||
insert into sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作');
|
||
insert into sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作');
|
||
insert into sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作');
|
||
insert into sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作');
|
||
insert into sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作');
|
||
insert into sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作');
|
||
insert into sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作');
|
||
insert into sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态');
|
||
insert into sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||
insert into sys_dict_data values(30, 1, '企业管理系统', 'enterprise', 'source_project_category', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '源码分类-企业管理系统');
|
||
insert into sys_dict_data values(31, 2, '商城系统', 'mall', 'source_project_category', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '源码分类-商城系统');
|
||
insert into sys_dict_data values(32, 3, 'OA 办公', 'office', 'source_project_category', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '源码分类-OA 办公');
|
||
insert into sys_dict_data values(33, 4, '低代码平台', 'lowcode', 'source_project_category', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '源码分类-低代码平台');
|
||
insert into sys_dict_data values(34, 5, '微服务脚手架', 'microservice', 'source_project_category', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '源码分类-微服务脚手架');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 13、参数配置表
|
||
-- ----------------------------
|
||
drop table if exists sys_config;
|
||
create table sys_config (
|
||
config_id int(5) not null auto_increment comment '参数主键',
|
||
config_name varchar(100) default '' comment '参数名称',
|
||
config_key varchar(100) default '' comment '参数键名',
|
||
config_value varchar(500) default '' comment '参数键值',
|
||
config_type char(1) default 'N' comment '系统内置(Y是 N否)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (config_id)
|
||
) engine=innodb auto_increment=100 comment = '参数配置表';
|
||
|
||
insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
|
||
insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
|
||
insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' );
|
||
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
|
||
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
|
||
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 14、系统访问记录
|
||
-- ----------------------------
|
||
drop table if exists sys_logininfor;
|
||
create table sys_logininfor (
|
||
info_id bigint(20) not null auto_increment comment '访问ID',
|
||
user_name varchar(50) default '' comment '用户账号',
|
||
ipaddr varchar(128) default '' comment '登录IP地址',
|
||
login_location varchar(255) default '' comment '登录地点',
|
||
browser varchar(50) default '' comment '浏览器类型',
|
||
os varchar(50) default '' comment '操作系统',
|
||
status char(1) default '0' comment '登录状态(0成功 1失败)',
|
||
msg varchar(255) default '' comment '提示消息',
|
||
login_time datetime comment '访问时间',
|
||
primary key (info_id),
|
||
key idx_sys_logininfor_s (status),
|
||
key idx_sys_logininfor_lt (login_time)
|
||
) engine=innodb auto_increment=100 comment = '系统访问记录';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 15、定时任务调度表
|
||
-- ----------------------------
|
||
drop table if exists sys_job;
|
||
create table sys_job (
|
||
job_id bigint(20) not null auto_increment comment '任务ID',
|
||
job_name varchar(64) default '' comment '任务名称',
|
||
job_group varchar(64) default 'DEFAULT' comment '任务组名',
|
||
invoke_target varchar(500) not null comment '调用目标字符串',
|
||
cron_expression varchar(255) default '' comment 'cron执行表达式',
|
||
misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
|
||
concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)',
|
||
status char(1) default '0' comment '状态(0正常 1暂停)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default '' comment '备注信息',
|
||
primary key (job_id, job_name, job_group)
|
||
) engine=innodb auto_increment=100 comment = '定时任务调度表';
|
||
|
||
insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||
insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||
insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 16、定时任务调度日志表
|
||
-- ----------------------------
|
||
drop table if exists sys_job_log;
|
||
create table sys_job_log (
|
||
job_log_id bigint(20) not null auto_increment comment '任务日志ID',
|
||
job_name varchar(64) not null comment '任务名称',
|
||
job_group varchar(64) not null comment '任务组名',
|
||
invoke_target varchar(500) not null comment '调用目标字符串',
|
||
job_message varchar(500) comment '日志信息',
|
||
status char(1) default '0' comment '执行状态(0正常 1失败)',
|
||
exception_info varchar(2000) default '' comment '异常信息',
|
||
create_time datetime comment '创建时间',
|
||
primary key (job_log_id)
|
||
) engine=innodb comment = '定时任务调度日志表';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 17、通知公告表
|
||
-- ----------------------------
|
||
drop table if exists sys_notice;
|
||
create table sys_notice (
|
||
notice_id int(4) not null auto_increment comment '公告ID',
|
||
notice_title varchar(50) not null comment '公告标题',
|
||
notice_type char(1) not null comment '公告类型(1通知 2公告)',
|
||
notice_content longblob default null comment '公告内容',
|
||
status char(1) default '0' comment '公告状态(0正常 1关闭)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(255) default null comment '备注',
|
||
primary key (notice_id)
|
||
) engine=innodb auto_increment=10 comment = '通知公告表';
|
||
|
||
-- ----------------------------
|
||
-- 初始化-公告信息表数据
|
||
-- ----------------------------
|
||
insert into sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');
|
||
insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员');
|
||
|
||
|
||
-- ----------------------------
|
||
-- 18、代码生成业务表
|
||
-- ----------------------------
|
||
drop table if exists gen_table;
|
||
create table gen_table (
|
||
table_id bigint(20) not null auto_increment comment '编号',
|
||
table_name varchar(200) default '' comment '表名称',
|
||
table_comment varchar(500) default '' comment '表描述',
|
||
sub_table_name varchar(64) default null comment '关联子表的表名',
|
||
sub_table_fk_name varchar(64) default null comment '子表关联的外键名',
|
||
class_name varchar(100) default '' comment '实体类名称',
|
||
tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)',
|
||
tpl_web_type varchar(30) default '' comment '前端模板类型(element-ui模版 element-plus模版)',
|
||
package_name varchar(100) comment '生成包路径',
|
||
module_name varchar(30) comment '生成模块名',
|
||
business_name varchar(30) comment '生成业务名',
|
||
function_name varchar(50) comment '生成功能名',
|
||
function_author varchar(50) comment '生成功能作者',
|
||
gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)',
|
||
gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)',
|
||
create_table_sql longtext comment '建表SQL语句',
|
||
admin_menu_name varchar(100) default '' comment '后台菜单名称',
|
||
allow_add char(1) default '1' comment '是否允许新增(1是 0否)',
|
||
allow_edit char(1) default '1' comment '是否允许修改(1是 0否)',
|
||
allow_remove char(1) default '1' comment '是否允许删除(1是 0否)',
|
||
remove_type varchar(20) default 'physical' comment '删除方式(none不允许 logical逻辑删除 physical物理删除)',
|
||
operation_note varchar(500) default '' comment '操作能力说明',
|
||
options varchar(1000) comment '其它生成选项',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (table_id)
|
||
) engine=innodb auto_increment=1 comment = '代码生成业务表';
|
||
|
||
|
||
-- ----------------------------
|
||
-- 19、代码生成业务表字段
|
||
-- ----------------------------
|
||
drop table if exists gen_table_column;
|
||
create table gen_table_column (
|
||
column_id bigint(20) not null auto_increment comment '编号',
|
||
table_id bigint(20) comment '归属表编号',
|
||
column_name varchar(200) comment '列名称',
|
||
column_comment varchar(500) comment '列描述',
|
||
column_type varchar(100) comment '列类型',
|
||
java_type varchar(500) comment 'JAVA类型',
|
||
java_field varchar(200) comment 'JAVA字段名',
|
||
is_pk char(1) comment '是否主键(1是)',
|
||
is_increment char(1) comment '是否自增(1是)',
|
||
is_required char(1) comment '是否必填(1是)',
|
||
is_insert char(1) comment '是否为插入字段(1是)',
|
||
is_edit char(1) comment '是否编辑字段(1是)',
|
||
is_list char(1) comment '是否列表字段(1是)',
|
||
is_query char(1) comment '是否查询字段(1是)',
|
||
query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)',
|
||
html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
|
||
dict_type varchar(200) default '' comment '字典类型',
|
||
sort int comment '排序',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
primary key (column_id)
|
||
) engine=innodb auto_increment=1 comment = '代码生成业务表字段';
|
||
|
||
-- =================================================
|
||
-- Quartz scheduler tables
|
||
-- Source: sql/quartz.sql
|
||
-- =================================================
|
||
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
||
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
||
DROP TABLE IF EXISTS QRTZ_LOCKS;
|
||
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
|
||
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
|
||
DROP TABLE IF EXISTS QRTZ_CALENDARS;
|
||
|
||
-- ----------------------------
|
||
-- 1、存储每一个已配置的 jobDetail 的详细信息
|
||
-- ----------------------------
|
||
create table QRTZ_JOB_DETAILS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
job_name varchar(200) not null comment '任务名称',
|
||
job_group varchar(200) not null comment '任务组名',
|
||
description varchar(250) null comment '相关介绍',
|
||
job_class_name varchar(250) not null comment '执行任务类名称',
|
||
is_durable varchar(1) not null comment '是否持久化',
|
||
is_nonconcurrent varchar(1) not null comment '是否并发',
|
||
is_update_data varchar(1) not null comment '是否更新数据',
|
||
requests_recovery varchar(1) not null comment '是否接受恢复执行',
|
||
job_data blob null comment '存放持久化job对象',
|
||
primary key (sched_name, job_name, job_group)
|
||
) engine=innodb comment = '任务详细信息表';
|
||
|
||
-- ----------------------------
|
||
-- 2、 存储已配置的 Trigger 的信息
|
||
-- ----------------------------
|
||
create table QRTZ_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_name varchar(200) not null comment '触发器的名字',
|
||
trigger_group varchar(200) not null comment '触发器所属组的名字',
|
||
job_name varchar(200) not null comment 'qrtz_job_details表job_name的外键',
|
||
job_group varchar(200) not null comment 'qrtz_job_details表job_group的外键',
|
||
description varchar(250) null comment '相关介绍',
|
||
next_fire_time bigint(13) null comment '上一次触发时间(毫秒)',
|
||
prev_fire_time bigint(13) null comment '下一次触发时间(默认为-1表示不触发)',
|
||
priority integer null comment '优先级',
|
||
trigger_state varchar(16) not null comment '触发器状态',
|
||
trigger_type varchar(8) not null comment '触发器的类型',
|
||
start_time bigint(13) not null comment '开始时间',
|
||
end_time bigint(13) null comment '结束时间',
|
||
calendar_name varchar(200) null comment '日程表名称',
|
||
misfire_instr smallint(2) null comment '补偿执行的策略',
|
||
job_data blob null comment '存放持久化job对象',
|
||
primary key (sched_name, trigger_name, trigger_group),
|
||
foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group)
|
||
) engine=innodb comment = '触发器详细信息表';
|
||
|
||
-- ----------------------------
|
||
-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
|
||
-- ----------------------------
|
||
create table QRTZ_SIMPLE_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
repeat_count bigint(7) not null comment '重复的次数统计',
|
||
repeat_interval bigint(12) not null comment '重复的间隔时间',
|
||
times_triggered bigint(10) not null comment '已经触发的次数',
|
||
primary key (sched_name, trigger_name, trigger_group),
|
||
foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
|
||
) engine=innodb comment = '简单触发器的信息表';
|
||
|
||
-- ----------------------------
|
||
-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
|
||
-- ----------------------------
|
||
create table QRTZ_CRON_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
cron_expression varchar(200) not null comment 'cron表达式',
|
||
time_zone_id varchar(80) comment '时区',
|
||
primary key (sched_name, trigger_name, trigger_group),
|
||
foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
|
||
) engine=innodb comment = 'Cron类型的触发器表';
|
||
|
||
-- ----------------------------
|
||
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
|
||
-- ----------------------------
|
||
create table QRTZ_BLOB_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
blob_data blob null comment '存放持久化Trigger对象',
|
||
primary key (sched_name, trigger_name, trigger_group),
|
||
foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
|
||
) engine=innodb comment = 'Blob类型的触发器表';
|
||
|
||
-- ----------------------------
|
||
-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
|
||
-- ----------------------------
|
||
create table QRTZ_CALENDARS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
calendar_name varchar(200) not null comment '日历名称',
|
||
calendar blob not null comment '存放持久化calendar对象',
|
||
primary key (sched_name, calendar_name)
|
||
) engine=innodb comment = '日历信息表';
|
||
|
||
-- ----------------------------
|
||
-- 7、 存储已暂停的 Trigger 组的信息
|
||
-- ----------------------------
|
||
create table QRTZ_PAUSED_TRIGGER_GRPS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
primary key (sched_name, trigger_group)
|
||
) engine=innodb comment = '暂停的触发器表';
|
||
|
||
-- ----------------------------
|
||
-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
|
||
-- ----------------------------
|
||
create table QRTZ_FIRED_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
entry_id varchar(95) not null comment '调度器实例id',
|
||
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
instance_name varchar(200) not null comment '调度器实例名',
|
||
fired_time bigint(13) not null comment '触发的时间',
|
||
sched_time bigint(13) not null comment '定时器制定的时间',
|
||
priority integer not null comment '优先级',
|
||
state varchar(16) not null comment '状态',
|
||
job_name varchar(200) null comment '任务名称',
|
||
job_group varchar(200) null comment '任务组名',
|
||
is_nonconcurrent varchar(1) null comment '是否并发',
|
||
requests_recovery varchar(1) null comment '是否接受恢复执行',
|
||
primary key (sched_name, entry_id)
|
||
) engine=innodb comment = '已触发的触发器表';
|
||
|
||
-- ----------------------------
|
||
-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
|
||
-- ----------------------------
|
||
create table QRTZ_SCHEDULER_STATE (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
instance_name varchar(200) not null comment '实例名称',
|
||
last_checkin_time bigint(13) not null comment '上次检查时间',
|
||
checkin_interval bigint(13) not null comment '检查间隔时间',
|
||
primary key (sched_name, instance_name)
|
||
) engine=innodb comment = '调度器状态表';
|
||
|
||
-- ----------------------------
|
||
-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
|
||
-- ----------------------------
|
||
create table QRTZ_LOCKS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
lock_name varchar(40) not null comment '悲观锁名称',
|
||
primary key (sched_name, lock_name)
|
||
) engine=innodb comment = '存储的悲观锁信息表';
|
||
|
||
-- ----------------------------
|
||
-- 11、 Quartz集群实现同步机制的行锁表
|
||
-- ----------------------------
|
||
create table QRTZ_SIMPROP_TRIGGERS (
|
||
sched_name varchar(120) not null comment '调度名称',
|
||
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
|
||
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
|
||
str_prop_1 varchar(512) null comment 'String类型的trigger的第一个参数',
|
||
str_prop_2 varchar(512) null comment 'String类型的trigger的第二个参数',
|
||
str_prop_3 varchar(512) null comment 'String类型的trigger的第三个参数',
|
||
int_prop_1 int null comment 'int类型的trigger的第一个参数',
|
||
int_prop_2 int null comment 'int类型的trigger的第二个参数',
|
||
long_prop_1 bigint null comment 'long类型的trigger的第一个参数',
|
||
long_prop_2 bigint null comment 'long类型的trigger的第二个参数',
|
||
dec_prop_1 numeric(13,4) null comment 'decimal类型的trigger的第一个参数',
|
||
dec_prop_2 numeric(13,4) null comment 'decimal类型的trigger的第二个参数',
|
||
bool_prop_1 varchar(1) null comment 'Boolean类型的trigger的第一个参数',
|
||
bool_prop_2 varchar(1) null comment 'Boolean类型的trigger的第二个参数',
|
||
primary key (sched_name, trigger_name, trigger_group),
|
||
foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
|
||
) engine=innodb comment = '同步机制的行锁表';
|
||
|
||
commit;
|
||
|
||
-- =================================================
|
||
-- Generator-platform extension tables
|
||
-- =================================================
|
||
|
||
-- ----------------------------
|
||
-- 代码生成扩展表
|
||
-- ----------------------------
|
||
|
||
-- ----------------------------
|
||
-- 1、项目表
|
||
-- ----------------------------
|
||
drop table if exists gen_project;
|
||
create table gen_project (
|
||
project_id bigint(20) not null auto_increment comment '项目ID',
|
||
project_name varchar(50) not null comment '项目名称',
|
||
project_file_name varchar(100) default '' comment '项目文件名称',
|
||
package_name varchar(100) not null comment '包名',
|
||
version varchar(20) not null comment '版本号',
|
||
project_desc varchar(500) default null comment '项目描述',
|
||
author varchar(50) not null comment '作者',
|
||
front_framework varchar(50) not null comment '前端框架',
|
||
back_framework varchar(50) not null comment '后端框架',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (project_id)
|
||
) engine=innodb auto_increment=100 comment = '项目表';
|
||
|
||
-- ----------------------------
|
||
-- 2、数据源信息表
|
||
-- ----------------------------
|
||
drop table if exists sys_datasource;
|
||
create table sys_datasource (
|
||
datasource_id bigint(20) not null auto_increment comment '数据源ID',
|
||
datasource_name varchar(100) not null comment '数据源名称',
|
||
driver varchar(255) default 'com.mysql.cj.jdbc.Driver' comment '数据库驱动',
|
||
url varchar(1000) not null comment '数据源URL',
|
||
user varchar(100) not null comment '用户名',
|
||
password varchar(255) default null comment '密码',
|
||
primary key (datasource_id)
|
||
) engine=innodb auto_increment=100 comment = '数据源信息表';
|
||
|
||
-- ----------------------------
|
||
-- 3、功能模块表
|
||
-- ----------------------------
|
||
drop table if exists sys_module;
|
||
create table sys_module (
|
||
module_id bigint(20) not null auto_increment comment '模块ID',
|
||
module_name varchar(50) not null comment '模块名称',
|
||
module_alias varchar(50) default '' comment '模块别名',
|
||
module_desc varchar(500) default '' comment '模块描述',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (module_id)
|
||
) engine=innodb auto_increment=100 comment = '功能模块表';
|
||
|
||
-- ----------------------------
|
||
-- 4、代码模板表
|
||
-- ----------------------------
|
||
drop table if exists sys_template_artifact;
|
||
drop table if exists sys_template_bundle;
|
||
create table sys_template_bundle (
|
||
bundle_id bigint(20) not null auto_increment comment 'template bundle id',
|
||
bundle_code varchar(64) not null comment 'template bundle code',
|
||
bundle_name varchar(100) not null comment 'template bundle name',
|
||
description varchar(500) default null comment 'description',
|
||
preview_image varchar(500) default null comment 'template bundle preview image',
|
||
status char(1) not null default '0' comment 'status 0 normal 1 disabled',
|
||
is_default char(1) not null default '0' comment 'default bundle 1 yes 0 no',
|
||
support_backend char(1) not null default '1' comment 'supports backend',
|
||
support_frontend char(1) not null default '1' comment 'supports frontend',
|
||
support_admin_frontend char(1) not null default '1' comment 'supports admin frontend',
|
||
support_sql char(1) not null default '1' comment 'supports sql',
|
||
sort_order int default 0 comment 'sort order',
|
||
create_by varchar(64) default '' comment 'creator',
|
||
create_time datetime comment 'create time',
|
||
update_by varchar(64) default '' comment 'updater',
|
||
update_time datetime comment 'update time',
|
||
remark varchar(500) default null comment 'remark',
|
||
primary key (bundle_id),
|
||
unique key uk_template_bundle_code (bundle_code)
|
||
) engine=innodb auto_increment=100 comment = 'code template bundle table';
|
||
|
||
drop table if exists sys_template;
|
||
create table sys_template (
|
||
template_id bigint(20) not null auto_increment comment '模板ID',
|
||
template_name varchar(100) not null comment '模板名称',
|
||
template_path varchar(255) default '' comment '模板路径',
|
||
template_desc varchar(500) default null comment '模板描述',
|
||
template_type varchar(50) default '' comment '模板类型',
|
||
bundle_code varchar(64) default 'qing' comment 'template bundle code',
|
||
template_status bigint(20) default 0 comment '模板状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
key idx_template_bundle_code (bundle_code),
|
||
primary key (template_id)
|
||
) engine=innodb auto_increment=100 comment = '代码模板表';
|
||
|
||
insert into sys_template_bundle
|
||
(bundle_id, bundle_code, bundle_name, description, preview_image, status, is_default, support_backend,
|
||
support_frontend, support_admin_frontend, support_sql, sort_order, create_by, create_time, remark)
|
||
values
|
||
(1, 'qing', 'Qing Default Template', 'Spring Boot + MyBatis Plus + Vue2 runnable template', null, '0', '1',
|
||
'1', '1', '1', '1', 1, 'admin', sysdate(), 'default code template bundle');
|
||
|
||
-- ----------------------------
|
||
-- 4.1、页面主题与布局模板目录
|
||
-- ----------------------------
|
||
drop table if exists sys_page_layout_template;
|
||
drop table if exists sys_page_theme;
|
||
create table sys_page_theme (
|
||
theme_id bigint(20) not null auto_increment, theme_code varchar(64) not null, theme_name varchar(100) not null,
|
||
description varchar(500) default null, framework varchar(64) not null default 'vue2-element-ui',
|
||
density varchar(32) not null default 'comfortable', tokens_json longtext not null,
|
||
component_defaults_json longtext, shell_json longtext, layout_policy_json longtext, asset_policy_json longtext,
|
||
preview_image varchar(500) default null, version int not null default 1,
|
||
status char(1) not null default '0', sort_order int not null default 0,
|
||
create_by varchar(64) default '', create_time datetime, update_by varchar(64) default '', update_time datetime,
|
||
remark varchar(500) default null, primary key (theme_id), unique key uk_page_theme_code (theme_code)
|
||
) engine=innodb default charset=utf8mb4 comment='generated page theme catalog';
|
||
|
||
create table sys_page_layout_template (
|
||
layout_id bigint(20) not null auto_increment, layout_code varchar(100) not null, layout_name varchar(100) not null,
|
||
description varchar(500) default null, page_type varchar(50) not null, page_scope varchar(20) not null default 'all',
|
||
framework varchar(64) not null default 'vue2-element-ui', render_template_key varchar(150) not null,
|
||
config_json longtext, compatibility_json longtext, preview_image varchar(500) default null,
|
||
version int not null default 1, weight int not null default 1, status char(1) not null default '0',
|
||
sort_order int not null default 0, create_by varchar(64) default '', create_time datetime,
|
||
update_by varchar(64) default '', update_time datetime, remark varchar(500) default null,
|
||
primary key (layout_id), unique key uk_page_layout_code (layout_code),
|
||
key idx_page_layout_type_scope (page_type, page_scope, status)
|
||
) engine=innodb default charset=utf8mb4 comment='generated page layout catalog';
|
||
|
||
insert into sys_page_theme
|
||
(theme_code,theme_name,description,framework,density,tokens_json,component_defaults_json,version,status,sort_order,create_by,create_time) values
|
||
('classic-admin','经典后台','传统企业后台主题','vue2-element-ui','compact','{"primary":"#409eff","primaryStrong":"#337ecc","primarySoft":"#ecf5ff","accent":"#67c23a","background":"#f4f6f8","surface":"#fff","border":"#dcdfe6","text":"#303133","textSecondary":"#606266","radiusSm":"4px","radiusMd":"6px","radiusLg":"8px","shadowSm":"0 2px 12px rgba(0,0,0,.06)","shadowMd":"0 10px 30px rgba(0,0,0,.10)","contentWidth":"1280px"}','{"formStyle":"inline","dialogStyle":"dialog","tableStyle":"border","buttonStyle":"square"}',1,'0',10,'system',sysdate()),
|
||
('modern-blue','现代蓝','现代卡片式蓝色主题','vue2-element-ui','comfortable','{"primary":"#2563eb","primaryStrong":"#1d4ed8","primarySoft":"#eff6ff","accent":"#06b6d4","background":"#f5f7fb","surface":"#fff","border":"#dbe5f3","text":"#172033","textSecondary":"#64748b","radiusSm":"8px","radiusMd":"12px","radiusLg":"18px","shadowSm":"0 8px 24px rgba(37,99,235,.08)","shadowMd":"0 20px 48px rgba(37,99,235,.14)","contentWidth":"1200px"}','{"formStyle":"top","dialogStyle":"drawer","tableStyle":"card","buttonStyle":"round"}',1,'0',20,'system',sysdate()),
|
||
('soft-green','清新绿','社区与预约场景主题','vue2-element-ui','comfortable','{"primary":"#16a34a","primaryStrong":"#15803d","primarySoft":"#f0fdf4","accent":"#0d9488","background":"#f7fbf8","surface":"#fff","border":"#dcebe0","text":"#183022","textSecondary":"#607468","radiusSm":"10px","radiusMd":"14px","radiusLg":"20px","shadowSm":"0 8px 22px rgba(22,163,74,.07)","shadowMd":"0 18px 42px rgba(22,163,74,.12)","contentWidth":"1180px"}','{"formStyle":"top","dialogStyle":"drawer","tableStyle":"card","buttonStyle":"round"}',1,'0',30,'system',sysdate()),
|
||
('dark-tech','科技黑','暗色科技看板主题','vue2-element-ui','compact','{"primary":"#38bdf8","primaryStrong":"#0284c7","primarySoft":"#082f49","accent":"#a78bfa","background":"#07111f","surface":"#101c2d","border":"#26364a","text":"#e5f2ff","textSecondary":"#94a9bf","radiusSm":"8px","radiusMd":"12px","radiusLg":"18px","shadowSm":"0 8px 24px rgba(0,0,0,.22)","shadowMd":"0 22px 54px rgba(0,0,0,.35)","contentWidth":"1280px"}','{"formStyle":"top","dialogStyle":"drawer","tableStyle":"border","buttonStyle":"round"}',1,'0',40,'system',sysdate()),
|
||
('campus-orange','校园橙','校园服务活力主题','vue2-element-ui','comfortable','{"primary":"#ea580c","primaryStrong":"#c2410c","primarySoft":"#fff7ed","accent":"#2563eb","background":"#fffaf5","surface":"#fff","border":"#f0dfd2","text":"#2f241d","textSecondary":"#78685d","radiusSm":"10px","radiusMd":"14px","radiusLg":"20px","shadowSm":"0 8px 22px rgba(234,88,12,.08)","shadowMd":"0 20px 46px rgba(234,88,12,.14)","contentWidth":"1180px"}','{"formStyle":"top","dialogStyle":"dialog","tableStyle":"stripe","buttonStyle":"round"}',1,'0',50,'system',sysdate()),
|
||
('elegant-purple','优雅紫','内容与服务型项目主题','vue2-element-ui','comfortable','{"primary":"#7c3aed","primaryStrong":"#6d28d9","primarySoft":"#f5f3ff","accent":"#db2777","background":"#faf8ff","surface":"#fff","border":"#e6def4","text":"#292038","textSecondary":"#746a82","radiusSm":"10px","radiusMd":"14px","radiusLg":"20px","shadowSm":"0 8px 24px rgba(124,58,237,.08)","shadowMd":"0 20px 48px rgba(124,58,237,.14)","contentWidth":"1200px"}','{"formStyle":"top","dialogStyle":"drawer","tableStyle":"card","buttonStyle":"round"}',1,'0',60,'system',sysdate()),
|
||
('minimal-white','极简白','低装饰高留白主题','vue2-element-ui','comfortable','{"primary":"#111827","primaryStrong":"#030712","primarySoft":"#f3f4f6","accent":"#4b5563","background":"#f9fafb","surface":"#fff","border":"#e5e7eb","text":"#111827","textSecondary":"#6b7280","radiusSm":"4px","radiusMd":"6px","radiusLg":"10px","shadowSm":"0 2px 10px rgba(15,23,42,.04)","shadowMd":"0 10px 30px rgba(15,23,42,.08)","contentWidth":"1160px"}','{"formStyle":"top","dialogStyle":"dialog","tableStyle":"plain","buttonStyle":"square"}',1,'0',70,'system',sysdate());
|
||
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"sidebar","adminNavigation":"sidebar","header":"compact","login":"centered","contentFrame":"wide"}', layout_policy_json='{"frontend.list":"frontend-list-v1","frontend.current_user_list":"frontend-current-user-list-v1","frontend.detail":"frontend-detail-v1","frontend.form":"frontend-form-v1","admin.list":"admin-list-v1","admin.detail":"admin-detail-v1","admin.form":"admin-form-v1"}', asset_policy_json='{"iconStyle":"classic","illustrationStyle":"business","chartPalette":["#409eff","#67c23a","#e6a23c","#909399","#f56c6c"]}' where theme_code='classic-admin';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"top","adminNavigation":"top","header":"hero","login":"split","contentFrame":"contained"}', layout_policy_json='{"frontend.list":"frontend-list-card-v1","frontend.current_user_list":"frontend-current-user-card-v1","frontend.detail":"frontend-detail-media-v1","frontend.form":"frontend-form-group-v1","admin.list":"admin-list-v1"}', asset_policy_json='{"iconStyle":"outline","illustrationStyle":"modern","chartPalette":["#2563eb","#06b6d4","#7c3aed","#f59e0b","#10b981"]}' where theme_code='modern-blue';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"top","adminNavigation":"top","header":"hero","login":"split","contentFrame":"contained"}', layout_policy_json='{"frontend.list":"frontend-list-card-v1","frontend.current_user_list":"frontend-current-user-card-v1","frontend.detail":"frontend-detail-v1","frontend.form":"frontend-form-v1","admin.list":"admin-list-v1"}', asset_policy_json='{"iconStyle":"rounded","illustrationStyle":"natural","chartPalette":["#16a34a","#0d9488","#84cc16","#2563eb","#f59e0b"]}' where theme_code='soft-green';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"sidebar","adminNavigation":"sidebar","header":"compact","login":"centered","contentFrame":"wide"}', layout_policy_json='{"frontend.list":"frontend-list-card-v1","frontend.current_user_list":"frontend-current-user-card-v1","frontend.detail":"frontend-detail-media-v1","frontend.form":"frontend-form-group-v1","admin.list":"admin-list-dense-v1"}', asset_policy_json='{"iconStyle":"neon","illustrationStyle":"technical","chartPalette":["#38bdf8","#a78bfa","#22d3ee","#34d399","#fbbf24"]}' where theme_code='dark-tech';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"top","adminNavigation":"top","header":"hero","login":"split","contentFrame":"contained"}', layout_policy_json='{"frontend.list":"frontend-list-card-v1","frontend.current_user_list":"frontend-current-user-card-v1","frontend.detail":"frontend-detail-media-v1","frontend.form":"frontend-form-v1","admin.list":"admin-list-v1"}', asset_policy_json='{"iconStyle":"rounded","illustrationStyle":"youthful","chartPalette":["#ea580c","#2563eb","#f59e0b","#16a34a","#db2777"]}' where theme_code='campus-orange';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"top","adminNavigation":"top","header":"hero","login":"centered","contentFrame":"contained"}', layout_policy_json='{"frontend.list":"frontend-list-card-v1","frontend.current_user_list":"frontend-current-user-card-v1","frontend.detail":"frontend-detail-media-v1","frontend.form":"frontend-form-group-v1","admin.list":"admin-list-v1"}', asset_policy_json='{"iconStyle":"outline","illustrationStyle":"editorial","chartPalette":["#7c3aed","#db2777","#a78bfa","#2563eb","#f59e0b"]}' where theme_code='elegant-purple';
|
||
update sys_page_theme set shell_json='{"frontendNavigation":"top","adminNavigation":"top","header":"hidden","login":"centered","contentFrame":"narrow"}', layout_policy_json='{"frontend.list":"frontend-list-v1","frontend.current_user_list":"frontend-current-user-list-v1","frontend.detail":"frontend-detail-v1","frontend.form":"frontend-form-v1","admin.list":"admin-list-v1"}', asset_policy_json='{"iconStyle":"minimal","illustrationStyle":"none","chartPalette":["#111827","#4b5563","#9ca3af","#d1d5db","#6b7280"]}' where theme_code='minimal-white';
|
||
|
||
insert into sys_page_layout_template
|
||
(layout_code,layout_name,description,page_type,page_scope,framework,render_template_key,config_json,compatibility_json,version,weight,status,sort_order,create_by,create_time) values
|
||
('frontend-list-v1','标准表格','查询、工具栏、表格与弹窗','list','frontend','vue2-element-ui','qing/frontend-index','{}','{}',1,4,'0',10,'system',sysdate()),
|
||
('frontend-list-card-v1','卡片列表','适合商品、内容与活动','list','frontend','vue2-element-ui','qing/frontend-index','{}','{"imagePreferred":true}',1,3,'0',20,'system',sysdate()),
|
||
('frontend-list-split-v1','分栏列表','左侧分类,右侧数据','list','frontend','vue2-element-ui','qing/frontend-index','{}','{"categoryPreferred":true}',1,2,'0',30,'system',sysdate()),
|
||
('frontend-current-user-list-v1','我的列表','当前用户记录表格','current_user_list','frontend','vue2-element-ui','qing/frontend-index','{}','{}',1,3,'0',40,'system',sysdate()),
|
||
('frontend-current-user-card-v1','我的卡片','当前用户记录卡片','current_user_list','frontend','vue2-element-ui','qing/frontend-index','{}','{}',1,3,'0',50,'system',sysdate()),
|
||
('frontend-detail-v1','基础详情','普通记录详情','detail','frontend','vue2-element-ui','qing/frontend-index','{}','{}',1,3,'0',60,'system',sysdate()),
|
||
('frontend-detail-media-v1','图文详情','突出主图和内容','detail','frontend','vue2-element-ui','qing/frontend-index','{}','{"imagePreferred":true}',1,3,'0',70,'system',sysdate()),
|
||
('frontend-form-v1','单页表单','轻量录入表单','form','frontend','vue2-element-ui','qing/frontend-index','{}','{}',1,3,'0',80,'system',sysdate()),
|
||
('frontend-form-group-v1','分组表单','字段较多的录入页','form','frontend','vue2-element-ui','qing/frontend-index','{}','{"minFormFields":8}',1,3,'0',90,'system',sysdate()),
|
||
('admin-list-v1','标准管理表格','后台 CRUD 管理','list','admin','vue2-element-ui','qing/admin-index','{}','{}',1,4,'0',100,'system',sysdate()),
|
||
('admin-list-dense-v1','高密度表格','运营高频维护','list','admin','vue2-element-ui','qing/admin-index','{}','{"minListFields":10}',1,2,'0',110,'system',sysdate()),
|
||
('admin-list-split-v1','分栏管理','分类层级明显的后台页','list','admin','vue2-element-ui','qing/admin-index','{}','{"categoryPreferred":true}',1,2,'0',120,'system',sysdate()),
|
||
('admin-detail-v1','后台详情','审核与查看记录','detail','admin','vue2-element-ui','qing/admin-index','{}','{}',1,3,'0',130,'system',sysdate()),
|
||
('admin-form-v1','后台表单','后台新增与编辑','form','admin','vue2-element-ui','qing/admin-index','{}','{}',1,3,'0',140,'system',sysdate()),
|
||
('admin-form-group-v1','后台分组表单','字段较多的后台录入','form','admin','vue2-element-ui','qing/admin-index','{}','{"minFormFields":8}',1,3,'0',150,'system',sysdate()),
|
||
('business-blocks-v1','业务块页面','统计、图表与业务组件组合','business_block','all','vue2-element-ui','qing/business-blocks','{}','{}',1,1,'0',160,'system',sysdate()),
|
||
('menu-directory-v1','菜单目录','仅作为导航分组','menu_directory','all','vue2-element-ui','qing/menu-directory','{}','{}',1,1,'0',170,'system',sysdate());
|
||
|
||
-- ----------------------------
|
||
-- 5、代码模板文件表
|
||
-- ----------------------------
|
||
drop table if exists sys_template_file;
|
||
create table sys_template_file (
|
||
template_file_id bigint(20) not null auto_increment comment '模板文件ID',
|
||
template_id bigint(20) not null comment '模板ID',
|
||
file_name varchar(255) not null comment '文件名称',
|
||
module_id bigint(20) default null comment '功能模块ID',
|
||
file_path varchar(500) default '' comment '文件路径',
|
||
file_content longtext comment '文件内容',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
primary key (template_file_id),
|
||
key idx_template_file_template_id (template_id),
|
||
key idx_template_file_module_id (module_id),
|
||
constraint fk_template_file_template foreign key (template_id) references sys_template(template_id),
|
||
constraint fk_template_file_module foreign key (module_id) references sys_module(module_id)
|
||
) engine=innodb auto_increment=100 comment = '代码模板文件表';
|
||
|
||
-- ----------------------------
|
||
-- 5.1、代码模板骨架制品表
|
||
-- ----------------------------
|
||
create table sys_template_artifact (
|
||
artifact_id bigint(20) not null auto_increment comment '模板制品ID',
|
||
template_id bigint(20) not null comment '模板ID',
|
||
artifact_type varchar(32) not null comment '制品类型(skeleton)',
|
||
file_name varchar(255) not null comment '制品文件名',
|
||
artifact_content longblob comment '制品内容',
|
||
file_hash varchar(64) default null comment 'SHA-256',
|
||
file_size bigint(20) default 0 comment '文件大小',
|
||
file_manifest longtext comment '文件清单',
|
||
variable_metadata longtext comment '安全变量替换元数据',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
primary key (artifact_id),
|
||
unique key uk_template_artifact_type (template_id, artifact_type),
|
||
constraint fk_template_artifact_template foreign key (template_id)
|
||
references sys_template(template_id) on delete cascade
|
||
) engine=innodb auto_increment=100 comment = '代码模板骨架制品表';
|
||
|
||
-- ----------------------------
|
||
-- 6、代码片段管理表
|
||
-- ----------------------------
|
||
drop table if exists sys_code_snippet;
|
||
create table sys_code_snippet (
|
||
snippet_id bigint(20) not null auto_increment comment '代码片段ID',
|
||
module_id bigint(20) default null comment '功能模块ID',
|
||
snippet_content text not null comment '代码片段内容',
|
||
insert_point varchar(255) default '' comment '插入点',
|
||
param1 varchar(255) default null comment '参数1',
|
||
param2 varchar(255) default null comment '参数2',
|
||
param3 varchar(255) default null comment '参数3',
|
||
param4 varchar(255) default null comment '参数4',
|
||
param5 varchar(255) default null comment '参数5',
|
||
template_file_name varchar(255) default '' comment '模板文件名称',
|
||
relation_table_name varchar(255) default '' comment '关联表名称',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (snippet_id),
|
||
key idx_code_snippet_module_id (module_id),
|
||
constraint fk_code_snippet_module foreign key (module_id) references sys_module(module_id)
|
||
) engine=innodb auto_increment=100 comment = '代码片段管理表';
|
||
|
||
-- ----------------------------
|
||
-- 7、代码片段与功能模块关系表
|
||
-- ----------------------------
|
||
drop table if exists sys_code_snippet_module;
|
||
create table sys_code_snippet_module (
|
||
snippet_id bigint(20) not null comment '代码片段ID',
|
||
module_id bigint(20) not null comment '功能模块ID',
|
||
primary key (snippet_id, module_id),
|
||
key idx_snippet_module_module_id (module_id),
|
||
constraint fk_snippet_module_snippet foreign key (snippet_id) references sys_code_snippet(snippet_id),
|
||
constraint fk_snippet_module_module foreign key (module_id) references sys_module(module_id)
|
||
) engine=innodb comment = '代码片段与功能模块关系表';
|
||
|
||
-- ----------------------------
|
||
-- 8、项目与功能模块关系表
|
||
-- ----------------------------
|
||
drop table if exists sys_project_module;
|
||
create table sys_project_module (
|
||
id bigint(20) not null auto_increment comment 'ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
module_id bigint(20) not null comment '功能模块ID',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (id),
|
||
unique key idx_project_module (project_id, module_id),
|
||
key idx_project_module_module_id (module_id),
|
||
constraint fk_project_module_project foreign key (project_id) references gen_project(project_id),
|
||
constraint fk_project_module_module foreign key (module_id) references sys_module(module_id)
|
||
) engine=innodb auto_increment=100 comment = '项目与功能模块关系表';
|
||
|
||
-- ----------------------------
|
||
-- 9、项目与生成表关系表
|
||
-- ----------------------------
|
||
drop table if exists sys_project_table;
|
||
create table sys_project_table (
|
||
id bigint(20) not null auto_increment comment 'ID',
|
||
table_id bigint(20) not null comment '表ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
primary key (id),
|
||
unique key idx_project_table (project_id, table_id),
|
||
key idx_project_table_table_id (table_id),
|
||
constraint fk_project_table_project foreign key (project_id) references gen_project(project_id),
|
||
constraint fk_project_table_table foreign key (table_id) references gen_table(table_id)
|
||
) engine=innodb auto_increment=100 comment = '项目与生成表关系表';
|
||
|
||
-- 清理旧版重复关系表;当前源码只使用 sys_project_table
|
||
drop table if exists gen_table_project_rel;
|
||
|
||
-- ----------------------------
|
||
-- 10、项目模板配置表
|
||
-- ----------------------------
|
||
drop table if exists sys_project_template;
|
||
create table sys_project_template (
|
||
id bigint(20) not null auto_increment comment 'ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
template_id bigint(20) not null comment '模板ID',
|
||
template_type varchar(50) default '' comment '模板类型',
|
||
primary key (id),
|
||
unique key idx_project_template_type (project_id, template_type),
|
||
key idx_project_template_template_id (template_id),
|
||
constraint fk_project_template_project foreign key (project_id) references gen_project(project_id),
|
||
constraint fk_project_template_template foreign key (template_id) references sys_template(template_id)
|
||
) engine=innodb auto_increment=100 comment = '项目模板配置表';
|
||
|
||
-- ----------------------------
|
||
-- 11、项目结构节点表
|
||
-- ----------------------------
|
||
drop table if exists sys_project_structure;
|
||
create table sys_project_structure (
|
||
node_id bigint(20) not null auto_increment comment '节点ID',
|
||
parent_id bigint(20) default 0 comment '父节点ID',
|
||
node_name varchar(50) not null comment '节点名称',
|
||
node_type varchar(20) not null comment '节点类型(folder/file)',
|
||
module varchar(100) default '' comment '功能模块',
|
||
template_id bigint(20) default null comment '模板ID',
|
||
table_id bigint(20) default null comment '关联表ID',
|
||
category varchar(50) default null comment '文件类别',
|
||
sort_order int(4) default 0 comment '显示顺序',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime comment '更新时间',
|
||
primary key (node_id),
|
||
key idx_project_structure_parent_id (parent_id),
|
||
key idx_project_structure_template_id (template_id),
|
||
key idx_project_structure_table_id (table_id)
|
||
) engine=innodb auto_increment=100 comment = '项目结构节点表';
|
||
|
||
insert into sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) values
|
||
(1, 0, '项目根目录', 'folder', '根模块', null, null, null, 1, '0', 'admin', sysdate(), '', null),
|
||
(2, 1, 'src', 'folder', '源码', null, null, null, 1, '0', 'admin', sysdate(), '', null),
|
||
(3, 2, 'main', 'folder', '主目录', null, null, null, 1, '0', 'admin', sysdate(), '', null),
|
||
(4, 3, 'java', 'folder', '源代码', null, null, null, 1, '0', 'admin', sysdate(), '', null),
|
||
(5, 3, 'resources', 'folder', '资源', null, null, null, 2, '0', 'admin', sysdate(), '', null),
|
||
(6, 1, 'pom.xml', 'file', '依赖管理', null, null, 'xml', 2, '0', 'admin', sysdate(), '', null),
|
||
(7, 1, 'README.md', 'file', '说明文档', null, null, 'markdown', 3, '0', 'admin', sysdate(), '', null);
|
||
|
||
-- =================================================
|
||
-- EasyCode front workbench tables
|
||
-- Import after sql/db.sql, or use the copy appended to sql/db.sql
|
||
-- =================================================
|
||
|
||
drop table if exists front_project_file;
|
||
drop table if exists front_project_paper;
|
||
drop table if exists front_project_diagram;
|
||
drop table if exists front_ai_usage_ledger;
|
||
drop table if exists factory_ai_task_checkpoint;
|
||
drop table if exists factory_ai_task_stage;
|
||
drop table if exists front_ai_generation_task;
|
||
drop table if exists front_ai_quota_bucket;
|
||
drop table if exists factory_ai_stage_output;
|
||
drop table if exists front_project_generation;
|
||
drop table if exists front_project_column;
|
||
drop table if exists front_project_table;
|
||
drop table if exists front_project_page_design;
|
||
drop table if exists front_project_module;
|
||
drop table if exists factory_project_v1_acceptance_check;
|
||
drop table if exists factory_project_v1_acceptance_run;
|
||
drop table if exists factory_project_preview_job;
|
||
drop table if exists factory_project_certified_artifact;
|
||
drop table if exists factory_project_quality_check;
|
||
drop table if exists factory_project_quality_run;
|
||
drop table if exists factory_generation_file;
|
||
drop table if exists factory_generation_target;
|
||
drop table if exists factory_generation_run;
|
||
drop table if exists factory_project_spec_version;
|
||
drop table if exists factory_plugin_transition_outbox;
|
||
drop table if exists factory_plugin_transition_step_receipt;
|
||
drop table if exists factory_plugin_transition_execution;
|
||
drop table if exists factory_plugin_transition;
|
||
drop table if exists factory_plugin_version;
|
||
drop table if exists factory_plugin;
|
||
drop table if exists factory_prompt_debug_run;
|
||
drop table if exists factory_prompt_experiment;
|
||
drop table if exists factory_prompt_version;
|
||
drop table if exists factory_prompt_template;
|
||
drop table if exists front_project;
|
||
drop table if exists front_user;
|
||
|
||
create table factory_prompt_template (
|
||
prompt_template_id bigint(20) not null auto_increment comment 'Prompt template ID',
|
||
prompt_code varchar(100) not null comment 'Stable Prompt code',
|
||
prompt_name varchar(100) not null comment 'Prompt name',
|
||
generate_type varchar(50) not null comment 'AI generation type',
|
||
description varchar(500) default '' comment 'Prompt purpose',
|
||
status char(1) not null default '0' comment '0 enabled, 1 disabled',
|
||
current_version_id bigint(20) default null comment 'Current published version ID',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
update_by varchar(64) default '' comment 'Updater',
|
||
update_time datetime not null comment 'Update time',
|
||
remark varchar(500) default '' comment 'Remark',
|
||
primary key (prompt_template_id),
|
||
unique key uk_factory_prompt_code (prompt_code),
|
||
unique key uk_factory_prompt_generate_type (generate_type),
|
||
key idx_factory_prompt_current_version (current_version_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Prompt template registry';
|
||
|
||
create table factory_prompt_version (
|
||
prompt_version_id bigint(20) not null auto_increment comment 'Prompt version ID',
|
||
prompt_template_id bigint(20) not null comment 'Prompt template ID',
|
||
version_no int not null comment 'Monotonic version number',
|
||
version_label varchar(50) not null comment 'Published version label',
|
||
system_prompt longtext not null comment 'System Prompt content',
|
||
user_prompt_contract varchar(255) not null comment 'User Prompt builder/template contract',
|
||
user_prompt_template longtext null comment 'Editable User Prompt template using {{input}}',
|
||
provider_code varchar(50) not null comment 'Model provider code',
|
||
model varchar(100) default '' comment 'Pinned model or empty for gateway default',
|
||
content_hash char(64) not null comment 'Canonical Prompt SHA-256',
|
||
status varchar(20) not null default 'DRAFT' comment 'DRAFT, PUBLISHED, RETIRED',
|
||
parent_version_id bigint(20) default null comment 'Parent Prompt version ID',
|
||
pipeline_release_code varchar(100) default null comment 'Atomic compatible pipeline release code',
|
||
published_by varchar(64) default '' comment 'Publisher',
|
||
published_at datetime default null comment 'Publish time',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
remark varchar(500) default '' comment 'Change summary',
|
||
primary key (prompt_version_id),
|
||
unique key uk_factory_prompt_version_no (prompt_template_id, version_no),
|
||
unique key uk_factory_prompt_version_label (prompt_template_id, version_label),
|
||
key idx_factory_prompt_version_status (prompt_template_id, status),
|
||
key idx_factory_prompt_parent_version (parent_version_id),
|
||
constraint fk_factory_prompt_version_template foreign key (prompt_template_id)
|
||
references factory_prompt_template(prompt_template_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable Prompt content versions';
|
||
|
||
create table factory_prompt_experiment (
|
||
experiment_id bigint(20) not null auto_increment comment 'Experiment ID',
|
||
prompt_template_id bigint(20) not null comment 'Prompt template ID',
|
||
experiment_name varchar(100) not null comment 'Experiment name',
|
||
version_a_id bigint(20) not null comment 'Variant A Prompt version ID',
|
||
version_b_id bigint(20) not null comment 'Variant B Prompt version ID',
|
||
traffic_a int not null default 50 comment 'Variant A traffic percent',
|
||
traffic_b int not null default 50 comment 'Variant B traffic percent',
|
||
status varchar(20) not null default 'DRAFT' comment 'DRAFT, RUNNING, PAUSED, COMPLETED',
|
||
started_at datetime default null comment 'First start time',
|
||
ended_at datetime default null comment 'Completion time',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
update_by varchar(64) default '' comment 'Updater',
|
||
update_time datetime not null comment 'Update time',
|
||
remark varchar(500) default '' comment 'Experiment hypothesis',
|
||
primary key (experiment_id),
|
||
key idx_prompt_experiment_template (prompt_template_id, status),
|
||
key idx_prompt_experiment_version_a (version_a_id),
|
||
key idx_prompt_experiment_version_b (version_b_id),
|
||
constraint fk_prompt_experiment_template foreign key (prompt_template_id)
|
||
references factory_prompt_template(prompt_template_id) on delete cascade,
|
||
constraint fk_prompt_experiment_version_a foreign key (version_a_id)
|
||
references factory_prompt_version(prompt_version_id),
|
||
constraint fk_prompt_experiment_version_b foreign key (version_b_id)
|
||
references factory_prompt_version(prompt_version_id),
|
||
constraint chk_prompt_experiment_traffic check (traffic_a >= 0 and traffic_b >= 0 and traffic_a + traffic_b = 100),
|
||
constraint chk_prompt_experiment_versions check (version_a_id <> version_b_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Prompt A/B experiments';
|
||
|
||
create table factory_prompt_debug_run (
|
||
run_id bigint(20) not null auto_increment comment 'Debug run ID',
|
||
prompt_template_id bigint(20) not null comment 'Prompt template ID',
|
||
prompt_version_id bigint(20) not null comment 'Prompt version ID',
|
||
experiment_id bigint(20) default null comment 'A/B experiment ID',
|
||
variant varchar(20) not null default 'DEBUG' comment 'DEBUG, A, B',
|
||
provider_code varchar(50) not null comment 'Invoked provider',
|
||
model varchar(100) not null comment 'Invoked model',
|
||
user_prompt longtext not null comment 'Debug input',
|
||
output_content longtext default null comment 'Model output',
|
||
duration_ms bigint(20) not null default 0 comment 'Invocation duration in milliseconds',
|
||
success char(1) not null default '1' comment '1 success, 0 failed',
|
||
error_message varchar(1000) default null comment 'Sanitized error',
|
||
score int default null comment 'Manual quality score 1-5',
|
||
feedback varchar(1000) default '' comment 'Manual evaluation note',
|
||
create_by varchar(64) default '' comment 'Operator',
|
||
create_time datetime not null comment 'Create time',
|
||
update_by varchar(64) default '' comment 'Evaluator',
|
||
update_time datetime default null comment 'Evaluation time',
|
||
primary key (run_id),
|
||
key idx_prompt_debug_template (prompt_template_id, create_time),
|
||
key idx_prompt_debug_experiment (experiment_id, variant),
|
||
key idx_prompt_debug_version (prompt_version_id),
|
||
constraint fk_prompt_debug_template foreign key (prompt_template_id)
|
||
references factory_prompt_template(prompt_template_id) on delete cascade,
|
||
constraint fk_prompt_debug_version foreign key (prompt_version_id)
|
||
references factory_prompt_version(prompt_version_id),
|
||
constraint fk_prompt_debug_experiment foreign key (experiment_id)
|
||
references factory_prompt_experiment(experiment_id) on delete set null,
|
||
constraint chk_prompt_debug_score check (score is null or (score between 1 and 5))
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Prompt online debug and A/B run history';
|
||
|
||
create table factory_plugin (
|
||
plugin_id bigint(20) not null auto_increment comment 'Feature Plugin ID',
|
||
plugin_code varchar(100) not null comment 'Stable Plugin code',
|
||
plugin_name varchar(100) not null comment 'Plugin name',
|
||
provider varchar(100) not null comment 'Trusted provider code',
|
||
description varchar(500) default '' comment 'Plugin purpose',
|
||
status char(1) not null default '0' comment '0 enabled, 1 disabled',
|
||
current_version_id bigint(20) default null comment 'Current published version ID',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
update_by varchar(64) default '' comment 'Updater',
|
||
update_time datetime not null comment 'Update time',
|
||
remark varchar(500) default '' comment 'Remark',
|
||
primary key (plugin_id),
|
||
unique key uk_factory_plugin_code (plugin_code),
|
||
key idx_factory_plugin_current_version (current_version_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Feature Plugin registry';
|
||
|
||
create table factory_plugin_version (
|
||
plugin_version_id bigint(20) not null auto_increment comment 'Plugin version ID',
|
||
plugin_id bigint(20) not null comment 'Feature Plugin ID',
|
||
version_no int not null comment 'Monotonic version number',
|
||
version_label varchar(50) not null comment 'Semantic release version',
|
||
manifest_schema_version varchar(20) not null comment 'Plugin manifest schema version',
|
||
manifest_json longtext not null comment 'Canonical immutable Plugin manifest',
|
||
content_hash char(64) not null comment 'Canonical manifest SHA-256',
|
||
status varchar(20) not null default 'DRAFT' comment 'DRAFT, PUBLISHED, RETIRED',
|
||
parent_version_id bigint(20) default null comment 'Parent Plugin version ID',
|
||
published_by varchar(64) default '' comment 'Publisher',
|
||
published_at datetime default null comment 'Publish time',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
remark varchar(500) default '' comment 'Change summary',
|
||
primary key (plugin_version_id),
|
||
unique key uk_factory_plugin_version_no (plugin_id, version_no),
|
||
unique key uk_factory_plugin_version_label (plugin_id, version_label),
|
||
key idx_factory_plugin_version_status (plugin_id, status),
|
||
key idx_factory_plugin_parent_version (parent_version_id),
|
||
constraint fk_factory_plugin_version_plugin foreign key (plugin_id)
|
||
references factory_plugin(plugin_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable Feature Plugin versions';
|
||
|
||
create table factory_plugin_transition (
|
||
transition_id bigint(20) not null auto_increment comment 'Plugin transition journal ID',
|
||
plugin_id bigint(20) not null comment 'Feature Plugin ID',
|
||
from_version_id bigint(20) default null comment 'Previous Plugin version ID',
|
||
to_version_id bigint(20) not null comment 'Target Plugin version ID',
|
||
operation varchar(20) not null comment 'PUBLISH, RESTORE, BOOTSTRAP, REPAIR',
|
||
transition_plan_json longtext not null comment 'Canonical immutable contribution transition plan',
|
||
transition_fingerprint char(64) not null comment 'Canonical transition plan SHA-256',
|
||
step_count int not null default 0 comment 'Artifact step count',
|
||
status varchar(20) not null default 'RECORDED' comment 'Append-only journal status',
|
||
operator varchar(64) default '' comment 'Transition operator',
|
||
create_time datetime not null comment 'Journal time',
|
||
primary key (transition_id),
|
||
key idx_factory_plugin_transition_time (plugin_id, create_time),
|
||
key idx_factory_plugin_transition_target (to_version_id),
|
||
constraint fk_factory_plugin_transition_plugin foreign key (plugin_id)
|
||
references factory_plugin(plugin_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable Feature Plugin transition journal';
|
||
|
||
create table if not exists factory_plugin_transition_approval (
|
||
approval_id bigint(20) not null auto_increment comment 'Transition approval ID',
|
||
transition_id bigint(20) not null comment 'Plugin transition journal ID',
|
||
execution_mode varchar(20) not null comment 'APPLY, RETRY, COMPENSATE',
|
||
transition_fingerprint char(64) not null comment 'Frozen Transition SHA-256',
|
||
routing_fingerprint char(64) not null comment 'Frozen executor routing SHA-256',
|
||
environment_code varchar(64) not null comment 'Frozen execution environment',
|
||
executor_code varchar(100) not null comment 'Frozen summary Executor code',
|
||
status varchar(20) not null comment 'PENDING, APPROVED, REVOKED, CONSUMED, EXPIRED',
|
||
requested_by varchar(64) not null comment 'Approval requester',
|
||
requester_roles varchar(1000) not null comment 'Frozen requester role keys',
|
||
request_reason varchar(500) not null comment 'Execution request reason',
|
||
requested_at datetime not null comment 'Request time',
|
||
request_expires_at datetime not null comment 'Pending request expiry',
|
||
approved_by varchar(64) default '' comment 'Distinct approval operator',
|
||
approver_roles varchar(1000) default '' comment 'Frozen approver role keys',
|
||
approved_at datetime default null comment 'Approval time',
|
||
approval_reason varchar(500) default '' comment 'Approval decision reason',
|
||
expires_at datetime default null comment 'Approved evidence expiry',
|
||
revoked_by varchar(64) default '' comment 'Revocation operator',
|
||
revoker_roles varchar(1000) default '' comment 'Frozen revoker role keys',
|
||
revoked_at datetime default null comment 'Revocation time',
|
||
revocation_reason varchar(500) default '' comment 'Revocation reason',
|
||
consumed_by varchar(64) default '' comment 'Execution operator consuming approval',
|
||
consumed_at datetime default null comment 'Approval consumption time',
|
||
execution_id bigint(20) default null comment 'Created execution batch ID',
|
||
create_time datetime not null comment 'Creation time',
|
||
update_time datetime not null comment 'Last lifecycle update',
|
||
primary key (approval_id),
|
||
unique key uk_factory_plugin_approval_execution (execution_id),
|
||
key idx_factory_plugin_approval_status (transition_id, status, approval_id),
|
||
key idx_factory_plugin_approval_expiry (status, request_expires_at, expires_at),
|
||
constraint fk_factory_plugin_approval_transition foreign key (transition_id)
|
||
references factory_plugin_transition(transition_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Plugin transition separation-of-duties approvals';
|
||
|
||
create table factory_plugin_transition_execution (
|
||
execution_id bigint(20) not null auto_increment comment 'Transition execution batch ID',
|
||
transition_id bigint(20) not null comment 'Plugin transition journal ID',
|
||
attempt_no int not null comment 'Monotonic execution attempt',
|
||
execution_mode varchar(20) not null comment 'APPLY, RETRY, COMPENSATE',
|
||
executor_code varchar(100) not null comment 'Configured target executor code',
|
||
environment_code varchar(64) not null default '' comment 'Frozen execution environment',
|
||
routing_fingerprint char(64) not null default '' comment 'Frozen executor routing SHA-256',
|
||
approval_required tinyint(1) not null default 0 comment 'Whether durable approval was required',
|
||
approval_id bigint(20) default null comment 'Consumed approval ID',
|
||
requested_by varchar(64) default '' comment 'Approval requester snapshot',
|
||
requester_roles varchar(1000) default '' comment 'Requester role snapshot',
|
||
request_reason varchar(500) default '' comment 'Execution request reason snapshot',
|
||
approved_by varchar(64) default '' comment 'Approval operator',
|
||
approver_roles varchar(1000) default '' comment 'Approver role snapshot',
|
||
approved_at datetime default null comment 'Approval time',
|
||
approval_reason varchar(500) default '' comment 'Approval reason',
|
||
approval_expires_at datetime default null comment 'Approval evidence expiry',
|
||
idempotency_key char(64) not null comment 'Execution idempotency SHA-256',
|
||
status varchar(20) not null comment 'QUEUED, RUNNING, SUCCEEDED, FAILED',
|
||
started_by varchar(64) default '' comment 'Execution operator',
|
||
started_at datetime default null comment 'Execution start time',
|
||
finished_at datetime default null comment 'Execution finish time',
|
||
duration_millis bigint(20) default null comment 'Execution duration',
|
||
error_message varchar(1000) default '' comment 'Sanitized execution error',
|
||
primary key (execution_id),
|
||
unique key uk_factory_plugin_execution_attempt (transition_id, attempt_no),
|
||
unique key uk_factory_plugin_execution_idempotency (idempotency_key),
|
||
key idx_factory_plugin_execution_approval (approval_id),
|
||
key idx_factory_plugin_execution_status (transition_id, status),
|
||
constraint fk_factory_plugin_execution_transition foreign key (transition_id)
|
||
references factory_plugin_transition(transition_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Plugin transition execution batches';
|
||
|
||
create table factory_plugin_transition_step_receipt (
|
||
receipt_id bigint(20) not null auto_increment comment 'Step execution receipt ID',
|
||
execution_id bigint(20) not null comment 'Transition execution batch ID',
|
||
step_sequence int not null comment 'Execution order in this batch',
|
||
plan_step_sequence int not null comment 'Source Transition Plan step',
|
||
direction varchar(20) not null comment 'APPLY or ROLLBACK',
|
||
contribution_type varchar(40) not null comment 'Contribution type',
|
||
contribution_key varchar(255) not null comment 'Contribution identity key',
|
||
target varchar(40) not null comment 'Target archive or environment',
|
||
artifact_path varchar(1024) not null comment 'Verified contribution artifact path',
|
||
content_hash char(64) not null comment 'Verified contribution content SHA-256',
|
||
step_idempotency_key char(64) not null comment 'Stable logical step idempotency SHA-256',
|
||
executor_code varchar(100) not null comment 'Target executor code',
|
||
status varchar(20) not null comment 'PENDING, RUNNING, SUCCEEDED, FAILED',
|
||
external_receipt varchar(1000) default '' comment 'Executor receipt identity',
|
||
error_message varchar(1000) default '' comment 'Sanitized step error',
|
||
started_at datetime default null comment 'Step start time',
|
||
finished_at datetime default null comment 'Step finish time',
|
||
duration_millis bigint(20) default null comment 'Step duration',
|
||
primary key (receipt_id),
|
||
unique key uk_factory_plugin_receipt_step (execution_id, step_sequence),
|
||
key idx_factory_plugin_receipt_status (execution_id, status),
|
||
key idx_factory_plugin_receipt_idempotency (step_idempotency_key),
|
||
constraint fk_factory_plugin_receipt_execution foreign key (execution_id)
|
||
references factory_plugin_transition_execution(execution_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Plugin transition step execution receipts';
|
||
|
||
create table factory_plugin_transition_outbox (
|
||
outbox_id bigint(20) not null auto_increment comment 'Durable execution command ID',
|
||
execution_id bigint(20) not null comment 'Transition execution batch ID',
|
||
status varchar(20) not null comment 'PENDING, PROCESSING, DELIVERED, FAILED',
|
||
available_at datetime not null comment 'Earliest claim time',
|
||
lease_owner varchar(128) default '' comment 'Current Worker identity',
|
||
lease_token varchar(64) default '' comment 'Current claim token',
|
||
lease_until datetime default null comment 'Claim expiry time',
|
||
delivery_count int not null default 0 comment 'Successful claim count',
|
||
last_error varchar(1000) default '' comment 'Last delivery error',
|
||
created_at datetime not null comment 'Outbox creation time',
|
||
updated_at datetime not null comment 'Outbox update time',
|
||
delivered_at datetime default null comment 'Terminal delivery time',
|
||
primary key (outbox_id),
|
||
unique key uk_factory_plugin_outbox_execution (execution_id),
|
||
key idx_factory_plugin_outbox_claim (status, available_at, lease_until),
|
||
constraint fk_factory_plugin_outbox_execution foreign key (execution_id)
|
||
references factory_plugin_transition_execution(execution_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Durable Plugin transition execution Outbox';
|
||
|
||
create table factory_plugin_delivery_rehearsal_run (
|
||
rehearsal_id bigint(20) not null auto_increment comment 'Delivery rehearsal run ID',
|
||
run_key char(64) not null comment 'Unique rehearsal identity SHA-256',
|
||
schema_version varchar(20) not null comment 'Rehearsal snapshot schema version',
|
||
rehearsal_mode varchar(20) not null comment 'PLAN_ONLY until an isolated target is explicitly authorized',
|
||
status varchar(20) not null comment 'READY or BLOCKED by acceptance snapshot',
|
||
execution_environment_code varchar(64) default '' comment 'Frozen control-plane environment',
|
||
target_environment_code varchar(64) default '' comment 'Frozen JDBC target environment',
|
||
target_catalog varchar(128) default '' comment 'Non-secret target catalog identity',
|
||
routing_fingerprint char(64) not null comment 'Frozen executor routing SHA-256',
|
||
acceptance_fingerprint char(64) not null comment 'Acceptance snapshot SHA-256',
|
||
scenario_fingerprint char(64) not null comment 'Ordered scenario report SHA-256',
|
||
acceptance_snapshot_json longtext not null comment 'Canonical non-secret acceptance snapshot',
|
||
check_count int not null default 0 comment 'Frozen acceptance check count',
|
||
passed_check_count int not null default 0 comment 'Frozen passed check count',
|
||
scenario_count int not null default 0 comment 'Frozen rehearsal scenario count',
|
||
created_by varchar(64) not null comment 'Authenticated planner account',
|
||
create_time datetime not null comment 'Snapshot creation time',
|
||
primary key (rehearsal_id),
|
||
unique key uk_factory_plugin_rehearsal_run_key (run_key),
|
||
key idx_factory_plugin_rehearsal_created (status, create_time)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Append-only Plugin delivery rehearsal runs';
|
||
|
||
create table factory_plugin_delivery_rehearsal_scenario (
|
||
scenario_id bigint(20) not null auto_increment comment 'Rehearsal scenario ID',
|
||
rehearsal_id bigint(20) not null comment 'Delivery rehearsal run ID',
|
||
scenario_sequence int not null comment 'Stable scenario order',
|
||
scenario_code varchar(64) not null comment 'Stable scenario code',
|
||
scenario_name varchar(100) not null comment 'Scenario display name',
|
||
state varchar(20) not null comment 'PLANNED or BLOCKED',
|
||
required_evidence varchar(1000) not null comment 'Evidence required for completion',
|
||
message varchar(1000) not null comment 'Planning result',
|
||
primary key (scenario_id),
|
||
unique key uk_factory_plugin_rehearsal_scenario (rehearsal_id, scenario_code),
|
||
unique key uk_factory_plugin_rehearsal_sequence (rehearsal_id, scenario_sequence),
|
||
constraint fk_factory_plugin_rehearsal_scenario_run foreign key (rehearsal_id)
|
||
references factory_plugin_delivery_rehearsal_run(rehearsal_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable Plugin delivery rehearsal scenario report';
|
||
|
||
create table factory_plugin_delivery_rehearsal_attempt (
|
||
attempt_id bigint(20) not null auto_increment comment 'Local rehearsal attempt ID',
|
||
rehearsal_id bigint(20) not null comment 'Delivery rehearsal run ID',
|
||
retry_of_attempt_id bigint(20) default null comment 'Terminal attempt replayed from scratch',
|
||
attempt_no int not null comment 'Monotonic attempt number within Run',
|
||
attempt_key char(64) not null comment 'Unique attempt identity SHA-256',
|
||
execution_mode varchar(20) not null comment 'LOCAL_H2 only',
|
||
status varchar(20) not null comment 'PENDING, RUNNING, SUCCEEDED, FAILED, ABORTED',
|
||
run_key char(64) not null comment 'Frozen parent Run identity',
|
||
acceptance_fingerprint char(64) not null comment 'Frozen acceptance snapshot SHA-256',
|
||
scenario_fingerprint char(64) not null comment 'Frozen scenario plan SHA-256',
|
||
sandbox_fingerprint char(64) not null comment 'Ephemeral local sandbox identity',
|
||
receipt_count int not null default 0 comment 'Expected scenario receipt count',
|
||
succeeded_receipt_count int not null default 0 comment 'Completed scenario receipt count',
|
||
started_by varchar(64) not null comment 'Authenticated rehearsal operator',
|
||
create_time datetime not null comment 'Attempt creation time',
|
||
started_at datetime default null comment 'Attempt start time',
|
||
finished_at datetime default null comment 'Attempt terminal time',
|
||
duration_millis bigint(20) default null comment 'Attempt duration',
|
||
error_message varchar(1000) default '' comment 'Sanitized terminal error',
|
||
primary key (attempt_id),
|
||
unique key uk_factory_plugin_rehearsal_attempt_key (attempt_key),
|
||
unique key uk_factory_plugin_rehearsal_attempt_no (rehearsal_id, attempt_no),
|
||
key idx_factory_plugin_rehearsal_attempt_status (rehearsal_id, status, attempt_id),
|
||
key idx_factory_plugin_rehearsal_retry (retry_of_attempt_id),
|
||
constraint fk_factory_plugin_rehearsal_attempt_run foreign key (rehearsal_id)
|
||
references factory_plugin_delivery_rehearsal_run(rehearsal_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Local H2 Plugin delivery rehearsal attempts';
|
||
|
||
create table factory_plugin_delivery_rehearsal_receipt (
|
||
receipt_id bigint(20) not null auto_increment comment 'Scenario execution receipt ID',
|
||
attempt_id bigint(20) not null comment 'Local rehearsal attempt ID',
|
||
scenario_id bigint(20) not null comment 'Frozen rehearsal scenario ID',
|
||
scenario_sequence int not null comment 'Stable scenario order',
|
||
scenario_code varchar(64) not null comment 'Stable scenario code',
|
||
scenario_name varchar(100) not null comment 'Frozen scenario display name',
|
||
status varchar(20) not null comment 'PENDING, RUNNING, SUCCEEDED, FAILED, ABORTED',
|
||
evidence_json longtext default null comment 'Canonical non-secret scenario evidence',
|
||
evidence_fingerprint char(64) default '' comment 'Scenario evidence SHA-256',
|
||
message varchar(1000) default '' comment 'Sanitized scenario result',
|
||
started_at datetime default null comment 'Scenario start time',
|
||
finished_at datetime default null comment 'Scenario terminal time',
|
||
duration_millis bigint(20) default null comment 'Scenario duration',
|
||
primary key (receipt_id),
|
||
unique key uk_factory_plugin_rehearsal_receipt_code (attempt_id, scenario_code),
|
||
unique key uk_factory_plugin_rehearsal_receipt_sequence (attempt_id, scenario_sequence),
|
||
key idx_factory_plugin_rehearsal_receipt_status (attempt_id, status),
|
||
constraint fk_factory_plugin_rehearsal_receipt_attempt foreign key (attempt_id)
|
||
references factory_plugin_delivery_rehearsal_attempt(attempt_id) on delete cascade,
|
||
constraint fk_factory_plugin_rehearsal_receipt_scenario foreign key (scenario_id)
|
||
references factory_plugin_delivery_rehearsal_scenario(scenario_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Verified local rehearsal scenario receipts';
|
||
|
||
create table factory_plugin_delivery_rehearsal_outbox (
|
||
outbox_id bigint(20) not null auto_increment comment 'Durable rehearsal command ID',
|
||
attempt_id bigint(20) not null comment 'Local rehearsal attempt ID',
|
||
status varchar(20) not null comment 'PENDING, PROCESSING, DELIVERED, FAILED, ABORTED',
|
||
available_at datetime not null comment 'Earliest claim time',
|
||
lease_owner varchar(128) default '' comment 'Current worker identity',
|
||
lease_token varchar(64) default '' comment 'Private fencing token',
|
||
lease_until datetime default null comment 'Lease expiry time',
|
||
last_heartbeat_at datetime default null comment 'Last successful lease heartbeat',
|
||
delivery_count int not null default 0 comment 'Claim and takeover count',
|
||
last_error varchar(1000) default '' comment 'Sanitized delivery error',
|
||
create_time datetime not null comment 'Command creation time',
|
||
delivered_at datetime default null comment 'Terminal delivery time',
|
||
primary key (outbox_id),
|
||
unique key uk_factory_plugin_rehearsal_outbox_attempt (attempt_id),
|
||
key idx_factory_plugin_rehearsal_outbox_claim (status, available_at, lease_until),
|
||
constraint fk_factory_plugin_rehearsal_outbox_attempt foreign key (attempt_id)
|
||
references factory_plugin_delivery_rehearsal_attempt(attempt_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Durable local rehearsal Outbox commands';
|
||
|
||
create table front_user (
|
||
user_id bigint(20) not null auto_increment comment '前台用户ID',
|
||
username varchar(50) not null comment '用户名',
|
||
password varchar(100) not null comment '密码',
|
||
nickname varchar(50) default '' comment '昵称',
|
||
email varchar(100) default '' comment '邮箱',
|
||
phone varchar(20) default '' comment '手机号',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
del_flag char(1) default '0' comment '删除标志(0存在 2删除)',
|
||
last_login_time datetime default null comment '最后登录时间',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (user_id),
|
||
unique key uk_front_user_username (username),
|
||
key idx_front_user_email (email),
|
||
key idx_front_user_phone (phone)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台用户表';
|
||
|
||
create table front_project (
|
||
project_id bigint(20) not null auto_increment comment '前台项目ID',
|
||
user_id bigint(20) not null comment '前台用户ID',
|
||
project_name varchar(100) not null comment '项目名称',
|
||
project_file_name varchar(100) default '' comment '项目文件名',
|
||
package_name varchar(100) default 'com.easycode.generated' comment '包名',
|
||
version varchar(20) default '1.0.0' comment '版本号',
|
||
project_desc longtext comment '项目描述',
|
||
requirement_keyword varchar(1000) default '' comment '需求关键词',
|
||
industry_template varchar(50) default '' comment '行业模板',
|
||
style_preset varchar(50) default 'business_clean' comment '页面风格预设',
|
||
code_template varchar(64) default 'qing' comment 'code template bundle',
|
||
front_framework varchar(50) default 'Vue3 + Element Plus' comment '前台框架',
|
||
back_framework varchar(50) default 'Spring Boot + MyBatis' comment '后端框架',
|
||
frontend_enabled char(1) default '1' comment '是否生成前台前端(1是 0否)',
|
||
generate_status char(1) default '0' comment '数据库生成状态(0未生成 1生成中 2已生成 3失败)',
|
||
preview_status char(1) default '0' comment '预览状态(0未预览 1已预览 2失败)',
|
||
draft_revision bigint(20) not null default 0 comment '项目草稿乐观锁版本',
|
||
app_blueprint longtext comment '系统模块设计草稿JSON',
|
||
flow_config longtext comment '业务闭环唯一配置JSON(状态、动作、多表联动、按钮和统计)',
|
||
er_diagram longtext comment 'ER图草稿JSON',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (project_id),
|
||
key idx_front_project_user_id (user_id),
|
||
constraint fk_front_project_user foreign key (user_id) references front_user(user_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目草稿表';
|
||
|
||
create table factory_project_spec_version (
|
||
spec_version_id bigint(20) not null auto_increment comment 'ProjectSpec version ID',
|
||
project_id bigint(20) not null comment 'Front project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
version_no int not null comment 'Monotonic project version number',
|
||
parent_version_id bigint(20) default null comment 'Parent ProjectSpec version ID',
|
||
schema_version varchar(20) not null comment 'ProjectSpec schema version',
|
||
content_json longtext not null comment 'Canonical ProjectSpec JSON',
|
||
content_hash char(64) not null comment 'SHA-256 of canonical JSON',
|
||
change_source varchar(30) not null comment 'Version change source',
|
||
change_summary varchar(500) default '' comment 'Version change summary',
|
||
status char(1) not null default '0' comment 'Status: 0 active',
|
||
create_by varchar(64) default '' comment 'Creator',
|
||
create_time datetime not null comment 'Create time',
|
||
primary key (spec_version_id),
|
||
unique key uk_factory_spec_project_version (project_id, version_no),
|
||
key idx_factory_spec_user_project (user_id, project_id),
|
||
key idx_factory_spec_project_hash (project_id, content_hash),
|
||
key idx_factory_spec_parent (parent_version_id),
|
||
constraint fk_factory_spec_project foreign key (project_id)
|
||
references front_project(project_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable ProjectSpec version history';
|
||
|
||
create table factory_generation_run (
|
||
generation_run_id bigint(20) not null auto_increment comment 'Generation run ID',
|
||
project_id bigint(20) not null comment 'Front project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
spec_version_id bigint(20) not null comment 'ProjectSpec version ID',
|
||
spec_version_no int not null comment 'ProjectSpec version number at generation',
|
||
spec_content_hash char(64) not null comment 'ProjectSpec SHA-256',
|
||
adapter_code varchar(100) not null comment 'Generation adapter code',
|
||
adapter_version varchar(100) not null comment 'Generation adapter contract version',
|
||
adapter_fingerprint char(64) not null comment 'Adapter descriptor SHA-256',
|
||
adapter_capability_fingerprint char(64) not null comment 'Adapter capability descriptor SHA-256',
|
||
adapter_capabilities_json longtext not null comment 'Canonical adapter capability snapshot',
|
||
plugin_fingerprint char(64) not null comment 'Selected plugin descriptor SHA-256',
|
||
plugin_plan_json longtext not null comment 'Canonical resolved Plugin execution plan',
|
||
template_code varchar(100) not null comment 'Template pack code',
|
||
template_version varchar(100) not null comment 'Template contract version',
|
||
template_fingerprint char(64) not null comment 'Template descriptor SHA-256',
|
||
environment_fingerprint char(64) not null comment 'Aggregate environment SHA-256',
|
||
aggregate_content_hash char(64) not null comment 'Generated file manifest SHA-256',
|
||
target_count int not null default 0 comment 'Generated target count',
|
||
file_count int not null default 0 comment 'Generated file count',
|
||
total_bytes bigint(20) not null default 0 comment 'Uncompressed generated bytes',
|
||
status varchar(20) not null default 'SUCCEEDED' comment 'Run status',
|
||
create_time datetime not null comment 'Completion time',
|
||
primary key (generation_run_id),
|
||
key idx_factory_run_user_project (user_id, project_id),
|
||
key idx_factory_run_spec_version (spec_version_id),
|
||
key idx_factory_run_project_hash (project_id, aggregate_content_hash),
|
||
constraint fk_factory_run_project foreign key (project_id)
|
||
references front_project(project_id) on delete cascade,
|
||
constraint fk_factory_run_spec foreign key (spec_version_id)
|
||
references factory_project_spec_version(spec_version_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Successful ProjectSpec generation runs';
|
||
|
||
create table factory_generation_target (
|
||
generation_target_id bigint(20) not null auto_increment comment 'Generated target ID',
|
||
generation_run_id bigint(20) not null comment 'Generation run ID',
|
||
template_type varchar(40) not null comment 'Generation target type',
|
||
content_hash char(64) not null comment 'Target manifest SHA-256',
|
||
file_count int not null default 0 comment 'Target file count',
|
||
total_bytes bigint(20) not null default 0 comment 'Target uncompressed bytes',
|
||
primary key (generation_target_id),
|
||
unique key uk_factory_target_run_type (generation_run_id, template_type),
|
||
constraint fk_factory_target_run foreign key (generation_run_id)
|
||
references factory_generation_run(generation_run_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Generation target manifests';
|
||
|
||
create table factory_generation_file (
|
||
generation_file_id bigint(20) not null auto_increment comment 'Generated file manifest ID',
|
||
generation_target_id bigint(20) not null comment 'Generated target ID',
|
||
file_path varchar(1024) not null comment 'Relative generated file path',
|
||
file_size bigint(20) not null default 0 comment 'Generated file bytes',
|
||
content_hash char(64) not null comment 'Generated file SHA-256',
|
||
primary key (generation_file_id),
|
||
key idx_factory_file_target (generation_target_id),
|
||
constraint fk_factory_file_target foreign key (generation_target_id)
|
||
references factory_generation_target(generation_target_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Generated file manifests';
|
||
|
||
create table factory_project_quality_run (
|
||
quality_run_id bigint(20) not null auto_increment comment 'Quality Run ID',
|
||
project_id bigint(20) not null comment 'Front project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generation_run_id bigint(20) not null comment 'Bound Generation Run ID',
|
||
source_aggregate_hash char(64) not null comment 'Bound generated source aggregate SHA-256',
|
||
status varchar(20) not null default 'QUEUED' comment 'QUEUED, RUNNING, PASSED, FAILED, INTERRUPTED',
|
||
attempt_no int not null default 0 comment 'Worker claim count',
|
||
check_total int not null default 4 comment 'Expected quality check count',
|
||
passed_count int not null default 0 comment 'Passed quality checks',
|
||
failed_count int not null default 0 comment 'Failed quality checks',
|
||
error_summary varchar(1000) default '' comment 'Sanitized run failure summary',
|
||
lease_owner varchar(100) default null comment 'Current Worker identity',
|
||
lease_until datetime default null comment 'Current Worker lease expiry',
|
||
started_at datetime default null comment 'Execution start time',
|
||
finished_at datetime default null comment 'Terminal time',
|
||
duration_ms bigint(20) not null default 0 comment 'Execution duration milliseconds',
|
||
create_time datetime not null comment 'Creation time',
|
||
update_time datetime not null comment 'Update time',
|
||
primary key (quality_run_id),
|
||
key idx_factory_quality_user_project (user_id, project_id, quality_run_id),
|
||
key idx_factory_quality_generation (generation_run_id, source_aggregate_hash, quality_run_id),
|
||
key idx_factory_quality_claim (status, lease_until, quality_run_id),
|
||
constraint fk_factory_quality_generation foreign key (generation_run_id)
|
||
references factory_generation_run(generation_run_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Persistent project quality runs';
|
||
|
||
create table factory_project_quality_check (
|
||
quality_check_id bigint(20) not null auto_increment comment 'Quality check ID',
|
||
quality_run_id bigint(20) not null comment 'Quality Run ID',
|
||
check_code varchar(40) not null comment 'JAVA_TEST, FRONTEND_BUILD, SQL_IMPORT, API_SMOKE',
|
||
sequence_no int not null comment 'Stable execution order',
|
||
status varchar(20) not null default 'PENDING' comment 'PENDING, RUNNING, PASSED, FAILED',
|
||
summary varchar(1000) default '' comment 'Sanitized check summary',
|
||
log_excerpt longtext comment 'Sanitized bounded execution log',
|
||
started_at datetime default null comment 'Check start time',
|
||
finished_at datetime default null comment 'Check terminal time',
|
||
duration_ms bigint(20) not null default 0 comment 'Check duration milliseconds',
|
||
primary key (quality_check_id),
|
||
unique key uk_factory_quality_check_code (quality_run_id, check_code),
|
||
unique key uk_factory_quality_check_sequence (quality_run_id, sequence_no),
|
||
constraint fk_factory_quality_check_run foreign key (quality_run_id)
|
||
references factory_project_quality_run(quality_run_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Ordered project quality checks';
|
||
|
||
create table factory_project_certified_artifact (
|
||
artifact_id bigint(20) not null auto_increment comment 'Certified artifact ID',
|
||
quality_run_id bigint(20) not null comment 'Bound passed Quality Run ID',
|
||
project_id bigint(20) not null comment 'Front project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generation_run_id bigint(20) not null comment 'Bound Generation Run ID',
|
||
source_aggregate_hash char(64) not null comment 'Bound source aggregate SHA-256',
|
||
status varchar(20) not null comment 'READY or FAILED',
|
||
zip_sha256 char(64) not null comment 'Frozen ZIP SHA-256',
|
||
zip_size bigint(20) not null comment 'Frozen ZIP bytes',
|
||
report_sha256 char(64) not null comment 'Canonical quality report SHA-256',
|
||
report_size bigint(20) not null comment 'Quality report bytes',
|
||
storage_key varchar(500) not null comment 'Immutable ZIP object key',
|
||
report_storage_key varchar(500) not null comment 'Immutable report object key',
|
||
frozen_at datetime not null comment 'Artifact freeze time',
|
||
create_time datetime not null comment 'Creation time',
|
||
primary key (artifact_id),
|
||
unique key uk_factory_certified_quality (quality_run_id),
|
||
key idx_factory_certified_zip_hash (zip_sha256),
|
||
key idx_factory_certified_identity (user_id, project_id, generation_run_id, source_aggregate_hash),
|
||
constraint fk_factory_certified_quality foreign key (quality_run_id)
|
||
references factory_project_quality_run(quality_run_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable certified project artifacts';
|
||
|
||
create table factory_project_preview_job (
|
||
preview_job_id bigint(20) not null auto_increment comment 'Preview Job ID',
|
||
project_id bigint(20) not null comment 'Front project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
status varchar(24) not null comment 'Durable preview state',
|
||
message varchar(1000) default '' comment 'Sanitized user message',
|
||
lease_owner varchar(100) default null comment 'Preview Worker identity',
|
||
lease_token char(36) default null comment 'Private fencing token',
|
||
lease_until datetime default null comment 'Worker lease expiry',
|
||
runtime_ref varchar(200) default null comment 'Private Docker runtime reference',
|
||
runtime_ref_hash char(64) default null comment 'Public runtime identity hash',
|
||
frontend_url varchar(500) default null comment 'Preview frontend URL',
|
||
backend_url varchar(500) default null comment 'Preview backend URL',
|
||
admin_frontend_url varchar(500) default null comment 'Admin preview URL',
|
||
public_port int default null comment 'Worker allocated public port',
|
||
screenshot_key varchar(500) default null comment 'Screenshot object key',
|
||
screenshot_sha256 char(64) default null comment 'Screenshot SHA-256',
|
||
cpu_limit decimal(6,2) not null comment 'Docker CPU limit',
|
||
memory_limit_mb int not null comment 'Docker memory limit in MB',
|
||
pids_limit int not null comment 'Docker process limit',
|
||
log_excerpt longtext comment 'Sanitized bounded Worker log',
|
||
started_at datetime default null comment 'Container start time',
|
||
expires_at datetime not null comment 'Preview TTL deadline',
|
||
finished_at datetime default null comment 'Terminal time',
|
||
create_time datetime not null comment 'Creation time',
|
||
update_time datetime not null comment 'Update time',
|
||
primary key (preview_job_id),
|
||
key idx_factory_preview_user_project (user_id, project_id, preview_job_id),
|
||
key idx_factory_preview_claim (status, lease_until, preview_job_id),
|
||
key idx_factory_preview_expiry (status, expires_at, preview_job_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Durable isolated container preview jobs';
|
||
|
||
create table factory_project_v1_acceptance_run (
|
||
acceptance_run_id bigint(20) not null auto_increment comment 'V1 Acceptance Run ID',
|
||
project_id bigint(20) not null comment 'Golden sample project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generation_run_id bigint(20) default null comment 'Bound Generation Run ID',
|
||
quality_run_id bigint(20) default null comment 'Bound Quality Run ID',
|
||
artifact_id bigint(20) default null comment 'Bound certified artifact ID',
|
||
preview_job_id bigint(20) default null comment 'Bound container Preview Job ID',
|
||
status varchar(20) not null comment 'RUNNING, PASSED, FAILED',
|
||
summary varchar(1000) default '' comment 'Sanitized acceptance summary',
|
||
started_at datetime not null comment 'Acceptance start time',
|
||
finished_at datetime default null comment 'Acceptance terminal time',
|
||
duration_ms bigint(20) not null default 0 comment 'Acceptance duration',
|
||
create_time datetime not null comment 'Creation time',
|
||
primary key (acceptance_run_id),
|
||
key idx_factory_v1_acceptance_project (user_id, project_id, acceptance_run_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Project Factory V1 golden sample acceptance runs';
|
||
|
||
create table factory_project_v1_acceptance_check (
|
||
acceptance_check_id bigint(20) not null auto_increment comment 'Acceptance check ID',
|
||
acceptance_run_id bigint(20) not null comment 'Acceptance Run ID',
|
||
check_code varchar(40) not null comment 'GENERATION, FAILURE_RECOVERY, VERSION_ROLLBACK, CONTAINER_PREVIEW, CERTIFIED_DOWNLOAD',
|
||
sequence_no int not null comment 'Frozen check order',
|
||
status varchar(20) not null default 'PENDING' comment 'PENDING, PASSED, FAILED',
|
||
summary varchar(1000) default '' comment 'Sanitized check summary',
|
||
evidence_sha256 char(64) default null comment 'Canonical evidence SHA-256',
|
||
duration_ms bigint(20) not null default 0 comment 'Check duration',
|
||
primary key (acceptance_check_id),
|
||
unique key uk_factory_v1_acceptance_code (acceptance_run_id, check_code),
|
||
unique key uk_factory_v1_acceptance_sequence (acceptance_run_id, sequence_no),
|
||
constraint fk_factory_v1_acceptance_check foreign key (acceptance_run_id)
|
||
references factory_project_v1_acceptance_run(acceptance_run_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Ordered Project Factory V1 acceptance checks';
|
||
|
||
create table front_project_module (
|
||
id bigint(20) not null auto_increment comment 'id',
|
||
project_id bigint(20) not null comment '前台项目ID',
|
||
module_id bigint(20) not null comment '功能模块ID',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (id),
|
||
unique key uk_front_project_module (project_id, module_id),
|
||
key idx_front_project_module_project_id (project_id),
|
||
key idx_front_project_module_module_id (module_id),
|
||
constraint fk_front_project_module_project foreign key (project_id) references front_project(project_id),
|
||
constraint fk_front_project_module_module foreign key (module_id) references sys_module(module_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目功能模块关系';
|
||
|
||
create table front_project_page_design (
|
||
design_id bigint(20) not null auto_increment comment 'Page design ID',
|
||
project_id bigint(20) default null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
page_scope varchar(20) not null default 'frontend' comment 'Page scope: frontend/admin',
|
||
page_code varchar(100) not null comment 'Page code',
|
||
menu_code varchar(100) default '' comment 'Menu code',
|
||
page_name varchar(100) not null comment 'Page name',
|
||
route_path varchar(255) not null comment 'Route path',
|
||
page_type varchar(50) not null comment 'Page type',
|
||
table_name varchar(100) default '' comment 'Bound table name',
|
||
layout_json longtext comment 'Layout JSON',
|
||
action_json longtext comment 'Action JSON',
|
||
status char(1) default '0' comment 'Status',
|
||
version int default 1 comment 'Version',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
remark varchar(500) default null comment 'Remark',
|
||
primary key (design_id),
|
||
unique key uk_front_project_page_design (project_id, page_scope, page_code),
|
||
key idx_front_page_design_menu (project_id, menu_code),
|
||
key idx_front_page_design_table (project_id, table_name),
|
||
constraint fk_front_page_design_project foreign key (project_id) references front_project(project_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Frontend page design';
|
||
|
||
create table front_project_table (
|
||
table_id bigint(20) not null auto_increment comment '表设计ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
user_id bigint(20) not null comment '前台用户ID',
|
||
table_name varchar(200) not null comment '表名称',
|
||
table_comment varchar(500) default '' comment '表描述',
|
||
class_name varchar(100) default '' comment '实体类名称',
|
||
module_name varchar(30) default '' comment '生成模块名',
|
||
business_name varchar(30) default '' comment '生成业务名',
|
||
function_name varchar(50) default '' comment '生成功能名',
|
||
admin_menu_name varchar(100) default '' comment '后台菜单名称',
|
||
allow_add char(1) default '1' comment '是否允许新增(1是 0否)',
|
||
allow_edit char(1) default '1' comment '是否允许修改(1是 0否)',
|
||
allow_remove char(1) default '1' comment '是否允许删除(1是 0否)',
|
||
remove_type varchar(20) default 'physical' comment '删除方式(none不允许 logical逻辑删除 physical物理删除)',
|
||
operation_note varchar(500) default '' comment '操作能力说明',
|
||
tpl_category varchar(200) default 'crud' comment '模板类型',
|
||
tpl_web_type varchar(30) default 'element-plus' comment '前端模板类型',
|
||
options varchar(1000) default '' comment '生成选项',
|
||
create_table_sql longtext comment '建表SQL',
|
||
sort int default 0 comment '排序',
|
||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
primary key (table_id),
|
||
unique key uk_front_project_table (project_id, table_name),
|
||
key idx_front_project_table_project_id (project_id),
|
||
constraint fk_front_project_table_project foreign key (project_id) references front_project(project_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目表设计';
|
||
|
||
create table front_project_column (
|
||
column_id bigint(20) not null auto_increment comment '字段设计ID',
|
||
table_id bigint(20) not null comment '表设计ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
column_name varchar(200) not null comment '字段名称',
|
||
column_comment varchar(500) default '' comment '字段描述',
|
||
column_label varchar(100) default '' comment '字段展示名',
|
||
column_type varchar(100) not null comment '字段类型',
|
||
java_type varchar(500) default 'String' comment 'Java类型',
|
||
java_field varchar(200) default '' comment 'Java字段名',
|
||
is_pk char(1) default '0' comment '是否主键(1是)',
|
||
is_increment char(1) default '0' comment '是否自增(1是)',
|
||
is_required char(1) default '0' comment '是否必填(1是)',
|
||
is_insert char(1) default '1' comment '是否插入字段(1是)',
|
||
is_edit char(1) default '1' comment '是否编辑字段(1是)',
|
||
is_list char(1) default '1' comment '是否列表字段(1是)',
|
||
is_query char(1) default '0' comment '是否查询字段(1是)',
|
||
query_type varchar(200) default 'EQ' comment '查询方式',
|
||
html_type varchar(200) default 'input' comment '显示类型',
|
||
dict_type varchar(200) default '' comment '字典类型',
|
||
dict_options text comment '字段字典选项JSON',
|
||
default_value varchar(200) default null comment '默认值',
|
||
sort int default 0 comment '排序',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
primary key (column_id),
|
||
key idx_front_project_column_table_id (table_id),
|
||
key idx_front_project_column_project_id (project_id),
|
||
constraint fk_front_project_column_table foreign key (table_id) references front_project_table(table_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目字段设计';
|
||
|
||
create table front_project_generation (
|
||
generation_id bigint(20) not null auto_increment comment '生成记录ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
user_id bigint(20) not null comment '前台用户ID',
|
||
generate_type varchar(50) not null comment '生成类型',
|
||
provider varchar(50) default 'deepseek' comment 'AI提供方',
|
||
prompt_summary varchar(500) default '' comment 'Prompt摘要',
|
||
request_payload longtext comment '请求内容',
|
||
response_payload longtext comment '响应内容',
|
||
success char(1) default '0' comment '是否成功(1成功 0失败)',
|
||
error_message varchar(1000) default '' comment '错误信息',
|
||
token_usage int default 0 comment 'Token用量',
|
||
elapsed_ms bigint(20) default 0 comment '耗时毫秒',
|
||
create_time datetime default null comment '创建时间',
|
||
primary key (generation_id),
|
||
key idx_front_project_generation_project_id (project_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目生成记录';
|
||
|
||
create table factory_ai_stage_output (
|
||
stage_output_id bigint(20) not null auto_increment comment 'Stage output ID',
|
||
generation_id bigint(20) not null comment 'Parent generation ID',
|
||
project_id bigint(20) not null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generate_type varchar(50) not null comment 'Stage generation type',
|
||
request_payload longtext comment 'Rendered stage input',
|
||
response_payload longtext comment 'Raw model response or correction attempts',
|
||
success char(1) default '0' comment '1 success, 0 failure',
|
||
error_message varchar(1000) default '' comment 'Stage error',
|
||
elapsed_ms bigint(20) default 0 comment 'Elapsed milliseconds',
|
||
create_time datetime not null comment 'Created at',
|
||
primary key (stage_output_id),
|
||
key idx_factory_ai_stage_output_generation (generation_id),
|
||
key idx_factory_ai_stage_output_project (project_id, create_time)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Per-stage AI output evidence';
|
||
|
||
create table front_project_diagram (
|
||
diagram_id bigint(20) not null auto_increment comment 'Diagram ID',
|
||
project_id bigint(20) default null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
diagram_type varchar(50) not null comment 'Diagram type',
|
||
title varchar(200) default '' comment 'Diagram title',
|
||
description varchar(1000) default '' comment 'Diagram description',
|
||
diagram_json longtext comment 'Diagram JSON',
|
||
mermaid longtext comment 'Mermaid DSL',
|
||
markdown longtext comment 'Diagram notes',
|
||
status char(1) default '0' comment 'Status',
|
||
version int default 1 comment 'Version',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
remark varchar(500) default null comment 'Remark',
|
||
primary key (diagram_id),
|
||
key idx_front_project_diagram_project (project_id),
|
||
key idx_front_project_diagram_user (user_id, project_id),
|
||
unique key uk_front_project_diagram_type (user_id, project_id, diagram_type),
|
||
constraint fk_front_project_diagram_project foreign key (project_id) references front_project(project_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Front project diagram draft';
|
||
|
||
create table front_project_paper (
|
||
paper_id bigint(20) not null auto_increment comment 'Paper ID',
|
||
project_id bigint(20) not null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
paper_title varchar(300) default '' comment 'Paper title',
|
||
major varchar(100) default '' comment 'Major',
|
||
school varchar(100) default '' comment 'School',
|
||
degree_name varchar(50) default '' comment 'Degree',
|
||
target_words int default 8000 comment 'Target words',
|
||
extra_requirements varchar(2000) default '' comment 'Extra requirements',
|
||
outline_json longtext comment 'Outline JSON',
|
||
outline_markdown longtext comment 'Outline markdown',
|
||
draft_markdown longtext comment 'Draft markdown',
|
||
status char(1) default '0' comment 'Status',
|
||
version int default 1 comment 'Version',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
remark varchar(500) default null comment 'Remark',
|
||
primary key (paper_id),
|
||
unique key uk_front_project_paper_project (project_id),
|
||
key idx_front_project_paper_user (user_id, project_id),
|
||
constraint fk_front_project_paper_project foreign key (project_id) references front_project(project_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Front project paper draft';
|
||
|
||
create table front_ai_generation_task (
|
||
task_id bigint(20) not null auto_increment comment 'AI task ID',
|
||
generation_id bigint(20) default null comment 'Generation record ID',
|
||
project_id bigint(20) not null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generate_type varchar(50) not null comment 'Generation type',
|
||
provider varchar(50) default 'deepseek' comment 'AI provider',
|
||
model varchar(100) default 'deepseek-chat' comment 'AI model',
|
||
prompt_code varchar(100) not null comment 'Published Prompt code',
|
||
prompt_version varchar(50) not null comment 'Published Prompt version',
|
||
prompt_fingerprint char(64) not null comment 'Published Prompt SHA-256',
|
||
stage_manifest_json longtext comment 'Canonical stage manifest JSON',
|
||
stage_manifest_hash char(64) default null comment 'Stage manifest SHA-256',
|
||
status varchar(30) not null default 'QUEUED' comment 'Task status',
|
||
request_hash varchar(64) not null comment 'Request idempotency hash',
|
||
request_payload longtext comment 'Request JSON',
|
||
result_payload longtext comment 'Result JSON',
|
||
error_code varchar(100) default '' comment 'Error code',
|
||
error_message varchar(1000) default '' comment 'Error message',
|
||
attempts int default 0 comment 'Attempt count',
|
||
max_attempts int default 3 comment 'Max attempts',
|
||
next_retry_time datetime default null comment 'Next retry time',
|
||
locked_by varchar(100) default '' comment 'Worker lock owner',
|
||
locked_until datetime default null comment 'Worker lock expiry',
|
||
progress int default 0 comment 'Progress percent',
|
||
current_step varchar(100) default '' comment 'Current step',
|
||
prompt_tokens int default 0 comment 'Prompt tokens',
|
||
prompt_cache_hit_tokens int default 0 comment 'Prompt cache hit tokens',
|
||
prompt_cache_miss_tokens int default 0 comment 'Prompt cache miss tokens',
|
||
completion_tokens int default 0 comment 'Completion tokens',
|
||
reasoning_tokens int default 0 comment 'Reasoning tokens',
|
||
input_tokens int default 0 comment 'Input tokens',
|
||
output_tokens int default 0 comment 'Output tokens',
|
||
total_tokens int default 0 comment 'Total tokens',
|
||
cost_cents int default 0 comment 'Estimated cost in cents',
|
||
cost_usd decimal(18,8) default 0.00000000 comment 'Estimated cost in USD',
|
||
started_at datetime default null comment 'Started time',
|
||
finished_at datetime default null comment 'Finished time',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
primary key (task_id),
|
||
key idx_front_ai_task_project (user_id, project_id),
|
||
key idx_front_ai_task_status (status, next_retry_time),
|
||
key idx_front_ai_task_generation (generation_id),
|
||
key idx_front_ai_task_hash (user_id, project_id, request_hash)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Front AI generation task';
|
||
|
||
create table factory_ai_task_stage (
|
||
task_stage_id bigint(20) not null auto_increment comment 'Task stage attempt ID',
|
||
task_id bigint(20) not null comment 'AI task ID',
|
||
stage_code varchar(50) not null comment 'Stable stage code',
|
||
sequence_no int not null comment 'Manifest sequence number',
|
||
attempt_no int not null comment 'Task attempt number',
|
||
status varchar(20) not null comment 'RUNNING, SUCCEEDED, or FAILED',
|
||
handler_code varchar(100) default null comment 'Handler code',
|
||
handler_version varchar(50) default null comment 'Handler version',
|
||
input_contract varchar(100) default null comment 'Handler input contract',
|
||
output_contract varchar(100) default null comment 'Handler output contract',
|
||
generate_type varchar(50) default null comment 'AI generation type for this stage',
|
||
prompt_code varchar(100) default null comment 'Pinned Prompt code',
|
||
prompt_version varchar(50) default null comment 'Pinned Prompt version',
|
||
prompt_fingerprint char(64) default null comment 'Pinned Prompt SHA-256',
|
||
provider varchar(50) default null comment 'Pinned model provider',
|
||
model varchar(100) default null comment 'Pinned model ID',
|
||
generation_run_id bigint(20) default null comment 'Related source generation run ID',
|
||
started_at datetime not null comment 'Stage start time',
|
||
finished_at datetime default null comment 'Stage finish time',
|
||
duration_millis bigint(20) default null comment 'Stage duration in milliseconds',
|
||
error_message varchar(1000) default '' comment 'Sanitized stage error',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
primary key (task_stage_id),
|
||
unique key uk_factory_ai_stage_attempt (task_id, stage_code, attempt_no),
|
||
key idx_factory_ai_stage_task (task_id, attempt_no, sequence_no),
|
||
key idx_factory_ai_stage_status (status, update_time),
|
||
key idx_factory_ai_stage_generation_run (generation_run_id),
|
||
constraint fk_factory_ai_stage_task foreign key (task_id)
|
||
references front_ai_generation_task(task_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='AI task stage attempt ledger';
|
||
|
||
create table factory_ai_task_checkpoint (
|
||
checkpoint_id bigint(20) not null auto_increment comment 'Checkpoint ID',
|
||
task_id bigint(20) not null comment 'AI task ID',
|
||
stage_code varchar(50) not null comment 'Stable stage code',
|
||
sequence_no int not null comment 'Manifest sequence number',
|
||
attempt_no int not null comment 'Task attempt number',
|
||
schema_version varchar(20) not null comment 'Checkpoint payload schema',
|
||
payload_json longtext not null comment 'Canonical checkpoint envelope JSON',
|
||
content_hash char(64) not null comment 'Checkpoint SHA-256',
|
||
spec_version_id bigint(20) default null comment 'Pinned ProjectSpec version ID',
|
||
generation_run_id bigint(20) default null comment 'Related source generation run ID',
|
||
create_time datetime default null comment 'Create time',
|
||
primary key (checkpoint_id),
|
||
unique key uk_factory_ai_checkpoint_attempt (task_id, stage_code, attempt_no),
|
||
key idx_factory_ai_checkpoint_task (task_id, attempt_no, sequence_no),
|
||
key idx_factory_ai_checkpoint_spec (spec_version_id),
|
||
key idx_factory_ai_checkpoint_run (generation_run_id),
|
||
constraint fk_factory_ai_checkpoint_task foreign key (task_id)
|
||
references front_ai_generation_task(task_id) on delete cascade
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Immutable AI task stage checkpoint';
|
||
|
||
create table front_ai_quota_bucket (
|
||
bucket_id bigint(20) not null auto_increment comment 'Quota bucket ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
period_type varchar(20) not null comment 'DAY or MONTH',
|
||
period_key varchar(20) not null comment 'Period key',
|
||
task_limit int default 0 comment 'Task limit',
|
||
task_used int default 0 comment 'Used tasks',
|
||
token_limit int default 0 comment 'Token limit',
|
||
token_used int default 0 comment 'Used tokens',
|
||
cost_limit_cents int default 0 comment 'Cost limit in cents',
|
||
cost_used_cents int default 0 comment 'Used cost in cents',
|
||
running_limit int default 1 comment 'Running task limit',
|
||
running_count int default 0 comment 'Running task count',
|
||
create_time datetime default null comment 'Create time',
|
||
update_time datetime default null comment 'Update time',
|
||
primary key (bucket_id),
|
||
unique key uk_front_ai_quota_bucket (user_id, period_type, period_key)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Front AI quota bucket';
|
||
|
||
create table front_ai_usage_ledger (
|
||
ledger_id bigint(20) not null auto_increment comment 'Usage ledger ID',
|
||
task_id bigint(20) default null comment 'Task ID',
|
||
generation_id bigint(20) default null comment 'Generation record ID',
|
||
project_id bigint(20) default null comment 'Project ID',
|
||
user_id bigint(20) not null comment 'Front user ID',
|
||
generate_type varchar(50) not null comment 'Generation type',
|
||
provider varchar(50) default 'deepseek' comment 'AI provider',
|
||
model varchar(100) default 'deepseek-chat' comment 'AI model',
|
||
prompt_code varchar(100) default null comment 'Prompt code',
|
||
prompt_version varchar(50) default null comment 'Prompt version',
|
||
prompt_fingerprint char(64) default null comment 'Prompt SHA-256',
|
||
system_prompt longtext comment 'Actual system prompt',
|
||
user_prompt longtext comment 'Actual rendered user prompt',
|
||
output_content longtext comment 'Aggregated model output',
|
||
stream char(1) default '0' comment 'Streaming flag',
|
||
duration_ms bigint(20) default 0 comment 'Invocation duration in milliseconds',
|
||
prompt_tokens int default 0 comment 'Prompt tokens',
|
||
prompt_cache_hit_tokens int default 0 comment 'Prompt cache hit tokens',
|
||
prompt_cache_miss_tokens int default 0 comment 'Prompt cache miss tokens',
|
||
completion_tokens int default 0 comment 'Completion tokens',
|
||
reasoning_tokens int default 0 comment 'Reasoning tokens',
|
||
input_tokens int default 0 comment 'Input tokens',
|
||
output_tokens int default 0 comment 'Output tokens',
|
||
total_tokens int default 0 comment 'Total tokens',
|
||
cost_cents int default 0 comment 'Estimated cost in cents',
|
||
cost_usd decimal(18,8) default 0.00000000 comment 'Estimated cost in USD',
|
||
success char(1) default '0' comment 'Success flag',
|
||
error_message varchar(1000) default '' comment 'Error message',
|
||
create_time datetime default null comment 'Create time',
|
||
primary key (ledger_id),
|
||
key idx_front_ai_usage_user (user_id, create_time),
|
||
key idx_front_ai_usage_task (task_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='Front AI usage ledger';
|
||
|
||
create table front_project_file (
|
||
file_id bigint(20) not null auto_increment comment '文件缓存ID',
|
||
project_id bigint(20) not null comment '项目ID',
|
||
template_type varchar(50) not null comment '模板类型',
|
||
node_id varchar(100) default '' comment '结构节点ID',
|
||
table_id bigint(20) default null comment '表设计ID',
|
||
file_name varchar(255) not null comment '文件名',
|
||
file_path varchar(500) default '' comment '文件路径',
|
||
file_content longtext comment '文件内容',
|
||
content_hash varchar(64) default '' comment '内容哈希',
|
||
create_time datetime default null comment '创建时间',
|
||
update_time datetime default null comment '更新时间',
|
||
primary key (file_id),
|
||
key idx_front_project_file_project_id (project_id),
|
||
key idx_front_project_file_lookup (project_id, template_type, table_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='前台项目预览文件缓存';
|
||
|
||
-- =================================================
|
||
-- EasyCode source store tables
|
||
-- =================================================
|
||
|
||
drop table if exists source_purchase;
|
||
drop table if exists source_project;
|
||
|
||
create table source_project (
|
||
project_id bigint(20) not null auto_increment comment '源码项目ID',
|
||
slug varchar(100) not null comment '前台访问标识',
|
||
project_name varchar(120) not null comment '项目名称',
|
||
category varchar(50) default '' comment '分类',
|
||
cover_text varchar(30) default '' comment '封面标识',
|
||
summary varchar(500) default '' comment '项目摘要',
|
||
description_md longtext comment 'Markdown项目描述',
|
||
price bigint(20) default 0 comment '价格,单位分',
|
||
view_count bigint(20) default 0 comment '浏览量',
|
||
tags longtext comment '技术标签JSON',
|
||
modules longtext comment '功能模块JSON',
|
||
scenes longtext comment '适用场景JSON',
|
||
resource_name varchar(200) default '' comment '源码资源名称',
|
||
resource_url varchar(500) default '' comment '源码资源地址',
|
||
resource_version varchar(50) default '' comment '源码资源版本',
|
||
resource_size varchar(50) default '' comment '源码资源大小',
|
||
sort int default 0 comment '排序',
|
||
status char(1) default '0' comment '状态(0上架 1下架)',
|
||
del_flag char(1) default '0' comment '删除标志(0存在 2删除)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime default null comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime default null comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (project_id),
|
||
unique key uk_source_project_slug (slug),
|
||
key idx_source_project_category (category),
|
||
key idx_source_project_status (status, del_flag)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='源码库项目表';
|
||
|
||
create table source_purchase (
|
||
purchase_id bigint(20) not null auto_increment comment '购买记录ID',
|
||
project_id bigint(20) not null comment '源码项目ID',
|
||
user_id bigint(20) not null comment '前台用户ID',
|
||
order_no varchar(64) not null comment '订单号',
|
||
amount bigint(20) default 0 comment '金额,单位分',
|
||
pay_status char(1) default '0' comment '支付状态(0待支付 1已支付 2已取消)',
|
||
resource_status char(1) default '0' comment '资源状态(0未发放 1已发放)',
|
||
purchase_time datetime default null comment '购买时间',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime default null comment '创建时间',
|
||
update_by varchar(64) default '' comment '更新者',
|
||
update_time datetime default null comment '更新时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (purchase_id),
|
||
unique key uk_source_purchase_order_no (order_no),
|
||
key idx_source_purchase_user (user_id),
|
||
key idx_source_purchase_project (project_id),
|
||
constraint fk_source_purchase_project foreign key (project_id) references source_project(project_id),
|
||
constraint fk_source_purchase_user foreign key (user_id) references front_user(user_id)
|
||
) engine=innodb auto_increment=100 default charset=utf8mb4 comment='源码购买记录表';
|
||
|
||
insert into source_project
|
||
(project_id, slug, project_name, category, cover_text, summary, description_md, price, view_count, tags, modules, scenes, resource_name, resource_url, resource_version, resource_size, sort, status, del_flag, create_by, create_time, update_by, update_time, remark)
|
||
values
|
||
(100, 'dms-platform', '商用车 DMS 管理系统', 'enterprise', 'DMS', '覆盖经销商、维修工单、索赔、配件库存、服务活动和结算的商用车售后管理源码。',
|
||
'# 商用车 DMS 管理系统\n\n这套源码面向商用车售后服务场景,提供经销商、车辆档案、维修工单、索赔流程、配件库存和结算对账等核心能力。\n\n## 核心功能\n\n- 经销商档案、服务站和维修技师管理\n- 车辆档案、保养提醒和维修历史追踪\n- 维修工单、派工、完工质检和费用结算\n- 配件入库、出库、调拨和库存预警\n- 索赔申请、审核、结算和统计报表', 39900, 2860,
|
||
'["Spring Boot","Vue2","MySQL"]', '["经销商管理","维修工单","配件库存","索赔结算","服务活动"]', '["汽车后市场","商用车售后","经销商协同"]', '', '', '1.0.0', '', 1, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null),
|
||
(101, 'mall-order-system', '商城订单管理系统', 'mall', 'MALL', '包含商品、订单、支付、库存、优惠券、会员和后台统计模块的商城管理源码。',
|
||
'# 商城订单管理系统\n\n项目提供从商品上架到订单履约的完整后台管理能力,适合作为中小型商城或订单中台的启动源码。\n\n## 功能模块\n\n- 商品分类、SKU、库存和上下架\n- 购物车、订单、支付记录和售后单\n- 优惠券、满减活动和会员等级\n- 后台统计看板和经营数据导出', 29900, 1980,
|
||
'["Spring Cloud","Redis","Vue3"]', '["商品中心","订单中心","支付记录","会员体系","营销活动"]', '["电商后台","订单运营","会员营销"]', '', '', '1.0.0', '', 2, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null),
|
||
(102, 'oa-approval-suite', 'OA 办公审批系统', 'office', 'OA', '集成用户、角色、菜单、审批流、请假、报销、公告和文件管理的办公源码。',
|
||
'# OA 办公审批系统\n\n这是一套偏企业内网办公的基础源码,重点覆盖审批、公告、文件与权限管理。\n\n## 亮点\n\n- 可配置审批节点和审批人\n- 请假、报销、外出等常见办公流程\n- 公告通知、附件上传和文件归档\n- 角色、菜单、按钮级权限控制', 26800, 1750,
|
||
'["Sa-Token","Element UI","工作流"]', '["审批流程","请假报销","公告通知","文件管理","权限菜单"]', '["企业内网","行政审批","协同办公"]', '', '', '1.0.0', '', 3, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null),
|
||
(103, 'erp-warehouse', 'ERP 仓储管理系统', 'enterprise', 'ERP', '提供采购、销售、入库、出库、盘点、供应商和库存报表模块的仓储源码。',
|
||
'# ERP 仓储管理系统\n\n源码聚焦进销存和仓储管理,适合小型供应链、仓库和贸易公司快速搭建业务后台。\n\n## 模块清单\n\n- 采购订单、采购入库和供应商档案\n- 销售订单、销售出库和客户档案\n- 库存流水、库存盘点和预警规则\n- Excel 导入导出与库存报表', 19900, 1320,
|
||
'["ERP","MyBatis-Plus","Excel"]', '["采购入库","销售出库","库存盘点","供应商管理","报表导出"]', '["仓储管理","进销存","供应链后台"]', '', '', '1.0.0', '', 4, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null),
|
||
(104, 'lowcode-form-platform', '低代码表单平台', 'lowcode', 'FORM', '支持动态表单、拖拽布局、字段配置、数据字典和在线设计的低代码源码。',
|
||
'# 低代码表单平台\n\n项目用于构建配置化表单和数据采集页面,包含设计器、字段配置、预览和提交数据管理。\n\n## 能力范围\n\n- 拖拽式表单组件编排\n- 字段属性、校验规则和选项配置\n- 字典数据联动\n- 表单预览与数据提交记录', 49900, 980,
|
||
'["Vue3","Element Plus","拖拽设计"]', '["表单设计器","字段配置","动态校验","数据字典","表单预览"]', '["低代码平台","动态表单","配置化后台"]', '', '', '1.0.0', '', 5, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null),
|
||
(105, 'microservice-auth-starter', '微服务权限脚手架', 'microservice', 'MS', '集成网关、认证中心、系统服务、日志服务、文件服务和监控基础能力的脚手架源码。',
|
||
'# 微服务权限脚手架\n\n这套源码适合从单体后台升级到微服务架构的团队,预置认证、网关、系统权限和基础监控能力。\n\n## 服务组成\n\n- Gateway 网关统一鉴权和路由\n- Auth 认证中心\n- System 系统权限服务\n- Log 操作日志服务\n- File 文件服务', 59900, 2560,
|
||
'["Spring Cloud","Nacos","Gateway"]', '["网关服务","认证中心","系统服务","日志中心","文件服务"]', '["微服务基础架构","权限平台","多服务治理"]', '', '', '1.0.0', '', 6, '0', '0', 'admin', sysdate(), 'admin', sysdate(), null);
|
||
|
||
SET FOREIGN_KEY_CHECKS = 1;
|
||
|
||
-- Runnable three-tier code generation templates
|
||
-- Import this script after sql/db.sql.
|
||
-- Template ids: 9201 backend, 9202 admin_frontend, 9203 frontend
|
||
|
||
SET FOREIGN_KEY_CHECKS = 0;
|
||
|
||
DELETE FROM sys_project_template WHERE template_id IN (9201, 9202, 9203);
|
||
DELETE FROM sys_project_structure WHERE template_id IN (9201, 9202, 9203) OR node_id BETWEEN 920100 AND 920399;
|
||
DELETE FROM sys_template_file WHERE template_id IN (9201, 9202, 9203) OR template_file_id BETWEEN 920100 AND 920399;
|
||
DELETE FROM sys_template WHERE template_id IN (9201, 9202, 9203);
|
||
|
||
INSERT INTO sys_template (template_id, template_name, template_path, template_desc, template_type, bundle_code, template_status, create_by, create_time, remark) VALUES
|
||
(9201, 'Runnable Backend Template', '/runnable/backend', 'Spring Boot + MyBatis Plus runnable backend', 'backend', 'qing', 0, 'admin', sysdate(), 'three-tier runnable template'),
|
||
(9202, 'Runnable Admin Frontend Template', '/runnable/admin_frontend', 'Vue2 + Element UI runnable admin frontend', 'admin_frontend', 'qing', 0, 'admin', sysdate(), 'three-tier runnable template'),
|
||
(9203, 'Runnable Portal Frontend Template', '/runnable/frontend', 'Vue2 + Element UI runnable portal frontend', 'frontend', 'qing', 0, 'admin', sysdate(), 'three-tier runnable template');
|
||
|
||
-- Backend template files
|
||
INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES
|
||
(920101, 9201, 'pom.xml.vm', NULL, 'pom.xml.vm', '<?xml version="1.0" encoding="UTF-8"?>
|
||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||
<modelVersion>4.0.0</modelVersion>
|
||
|
||
<parent>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-starter-parent</artifactId>
|
||
<version>2.5.9</version>
|
||
<relativePath/>
|
||
</parent>
|
||
|
||
<groupId>${packageName}</groupId>
|
||
<artifactId>${businessName}-service</artifactId>
|
||
<version>1.0.0</version>
|
||
<name>${functionName}</name>
|
||
<description>${functionName} generated by qing template</description>
|
||
|
||
<properties>
|
||
<java.version>1.8</java.version>
|
||
</properties>
|
||
|
||
<dependencies>
|
||
<dependency>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-starter-web</artifactId>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>com.baomidou</groupId>
|
||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||
<version>3.5.1</version>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>mysql</groupId>
|
||
<artifactId>mysql-connector-java</artifactId>
|
||
<scope>runtime</scope>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>org.apache.commons</groupId>
|
||
<artifactId>commons-lang3</artifactId>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>cn.hutool</groupId>
|
||
<artifactId>hutool-all</artifactId>
|
||
<version>5.7.20</version>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>org.apache.poi</groupId>
|
||
<artifactId>poi-ooxml</artifactId>
|
||
<version>4.1.2</version>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>io.swagger</groupId>
|
||
<artifactId>swagger-annotations</artifactId>
|
||
<version>1.6.2</version>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>org.projectlombok</groupId>
|
||
<artifactId>lombok</artifactId>
|
||
<optional>true</optional>
|
||
</dependency>
|
||
|
||
<dependency>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-starter-test</artifactId>
|
||
<scope>test</scope>
|
||
</dependency>
|
||
</dependencies>
|
||
|
||
<build>
|
||
<plugins>
|
||
<plugin>
|
||
<groupId>org.springframework.boot</groupId>
|
||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||
</plugin>
|
||
</plugins>
|
||
</build>
|
||
</project>
|
||
', 'admin', sysdate()),
|
||
(920102, 9201, 'README.md.vm', NULL, 'README.md.vm', '# ${functionName}
|
||
|
||
这是由 qing 模板生成的单表 Spring Boot + Vue2 项目。
|
||
|
||
## 后端启动
|
||
|
||
1. 创建 MySQL 数据库,默认库名为 `vip`。
|
||
2. 执行 `sql/${businessName}.sql` 中的建表语句。
|
||
3. 按需修改 `src/main/resources/application.yml` 里的数据库账号密码。
|
||
4. 在项目根目录运行:
|
||
|
||
```bash
|
||
mvn spring-boot:run
|
||
```
|
||
|
||
The service starts at `http://localhost:8080`.
|
||
|
||
## 前端启动
|
||
|
||
```bash
|
||
cd vue
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
前端开发服务默认把 `/api` 代理到 `http://localhost:8080`。
|
||
', 'admin', sysdate()),
|
||
(920103, 9201, 'Application.java.vm', NULL, 'Application.java.vm', 'package ${packageName};
|
||
|
||
import org.mybatis.spring.annotation.MapperScan;
|
||
import org.springframework.boot.SpringApplication;
|
||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||
|
||
@MapperScan("${packageName}.mapper")
|
||
@SpringBootApplication
|
||
public class ${ClassName}Application
|
||
{
|
||
public static void main(String[] args)
|
||
{
|
||
SpringApplication.run(${ClassName}Application.class, args);
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920104, 9201, 'Result.java.vm', NULL, 'Result.java.vm', 'package ${packageName}.common;
|
||
|
||
import java.io.Serializable;
|
||
|
||
public class Result<T> implements Serializable
|
||
{
|
||
private static final long serialVersionUID = 1L;
|
||
|
||
private String code;
|
||
private String msg;
|
||
private T data;
|
||
|
||
public Result()
|
||
{
|
||
}
|
||
|
||
public Result(String code, String msg, T data)
|
||
{
|
||
this.code = code;
|
||
this.msg = msg;
|
||
this.data = data;
|
||
}
|
||
|
||
public static <T> Result<T> success()
|
||
{
|
||
return new Result<T>("200", "操作成功", null);
|
||
}
|
||
|
||
public static <T> Result<T> success(T data)
|
||
{
|
||
return new Result<T>("200", "操作成功", data);
|
||
}
|
||
|
||
public static <T> Result<T> error(String msg)
|
||
{
|
||
return new Result<T>("500", msg, null);
|
||
}
|
||
|
||
public String getCode()
|
||
{
|
||
return code;
|
||
}
|
||
|
||
public void setCode(String code)
|
||
{
|
||
this.code = code;
|
||
}
|
||
|
||
public String getMsg()
|
||
{
|
||
return msg;
|
||
}
|
||
|
||
public void setMsg(String msg)
|
||
{
|
||
this.msg = msg;
|
||
}
|
||
|
||
public T getData()
|
||
{
|
||
return data;
|
||
}
|
||
|
||
public void setData(T data)
|
||
{
|
||
this.data = data;
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920105, 9201, 'MybatisPlusConfig.java.vm', NULL, 'MybatisPlusConfig.java.vm', 'package ${packageName}.config;
|
||
|
||
import com.baomidou.mybatisplus.annotation.DbType;
|
||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||
import org.springframework.context.annotation.Bean;
|
||
import org.springframework.context.annotation.Configuration;
|
||
|
||
@Configuration
|
||
public class MybatisPlusConfig
|
||
{
|
||
@Bean
|
||
public MybatisPlusInterceptor mybatisPlusInterceptor()
|
||
{
|
||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||
return interceptor;
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920106, 9201, 'CorsConfig.java.vm', NULL, 'CorsConfig.java.vm', 'package ${packageName}.config;
|
||
|
||
import ${packageName}.security.PortalAuthInterceptor;
|
||
import javax.annotation.Resource;
|
||
import org.springframework.context.annotation.Configuration;
|
||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||
|
||
@Configuration
|
||
public class CorsConfig implements WebMvcConfigurer
|
||
{
|
||
@Resource
|
||
private PortalAuthInterceptor portalAuthInterceptor;
|
||
|
||
@Override
|
||
public void addCorsMappings(CorsRegistry registry)
|
||
{
|
||
registry.addMapping("/**")
|
||
.allowedOriginPatterns("*")
|
||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||
.allowedHeaders("*")
|
||
.allowCredentials(true)
|
||
.maxAge(3600);
|
||
}
|
||
|
||
@Override
|
||
public void addInterceptors(InterceptorRegistry registry)
|
||
{
|
||
registry.addInterceptor(portalAuthInterceptor)
|
||
.addPathPatterns("/**")
|
||
.excludePathPatterns("/auth/login", "/auth/admin/login", "/business-blocks/**", "/files/**", "/error");
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920107, 9201, 'FileController.java.vm', NULL, 'FileController.java.vm', 'package ${packageName}.controller;
|
||
|
||
import ${packageName}.common.Result;
|
||
import java.io.IOException;
|
||
import java.net.MalformedURLException;
|
||
import java.nio.file.Files;
|
||
import java.nio.file.Path;
|
||
import java.nio.file.Paths;
|
||
import java.nio.file.StandardCopyOption;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
import java.util.UUID;
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import org.springframework.core.io.Resource;
|
||
import org.springframework.core.io.UrlResource;
|
||
import org.springframework.http.HttpHeaders;
|
||
import org.springframework.http.ResponseEntity;
|
||
import org.springframework.util.StringUtils;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
import org.springframework.web.servlet.HandlerMapping;
|
||
|
||
@RestController
|
||
@RequestMapping("/files")
|
||
public class FileController
|
||
{
|
||
private final Path uploadRoot = Paths.get("uploads");
|
||
|
||
@PostMapping("/upload")
|
||
public Result<Map<String, String>> upload(@RequestParam("file") MultipartFile file) throws IOException
|
||
{
|
||
Files.createDirectories(uploadRoot);
|
||
String originalName = StringUtils.cleanPath(file.getOriginalFilename() == null ? "file" : file.getOriginalFilename());
|
||
String suffix = "";
|
||
int dotIndex = originalName.lastIndexOf(''.'');
|
||
if (dotIndex >= 0)
|
||
{
|
||
suffix = originalName.substring(dotIndex);
|
||
}
|
||
String fileName = UUID.randomUUID().toString().replace("-", "") + suffix;
|
||
Files.copy(file.getInputStream(), uploadRoot.resolve(fileName), StandardCopyOption.REPLACE_EXISTING);
|
||
|
||
Map<String, String> data = new HashMap<String, String>();
|
||
data.put("name", originalName);
|
||
data.put("url", "/files/" + fileName);
|
||
return Result.success(data);
|
||
}
|
||
|
||
@GetMapping("/**")
|
||
public ResponseEntity<Resource> getFile(HttpServletRequest request) throws MalformedURLException
|
||
{
|
||
String requestPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||
String fileName = cleanStoredPath(requestPath);
|
||
if (!StringUtils.hasText(fileName))
|
||
{
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
Path normalizedRoot = uploadRoot.toAbsolutePath().normalize();
|
||
Path filePath = normalizedRoot.resolve(fileName).normalize();
|
||
if (!filePath.startsWith(normalizedRoot))
|
||
{
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
|
||
Resource resource = new UrlResource(filePath.toUri());
|
||
if (!resource.exists())
|
||
{
|
||
return ResponseEntity.notFound().build();
|
||
}
|
||
return ResponseEntity.ok()
|
||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\\"" + resource.getFilename() + "\\"")
|
||
.body(resource);
|
||
}
|
||
|
||
private String cleanStoredPath(String requestPath)
|
||
{
|
||
String storedPath = requestPath == null ? "" : requestPath;
|
||
if (storedPath.startsWith("/files/"))
|
||
{
|
||
storedPath = storedPath.substring("/files/".length());
|
||
}
|
||
else if (storedPath.startsWith("/files"))
|
||
{
|
||
storedPath = storedPath.substring("/files".length());
|
||
}
|
||
while (storedPath.startsWith("/"))
|
||
{
|
||
storedPath = storedPath.substring(1);
|
||
}
|
||
storedPath = StringUtils.cleanPath(storedPath);
|
||
return storedPath.contains("..") ? "" : storedPath;
|
||
}
|
||
}
|
||
|
||
', 'admin', sysdate()),
|
||
(920108, 9201, 'application.yml.vm', NULL, 'application.yml.vm', '#set($d = ''$'')
|
||
server:
|
||
port: ${d}{SERVER_PORT:8080}
|
||
|
||
spring:
|
||
application:
|
||
name: ${businessName}-service
|
||
datasource:
|
||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||
url: ${d}{DB_URL:jdbc:mysql://localhost:3306/vip?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8}
|
||
username: ${d}{DB_USERNAME:root}
|
||
password: ${d}{DB_PASSWORD:123456}
|
||
servlet:
|
||
multipart:
|
||
max-file-size: 100MB
|
||
max-request-size: 100MB
|
||
|
||
mybatis-plus:
|
||
mapper-locations: classpath*:mapper/**/*.xml
|
||
configuration:
|
||
map-underscore-to-camel-case: true
|
||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||
', 'admin', sysdate()),
|
||
(920109, 9201, 'entity.java.vm', NULL, 'entity.java.vm', 'package ${packageName}.entity;
|
||
|
||
#foreach ($import in $importList)
|
||
import ${import};
|
||
#end
|
||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||
import com.baomidou.mybatisplus.annotation.TableName;
|
||
import com.baomidou.mybatisplus.annotation.IdType;
|
||
import com.baomidou.mybatisplus.annotation.TableId;
|
||
import com.baomidou.mybatisplus.annotation.TableField;
|
||
import io.swagger.annotations.ApiModel;
|
||
import io.swagger.annotations.ApiModelProperty;
|
||
import lombok.Getter;
|
||
import lombok.Setter;
|
||
import lombok.experimental.Accessors;
|
||
import cn.hutool.core.annotation.Alias;
|
||
|
||
/**
|
||
* ${functionName}对象 ${tableName}
|
||
*
|
||
* @author ${author}
|
||
* @date ${datetime}
|
||
*/
|
||
#if($table.crud || $table.sub)
|
||
#set($Entity="BaseEntity")
|
||
#elseif($table.tree)
|
||
#set($Entity="TreeEntity")
|
||
#end
|
||
@Getter
|
||
@Setter
|
||
@Accessors(chain = true)
|
||
@ApiModel(value = "${ClassName}对象", description = "${functionName}")
|
||
@TableName("${tableName}")
|
||
public class ${ClassName}
|
||
{
|
||
private static final long serialVersionUID = 1L;
|
||
|
||
#foreach ($column in $columns)
|
||
/** $column.columnComment */
|
||
#if($column.list)
|
||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||
#if($parentheseIndex != -1)
|
||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||
#else
|
||
#set($comment=$column.columnComment)
|
||
#end
|
||
#if($column.javaType == ''Date'')
|
||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||
#else
|
||
#end
|
||
#end
|
||
@ApiModelProperty("${column.columnComment}")
|
||
@Alias("${column.columnComment}")
|
||
#if ($column.isPk == "1")
|
||
@TableId(value = "${column.columnName}", type = IdType.AUTO)
|
||
#else
|
||
@TableField("${column.columnName}")
|
||
#end
|
||
private $column.javaType $column.javaField;
|
||
|
||
#end
|
||
#if($table.sub)
|
||
/** $table.subTable.functionName信息 */
|
||
@ApiModelProperty("${table.subTable.functionName}信息")
|
||
private List<${subClassName}> ${subclassName}List;
|
||
|
||
#end
|
||
@Override
|
||
public String toString() {
|
||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||
#foreach ($column in $columns)
|
||
#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
|
||
#set($AttrName=$column.javaField)
|
||
#else
|
||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||
#end
|
||
.append("${column.javaField}", get${AttrName}())
|
||
#end
|
||
#if($table.sub)
|
||
.append("${subclassName}List", get${subClassName}List())
|
||
#end
|
||
.toString();
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920110, 9201, 'mapper.java.vm', NULL, 'mapper.java.vm', 'package ${packageName}.mapper;
|
||
|
||
import ${packageName}.entity.${ClassName};
|
||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||
import org.apache.ibatis.annotations.Param;
|
||
import org.apache.ibatis.annotations.Select;
|
||
|
||
/**
|
||
* ${functionName}Mapper接口
|
||
*
|
||
* @author ${author}
|
||
* @date ${datetime}
|
||
*/
|
||
public interface ${ClassName}Mapper extends BaseMapper<${ClassName}> {
|
||
|
||
@Select("select * from ${tableName} where ${pkColumn.columnName} = #{id} for update")
|
||
${ClassName} selectByIdForUpdate(@Param("id") ${pkColumn.javaType} id);
|
||
|
||
}
|
||
|
||
', 'admin', sysdate()),
|
||
(920111, 9201, 'service.java.vm', NULL, 'service.java.vm', 'package ${packageName}.service;
|
||
|
||
import ${packageName}.entity.${ClassName};
|
||
import com.baomidou.mybatisplus.extension.service.IService;
|
||
|
||
/**
|
||
* ${functionName}Service接口
|
||
*
|
||
* @author ${author}
|
||
* @date ${datetime}
|
||
*/
|
||
public interface I${ClassName}Service extends IService<${ClassName}> {
|
||
|
||
#if($hasTypedBusinessActions)
|
||
#foreach($action in $typedBusinessActions)
|
||
void ${action.javaMethodName}(${action.serviceParameters});
|
||
|
||
#end
|
||
#end
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920112, 9201, 'serviceImpl.java.vm', NULL, 'serviceImpl.java.vm', 'package ${packageName}.service.impl;
|
||
|
||
import ${packageName}.entity.${ClassName};
|
||
import ${packageName}.mapper.${ClassName}Mapper;
|
||
import ${packageName}.service.I${ClassName}Service;
|
||
#if($hasTypedBusinessActions)
|
||
#foreach($dependency in $typedBusinessDependencies)
|
||
#if($dependency.className != $ClassName)
|
||
import ${packageName}.entity.${dependency.className};
|
||
import ${packageName}.mapper.${dependency.className}Mapper;
|
||
#end
|
||
#end
|
||
#if($typedBusinessUsesBigDecimal)
|
||
import java.math.BigDecimal;
|
||
#end
|
||
#if($typedBusinessUsesDate)
|
||
import java.util.Date;
|
||
#end
|
||
import javax.annotation.Resource;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
#end
|
||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
/**
|
||
* ${functionName}Service业务层处理
|
||
*
|
||
* @author ${author}
|
||
* @date ${datetime}
|
||
*/
|
||
@Service
|
||
public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}>
|
||
implements I${ClassName}Service
|
||
{
|
||
#if($hasTypedBusinessActions)
|
||
#foreach($dependency in $typedBusinessDependencies)
|
||
@Resource
|
||
private ${dependency.className}Mapper ${dependency.mapperField};
|
||
|
||
#end
|
||
#foreach($action in $typedBusinessActions)
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void ${action.javaMethodName}(${action.serviceParameters})
|
||
{
|
||
${action.recordClass} ${action.recordVariable} = ${action.ownerMapperField}.selectByIdForUpdate(${action.pkField});
|
||
if (${action.recordVariable} == null)
|
||
{
|
||
throw new IllegalArgumentException("${action.notFoundMessage}");
|
||
}
|
||
#if($action.stateTransition)
|
||
if (!"${action.fromState}".equals(${action.recordVariable}.${action.statusGetter}()))
|
||
{
|
||
throw new IllegalArgumentException("${action.invalidStateMessage}");
|
||
}
|
||
#end
|
||
|
||
#foreach($effect in $action.effects)
|
||
#if($effect.type == "create_record")
|
||
${effect.entityClass} ${effect.variable} = new ${effect.entityClass}();
|
||
#foreach($assignment in $effect.assignments)
|
||
${effect.variable}.${assignment.setter}(${assignment.expression});
|
||
#end
|
||
${effect.mapperField}.insert(${effect.variable});
|
||
#else
|
||
${effect.entityClass} ${effect.variable} = ${effect.mapperField}.selectByIdForUpdate(
|
||
${action.recordVariable}.${effect.relationGetter}());
|
||
if (${effect.variable} == null)
|
||
{
|
||
throw new IllegalArgumentException("${effect.notFoundMessage}");
|
||
}
|
||
#if($effect.guardExpression)
|
||
if (${effect.guardExpression})
|
||
{
|
||
throw new IllegalArgumentException("${effect.errorMessage}");
|
||
}
|
||
#end
|
||
#if($effect.type == "decrease" || $effect.type == "increase")
|
||
${effect.variable}.${effect.setter}(${effect.valueExpression});
|
||
#else
|
||
#foreach($assignment in $effect.assignments)
|
||
${effect.variable}.${assignment.setter}(${assignment.expression});
|
||
#end
|
||
#end
|
||
${effect.mapperField}.updateById(${effect.variable});
|
||
#end
|
||
|
||
#end
|
||
#if($action.stateTransition)
|
||
${action.recordVariable}.${action.statusSetter}("${action.toState}");
|
||
#if($action.auditUserSetter)
|
||
${action.recordVariable}.${action.auditUserSetter}(currentUserId);
|
||
#end
|
||
#if($action.auditTimeSetter)
|
||
${action.recordVariable}.${action.auditTimeSetter}(new Date());
|
||
#end
|
||
${action.ownerMapperField}.updateById(${action.recordVariable});
|
||
#end
|
||
}
|
||
|
||
#end
|
||
#end
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920113, 9201, 'controller.java.vm', NULL, 'controller.java.vm', 'package ${packageName}.controller;
|
||
|
||
import cn.hutool.poi.excel.ExcelReader;
|
||
import cn.hutool.poi.excel.ExcelUtil;
|
||
import cn.hutool.poi.excel.ExcelWriter;
|
||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import ${packageName}.common.Result;
|
||
import ${packageName}.entity.${ClassName};
|
||
#if($hasQingCurrentUserColumn || $hasTypedBusinessActions)
|
||
import ${packageName}.security.AuthPrincipal;
|
||
import ${packageName}.security.PortalAuthTokenStore;
|
||
#end
|
||
import ${packageName}.service.I${ClassName}Service;
|
||
import java.io.InputStream;
|
||
import java.net.URLEncoder;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import javax.annotation.Resource;
|
||
import javax.servlet.ServletOutputStream;
|
||
#if($hasQingCurrentUserColumn || $hasTypedBusinessActions)
|
||
import javax.servlet.http.HttpServletRequest;
|
||
#end
|
||
import javax.servlet.http.HttpServletResponse;
|
||
import org.apache.commons.lang3.StringUtils;
|
||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PathVariable;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
|
||
/** ${functionName}Controller */
|
||
@RestController
|
||
public class ${ClassName}Controller
|
||
{
|
||
@Resource
|
||
private I${ClassName}Service ${className}Service;
|
||
|
||
#if($hasQingCurrentUserColumn || $hasTypedBusinessActions)
|
||
@Resource
|
||
private PortalAuthTokenStore tokenStore;
|
||
|
||
#end
|
||
#if($allowAdd == ''1'' || $allowEdit == ''1'')
|
||
@PostMapping("${requestPath}")
|
||
public Result<Void> save(@RequestBody ${ClassName} ${className})
|
||
{
|
||
#if($allowAdd == ''1'' && $allowEdit == ''1'')
|
||
${className}Service.saveOrUpdate(${className});
|
||
#elseif($allowAdd == ''1'')
|
||
${className}Service.save(${className});
|
||
#else
|
||
${className}Service.updateById(${className});
|
||
#end
|
||
return Result.success();
|
||
}
|
||
#end
|
||
|
||
#if($allowRemove == ''1'')
|
||
@DeleteMapping("${requestPath}/{${pkColumn.javaField}}")
|
||
public Result<Void> delete(@PathVariable ${pkColumn.javaType} ${pkColumn.javaField})
|
||
{
|
||
${className}Service.removeById(${pkColumn.javaField});
|
||
return Result.success();
|
||
}
|
||
|
||
@PostMapping("${requestPath}/del/batch")
|
||
public Result<Void> deleteBatch(@RequestBody List<${pkColumn.javaType}> ${pkColumn.javaField}s)
|
||
{
|
||
${className}Service.removeByIds(${pkColumn.javaField}s);
|
||
return Result.success();
|
||
}
|
||
#end
|
||
|
||
@GetMapping("${requestPath}")
|
||
public Result<List<${ClassName}>> findAll()
|
||
{
|
||
return Result.success(${className}Service.list());
|
||
}
|
||
|
||
@GetMapping("${requestPath}/{${pkColumn.javaField}}")
|
||
public Result<${ClassName}> findOne(@PathVariable ${pkColumn.javaType} ${pkColumn.javaField})
|
||
{
|
||
return Result.success(${className}Service.getById(${pkColumn.javaField}));
|
||
}
|
||
|
||
@GetMapping("${requestPath}/page")
|
||
public Result<Page<${ClassName}>> findPage(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
||
@RequestParam(required = false, defaultValue = "10") Integer pageSize,
|
||
@RequestParam(required = false) Map<String, Object> params#if($hasQingCurrentUserColumn),
|
||
HttpServletRequest request#end)
|
||
{
|
||
QueryWrapper<${ClassName}> queryWrapper = new QueryWrapper<${ClassName}>();
|
||
#if($hasQingCurrentUserColumn)
|
||
if (isCurrentUserOnly(params))
|
||
{
|
||
AuthPrincipal currentUser = tokenStore.getPortalPrincipal(resolveToken(request));
|
||
if (currentUser == null)
|
||
{
|
||
return Result.success(new Page<${ClassName}>(pageNum, pageSize));
|
||
}
|
||
queryWrapper.eq("${qingCurrentUserColumn.columnName}", currentUser.getUserId());
|
||
}
|
||
#end
|
||
#foreach($column in $columns)
|
||
#if($column.isQuery == "1")
|
||
#if($column.queryType == "NE")
|
||
queryWrapper.ne(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#elseif($column.queryType == "GT")
|
||
queryWrapper.gt(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#elseif($column.queryType == "GTE")
|
||
queryWrapper.ge(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#elseif($column.queryType == "LT")
|
||
queryWrapper.lt(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#elseif($column.queryType == "LTE")
|
||
queryWrapper.le(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#elseif($column.queryType == "LIKE")
|
||
queryWrapper.like(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#else
|
||
queryWrapper.eq(hasValue(params.get("${column.javaField}")), "${column.columnName}", params.get("${column.javaField}"));
|
||
#end
|
||
#end
|
||
#end
|
||
queryWrapper.orderByDesc("${pkColumn.columnName}");
|
||
return Result.success(${className}Service.page(new Page<${ClassName}>(pageNum, pageSize), queryWrapper));
|
||
}
|
||
|
||
@GetMapping("${requestPath}/export")
|
||
public void export(HttpServletResponse response) throws Exception
|
||
{
|
||
List<${ClassName}> list = ${className}Service.list();
|
||
ExcelWriter writer = ExcelUtil.getWriter(true);
|
||
writer.write(list, true);
|
||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
|
||
String fileName = URLEncoder.encode("${functionName}信息表", "UTF-8");
|
||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
|
||
ServletOutputStream out = response.getOutputStream();
|
||
writer.flush(out, true);
|
||
out.close();
|
||
writer.close();
|
||
}
|
||
|
||
#if($allowAdd == ''1'')
|
||
@PostMapping("${requestPath}/import")
|
||
public Result<Void> imp(MultipartFile file) throws Exception
|
||
{
|
||
InputStream inputStream = file.getInputStream();
|
||
ExcelReader reader = ExcelUtil.getReader(inputStream);
|
||
List<${ClassName}> list = reader.readAll(${ClassName}.class);
|
||
${className}Service.saveBatch(list);
|
||
return Result.success();
|
||
}
|
||
#end
|
||
|
||
#if($hasTypedBusinessActions)
|
||
#foreach($action in $typedBusinessActions)
|
||
#if($action.method == "GET")
|
||
@GetMapping("${action.path}")
|
||
public Result<Void> ${action.javaMethodName}(@RequestParam Map<String, Object> params, HttpServletRequest request)
|
||
#elseif($action.method == "PUT")
|
||
@org.springframework.web.bind.annotation.PutMapping("${action.path}")
|
||
public Result<Void> ${action.javaMethodName}(@RequestBody Map<String, Object> params, HttpServletRequest request)
|
||
#elseif($action.method == "DELETE")
|
||
@DeleteMapping("${action.path}")
|
||
public Result<Void> ${action.javaMethodName}(@RequestBody Map<String, Object> params, HttpServletRequest request)
|
||
#else
|
||
@PostMapping("${action.path}")
|
||
public Result<Void> ${action.javaMethodName}(@RequestBody Map<String, Object> params, HttpServletRequest request)
|
||
#end
|
||
{
|
||
try
|
||
{
|
||
if (params == null || params.get("${action.pkField}") == null)
|
||
{
|
||
throw new IllegalArgumentException("缺少业务动作参数: ${action.pkField}");
|
||
}
|
||
AuthPrincipal currentUser = requireCurrentUser(request);
|
||
${action.pkType} ${action.pkField} = ${action.controllerIdExpression};
|
||
${className}Service.${action.javaMethodName}(${action.serviceArguments});
|
||
return Result.success();
|
||
}
|
||
catch (RuntimeException e)
|
||
{
|
||
return Result.error(e.getMessage());
|
||
}
|
||
}
|
||
|
||
#end
|
||
private AuthPrincipal requireCurrentUser(HttpServletRequest request)
|
||
{
|
||
AuthPrincipal currentUser = tokenStore.getPortalPrincipal(resolveToken(request));
|
||
if (currentUser == null)
|
||
{
|
||
throw new IllegalArgumentException("请先登录");
|
||
}
|
||
return currentUser;
|
||
}
|
||
#end
|
||
|
||
private boolean hasValue(Object value)
|
||
{
|
||
return value != null && StringUtils.isNotBlank(String.valueOf(value));
|
||
}
|
||
|
||
#if($hasQingCurrentUserColumn)
|
||
private boolean isCurrentUserOnly(Map<String, Object> params)
|
||
{
|
||
return params != null && "true".equalsIgnoreCase(String.valueOf(params.get("__currentUserOnly")));
|
||
}
|
||
#end
|
||
|
||
#if($hasQingCurrentUserColumn || $hasTypedBusinessActions)
|
||
private String resolveToken(HttpServletRequest request)
|
||
{
|
||
String authorization = request.getHeader("Authorization");
|
||
if (authorization != null && authorization.startsWith("Bearer "))
|
||
{
|
||
return authorization.substring("Bearer ".length());
|
||
}
|
||
return request.getHeader("X-Portal-Token");
|
||
}
|
||
#end
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920114, 9201, 'mapper.xml.vm', NULL, 'mapper.xml.vm', '<?xml version="1.0" encoding="UTF-8" ?>
|
||
<!DOCTYPE mapper
|
||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||
<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
|
||
|
||
<!-- 通用查询映射结果 -->
|
||
<resultMap type="${packageName}.entity.${ClassName}" id="BaseResultMap">
|
||
#foreach ($column in $columns)
|
||
#if ($column.isPk == "1")
|
||
<id column="${column.columnName}" property="${column.javaField}"/>
|
||
#else
|
||
<result column="${column.columnName}" property="${column.javaField}"/>
|
||
#end
|
||
#end
|
||
</resultMap>
|
||
|
||
<!-- 通用查询结果列 -->
|
||
<sql id="Base_Column_List">
|
||
#foreach ($column in $columns)
|
||
${column.columnName}#if($foreach.count != $columns.size()),#end
|
||
|
||
#end
|
||
</sql>
|
||
|
||
</mapper>
|
||
', 'admin', sysdate()),
|
||
(920115, 9201, 'sql.vm', NULL, 'sql.vm', '-- ${functionName} table
|
||
-- Generated by qing template at ${datetime}
|
||
|
||
${table.createTableSql}
|
||
', 'admin', sysdate()),
|
||
(920116, 9201, 'AuthPrincipal.java.vm', NULL, 'AuthPrincipal.java.vm', 'package ${packageName}.security;
|
||
|
||
public class AuthPrincipal
|
||
{
|
||
private Long userId;
|
||
private String account;
|
||
private String displayName;
|
||
private String roleCode;
|
||
private String roleName;
|
||
private String loginSide;
|
||
private String tableName;
|
||
|
||
public Long getUserId() { return userId; }
|
||
public void setUserId(Long userId) { this.userId = userId; }
|
||
public String getAccount() { return account; }
|
||
public void setAccount(String account) { this.account = account; }
|
||
public String getDisplayName() { return displayName; }
|
||
public void setDisplayName(String displayName) { this.displayName = displayName; }
|
||
public String getRoleCode() { return roleCode; }
|
||
public void setRoleCode(String roleCode) { this.roleCode = roleCode; }
|
||
public String getRoleName() { return roleName; }
|
||
public void setRoleName(String roleName) { this.roleName = roleName; }
|
||
public String getLoginSide() { return loginSide; }
|
||
public void setLoginSide(String loginSide) { this.loginSide = loginSide; }
|
||
public String getTableName() { return tableName; }
|
||
public void setTableName(String tableName) { this.tableName = tableName; }
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920118, 9201, 'PortalAuthTokenStore.java.vm', NULL, 'PortalAuthTokenStore.java.vm', 'package ${packageName}.security;
|
||
|
||
import java.util.Map;
|
||
import java.util.UUID;
|
||
import java.util.concurrent.ConcurrentHashMap;
|
||
import org.springframework.stereotype.Component;
|
||
|
||
@Component
|
||
public class PortalAuthTokenStore
|
||
{
|
||
private static final String LOGIN_SIDE_PORTAL = "PORTAL";
|
||
private static final String LOGIN_SIDE_ADMIN = "ADMIN";
|
||
|
||
private final Map<String, AuthPrincipal> sessions = new ConcurrentHashMap<String, AuthPrincipal>();
|
||
|
||
public String issue(AuthPrincipal principal)
|
||
{
|
||
String token = UUID.randomUUID().toString().replace("-", "");
|
||
sessions.put(token, principal);
|
||
return token;
|
||
}
|
||
|
||
public AuthPrincipal getPrincipal(String token)
|
||
{
|
||
if (token == null || token.trim().isEmpty())
|
||
{
|
||
return null;
|
||
}
|
||
return sessions.get(token);
|
||
}
|
||
|
||
public AuthPrincipal getPortalPrincipal(String token)
|
||
{
|
||
AuthPrincipal principal = getPrincipal(token);
|
||
return principal != null && LOGIN_SIDE_PORTAL.equals(principal.getLoginSide()) ? principal : null;
|
||
}
|
||
|
||
public AuthPrincipal getAdminPrincipal(String token)
|
||
{
|
||
AuthPrincipal principal = getPrincipal(token);
|
||
return principal != null && LOGIN_SIDE_ADMIN.equals(principal.getLoginSide()) ? principal : null;
|
||
}
|
||
|
||
public boolean validate(String token)
|
||
{
|
||
return getPrincipal(token) != null;
|
||
}
|
||
|
||
public void revoke(String token)
|
||
{
|
||
if (token != null)
|
||
{
|
||
sessions.remove(token);
|
||
}
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920119, 9201, 'PortalAuthInterceptor.java.vm', NULL, 'PortalAuthInterceptor.java.vm', 'package ${packageName}.security;
|
||
|
||
import java.io.IOException;
|
||
import javax.annotation.Resource;
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import javax.servlet.http.HttpServletResponse;
|
||
import org.springframework.stereotype.Component;
|
||
import org.springframework.web.servlet.HandlerInterceptor;
|
||
|
||
@Component
|
||
public class PortalAuthInterceptor implements HandlerInterceptor
|
||
{
|
||
@Resource
|
||
private PortalAuthTokenStore tokenStore;
|
||
|
||
@Override
|
||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||
throws IOException
|
||
{
|
||
if ("OPTIONS".equalsIgnoreCase(request.getMethod()))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
String token = resolveToken(request);
|
||
if (tokenStore.validate(token))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
response.setStatus(401);
|
||
response.setCharacterEncoding("UTF-8");
|
||
response.setContentType("application/json;charset=UTF-8");
|
||
response.getWriter().write("{\\"code\\":\\"401\\",\\"msg\\":\\"请先登录\\",\\"data\\":null}");
|
||
return false;
|
||
}
|
||
|
||
private String resolveToken(HttpServletRequest request)
|
||
{
|
||
String authorization = request.getHeader("Authorization");
|
||
if (authorization != null && authorization.startsWith("Bearer "))
|
||
{
|
||
return authorization.substring("Bearer ".length());
|
||
}
|
||
return request.getHeader("X-Portal-Token");
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920120, 9201, 'PortalAuthController.java.vm', NULL, 'PortalAuthController.java.vm', 'package ${packageName}.controller;
|
||
|
||
import ${packageName}.common.Result;
|
||
import ${packageName}.security.AuthPrincipal;
|
||
import ${packageName}.security.PortalAuthTokenStore;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.security.MessageDigest;
|
||
import java.util.HashMap;
|
||
import java.util.LinkedHashMap;
|
||
import java.util.Map;
|
||
import javax.annotation.Resource;
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import org.springframework.dao.EmptyResultDataAccessException;
|
||
import org.springframework.jdbc.core.JdbcTemplate;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
@RestController
|
||
@RequestMapping("/auth")
|
||
public class PortalAuthController
|
||
{
|
||
private static final String LOGIN_SIDE_PORTAL = "PORTAL";
|
||
|
||
private static final Map<String, AuthBinding> ROLE_BINDINGS = new LinkedHashMap<String, AuthBinding>();
|
||
|
||
static
|
||
{
|
||
#foreach($binding in $portalAuthBindings)
|
||
ROLE_BINDINGS.put("${binding.roleCodeLiteral}", new AuthBinding("${binding.roleCodeLiteral}", "${binding.roleNameLiteral}",
|
||
"${binding.tableNameLiteral}", "${binding.idColumnLiteral}", "${binding.accountColumnLiteral}",
|
||
"${binding.passwordColumnLiteral}", "${binding.displayNameColumnLiteral}", "${binding.statusColumnLiteral}"));
|
||
#end
|
||
}
|
||
|
||
@Resource
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
@Resource
|
||
private PortalAuthTokenStore tokenStore;
|
||
|
||
@PostMapping("/login")
|
||
public Result<Map<String, Object>> login(@RequestBody LoginBody body)
|
||
{
|
||
String account = body == null ? null : firstNonBlank(body.getAccount(), body.getUsername());
|
||
String password = body == null ? null : body.getPassword();
|
||
AuthBinding binding = resolveBinding(body == null ? null : body.getRoleCode());
|
||
if (isBlank(account) || isBlank(password))
|
||
{
|
||
return Result.error("请输入账号和密码");
|
||
}
|
||
if (binding == null)
|
||
{
|
||
return Result.error("请选择可登录角色");
|
||
}
|
||
|
||
AuthLoginCandidate candidate = findPrincipal(binding, account);
|
||
if (candidate == null)
|
||
{
|
||
return Result.error("账号或密码错误");
|
||
}
|
||
|
||
if (!passwordHash(password).equalsIgnoreCase(candidate.getPasswordHash()))
|
||
{
|
||
return Result.error("账号或密码错误");
|
||
}
|
||
|
||
AuthPrincipal principal = candidate.getPrincipal();
|
||
String token = tokenStore.issue(principal);
|
||
Map<String, Object> data = new HashMap<String, Object>();
|
||
data.put("token", token);
|
||
data.put("user", principal);
|
||
return Result.success(data);
|
||
}
|
||
|
||
@GetMapping("/me")
|
||
public Result<AuthPrincipal> me(HttpServletRequest request)
|
||
{
|
||
AuthPrincipal principal = tokenStore.getPortalPrincipal(resolveToken(request));
|
||
if (principal == null)
|
||
{
|
||
return Result.error("请先登录");
|
||
}
|
||
return Result.success(principal);
|
||
}
|
||
|
||
@PostMapping("/logout")
|
||
public Result<Void> logout(HttpServletRequest request)
|
||
{
|
||
tokenStore.revoke(resolveToken(request));
|
||
return Result.success();
|
||
}
|
||
|
||
private AuthBinding resolveBinding(String roleCode)
|
||
{
|
||
if (ROLE_BINDINGS.isEmpty())
|
||
{
|
||
return null;
|
||
}
|
||
if (!isBlank(roleCode))
|
||
{
|
||
return ROLE_BINDINGS.get(roleCode);
|
||
}
|
||
return ROLE_BINDINGS.size() == 1 ? ROLE_BINDINGS.values().iterator().next() : null;
|
||
}
|
||
|
||
private AuthLoginCandidate findPrincipal(AuthBinding binding, String account)
|
||
{
|
||
String sql = "select `" + binding.getIdColumn() + "` as user_id, `"
|
||
+ binding.getAccountColumn() + "` as account, `"
|
||
+ binding.getPasswordColumn() + "` as password_hash, `"
|
||
+ binding.getDisplayNameColumn() + "` as display_name, `"
|
||
+ binding.getStatusColumn() + "` as status from `"
|
||
+ binding.getTableName() + "` where `"
|
||
+ binding.getAccountColumn() + "` = ? and `"
|
||
+ binding.getStatusColumn() + "` = ''0'' limit 1";
|
||
try
|
||
{
|
||
Map<String, Object> row = jdbcTemplate.queryForMap(sql, account);
|
||
AuthPrincipal principal = new AuthPrincipal();
|
||
principal.setUserId(toLong(row.get("user_id")));
|
||
principal.setAccount(stringValue(row.get("account")));
|
||
principal.setDisplayName(firstNonBlank(stringValue(row.get("display_name")), principal.getAccount()));
|
||
principal.setRoleCode(binding.getRoleCode());
|
||
principal.setRoleName(binding.getRoleName());
|
||
principal.setLoginSide(LOGIN_SIDE_PORTAL);
|
||
principal.setTableName(binding.getTableName());
|
||
return new AuthLoginCandidate(principal, stringValue(row.get("password_hash")));
|
||
}
|
||
catch (EmptyResultDataAccessException e)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private String resolveToken(HttpServletRequest request)
|
||
{
|
||
String authorization = request.getHeader("Authorization");
|
||
if (authorization != null && authorization.startsWith("Bearer "))
|
||
{
|
||
return authorization.substring("Bearer ".length());
|
||
}
|
||
return request.getHeader("X-Portal-Token");
|
||
}
|
||
|
||
private String passwordHash(String password)
|
||
{
|
||
try
|
||
{
|
||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
|
||
StringBuilder builder = new StringBuilder();
|
||
for (byte item : hash)
|
||
{
|
||
builder.append(String.format("%02x", item));
|
||
}
|
||
return builder.toString();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
throw new IllegalStateException("Password hash failed", e);
|
||
}
|
||
}
|
||
|
||
private Long toLong(Object value)
|
||
{
|
||
if (value instanceof Number)
|
||
{
|
||
return ((Number) value).longValue();
|
||
}
|
||
if (value == null)
|
||
{
|
||
return null;
|
||
}
|
||
return Long.valueOf(String.valueOf(value));
|
||
}
|
||
|
||
private String stringValue(Object value)
|
||
{
|
||
return value == null ? "" : String.valueOf(value);
|
||
}
|
||
|
||
private String firstNonBlank(String first, String second)
|
||
{
|
||
return isBlank(first) ? second : first;
|
||
}
|
||
|
||
private boolean isBlank(String value)
|
||
{
|
||
return value == null || value.trim().isEmpty();
|
||
}
|
||
|
||
public static class LoginBody
|
||
{
|
||
private String roleCode;
|
||
private String account;
|
||
private String username;
|
||
private String password;
|
||
|
||
public String getRoleCode()
|
||
{
|
||
return roleCode;
|
||
}
|
||
|
||
public void setRoleCode(String roleCode)
|
||
{
|
||
this.roleCode = roleCode;
|
||
}
|
||
|
||
public String getAccount()
|
||
{
|
||
return account;
|
||
}
|
||
|
||
public void setAccount(String account)
|
||
{
|
||
this.account = account;
|
||
}
|
||
|
||
public String getUsername()
|
||
{
|
||
return username;
|
||
}
|
||
|
||
public void setUsername(String username)
|
||
{
|
||
this.username = username;
|
||
}
|
||
|
||
public String getPassword()
|
||
{
|
||
return password;
|
||
}
|
||
|
||
public void setPassword(String password)
|
||
{
|
||
this.password = password;
|
||
}
|
||
}
|
||
|
||
private static class AuthBinding
|
||
{
|
||
private final String roleCode;
|
||
private final String roleName;
|
||
private final String tableName;
|
||
private final String idColumn;
|
||
private final String accountColumn;
|
||
private final String passwordColumn;
|
||
private final String displayNameColumn;
|
||
private final String statusColumn;
|
||
|
||
private AuthBinding(String roleCode, String roleName, String tableName, String idColumn, String accountColumn,
|
||
String passwordColumn, String displayNameColumn, String statusColumn)
|
||
{
|
||
this.roleCode = roleCode;
|
||
this.roleName = roleName;
|
||
this.tableName = tableName;
|
||
this.idColumn = idColumn;
|
||
this.accountColumn = accountColumn;
|
||
this.passwordColumn = passwordColumn;
|
||
this.displayNameColumn = displayNameColumn;
|
||
this.statusColumn = statusColumn;
|
||
}
|
||
|
||
public String getRoleCode() { return roleCode; }
|
||
public String getRoleName() { return roleName; }
|
||
public String getTableName() { return tableName; }
|
||
public String getIdColumn() { return idColumn; }
|
||
public String getAccountColumn() { return accountColumn; }
|
||
public String getPasswordColumn() { return passwordColumn; }
|
||
public String getDisplayNameColumn() { return displayNameColumn; }
|
||
public String getStatusColumn() { return statusColumn; }
|
||
}
|
||
|
||
private static class AuthLoginCandidate
|
||
{
|
||
private final AuthPrincipal principal;
|
||
private final String passwordHash;
|
||
|
||
private AuthLoginCandidate(AuthPrincipal principal, String passwordHash)
|
||
{
|
||
this.principal = principal;
|
||
this.passwordHash = passwordHash;
|
||
}
|
||
|
||
public AuthPrincipal getPrincipal()
|
||
{
|
||
return principal;
|
||
}
|
||
|
||
public String getPasswordHash()
|
||
{
|
||
return passwordHash;
|
||
}
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920123, 9201, 'AdminAuthController.java.vm', NULL, 'AdminAuthController.java.vm', 'package ${packageName}.controller;
|
||
|
||
import ${packageName}.common.Result;
|
||
import ${packageName}.security.AuthPrincipal;
|
||
import ${packageName}.security.PortalAuthTokenStore;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.security.MessageDigest;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
import javax.annotation.Resource;
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import org.springframework.dao.EmptyResultDataAccessException;
|
||
import org.springframework.jdbc.core.JdbcTemplate;
|
||
import org.springframework.web.bind.annotation.GetMapping;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestBody;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
|
||
@RestController
|
||
@RequestMapping("/auth/admin")
|
||
public class AdminAuthController
|
||
{
|
||
private static final String LOGIN_SIDE_ADMIN = "ADMIN";
|
||
private static final String ROLE_CODE = "${adminAuthBinding.roleCodeLiteral}";
|
||
private static final String ROLE_NAME = "${adminAuthBinding.roleNameLiteral}";
|
||
private static final String TABLE_NAME = "${adminAuthBinding.tableNameLiteral}";
|
||
private static final String ID_COLUMN = "${adminAuthBinding.idColumnLiteral}";
|
||
private static final String ACCOUNT_COLUMN = "${adminAuthBinding.accountColumnLiteral}";
|
||
private static final String PASSWORD_COLUMN = "${adminAuthBinding.passwordColumnLiteral}";
|
||
private static final String DISPLAY_NAME_COLUMN = "${adminAuthBinding.displayNameColumnLiteral}";
|
||
private static final String STATUS_COLUMN = "${adminAuthBinding.statusColumnLiteral}";
|
||
|
||
@Resource
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
@Resource
|
||
private PortalAuthTokenStore tokenStore;
|
||
|
||
@PostMapping("/login")
|
||
public Result<Map<String, Object>> login(@RequestBody LoginBody body)
|
||
{
|
||
String account = body == null ? null : firstNonBlank(body.getAccount(), body.getUsername());
|
||
String password = body == null ? null : body.getPassword();
|
||
if (isBlank(account) || isBlank(password))
|
||
{
|
||
return Result.error("请输入账号和密码");
|
||
}
|
||
|
||
AuthLoginCandidate candidate = findPrincipal(account);
|
||
if (candidate == null)
|
||
{
|
||
return Result.error("账号或密码错误");
|
||
}
|
||
|
||
if (!passwordHash(password).equalsIgnoreCase(candidate.getPasswordHash()))
|
||
{
|
||
return Result.error("账号或密码错误");
|
||
}
|
||
|
||
AuthPrincipal principal = candidate.getPrincipal();
|
||
String token = tokenStore.issue(principal);
|
||
Map<String, Object> data = new HashMap<String, Object>();
|
||
data.put("token", token);
|
||
data.put("user", principal);
|
||
return Result.success(data);
|
||
}
|
||
|
||
@GetMapping("/me")
|
||
public Result<AuthPrincipal> me(HttpServletRequest request)
|
||
{
|
||
AuthPrincipal principal = tokenStore.getAdminPrincipal(resolveToken(request));
|
||
if (principal == null)
|
||
{
|
||
return Result.error("请先登录");
|
||
}
|
||
return Result.success(principal);
|
||
}
|
||
|
||
@PostMapping("/logout")
|
||
public Result<Void> logout(HttpServletRequest request)
|
||
{
|
||
tokenStore.revoke(resolveToken(request));
|
||
return Result.success();
|
||
}
|
||
|
||
private AuthLoginCandidate findPrincipal(String account)
|
||
{
|
||
String sql = "select `" + ID_COLUMN + "` as user_id, `"
|
||
+ ACCOUNT_COLUMN + "` as account, `"
|
||
+ PASSWORD_COLUMN + "` as password_hash, `"
|
||
+ DISPLAY_NAME_COLUMN + "` as display_name, `"
|
||
+ STATUS_COLUMN + "` as status from `"
|
||
+ TABLE_NAME + "` where `"
|
||
+ ACCOUNT_COLUMN + "` = ? and `"
|
||
+ STATUS_COLUMN + "` = ''0'' limit 1";
|
||
try
|
||
{
|
||
Map<String, Object> row = jdbcTemplate.queryForMap(sql, account);
|
||
AuthPrincipal principal = new AuthPrincipal();
|
||
principal.setUserId(toLong(row.get("user_id")));
|
||
principal.setAccount(stringValue(row.get("account")));
|
||
principal.setDisplayName(firstNonBlank(stringValue(row.get("display_name")), principal.getAccount()));
|
||
principal.setRoleCode(ROLE_CODE);
|
||
principal.setRoleName(ROLE_NAME);
|
||
principal.setLoginSide(LOGIN_SIDE_ADMIN);
|
||
principal.setTableName(TABLE_NAME);
|
||
return new AuthLoginCandidate(principal, stringValue(row.get("password_hash")));
|
||
}
|
||
catch (EmptyResultDataAccessException e)
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private String resolveToken(HttpServletRequest request)
|
||
{
|
||
String authorization = request.getHeader("Authorization");
|
||
if (authorization != null && authorization.startsWith("Bearer "))
|
||
{
|
||
return authorization.substring("Bearer ".length());
|
||
}
|
||
return request.getHeader("X-Admin-Token");
|
||
}
|
||
|
||
private String passwordHash(String password)
|
||
{
|
||
try
|
||
{
|
||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
|
||
StringBuilder builder = new StringBuilder();
|
||
for (byte item : hash)
|
||
{
|
||
builder.append(String.format("%02x", item));
|
||
}
|
||
return builder.toString();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
throw new IllegalStateException("Password hash failed", e);
|
||
}
|
||
}
|
||
|
||
private Long toLong(Object value)
|
||
{
|
||
if (value instanceof Number)
|
||
{
|
||
return ((Number) value).longValue();
|
||
}
|
||
if (value == null)
|
||
{
|
||
return null;
|
||
}
|
||
return Long.valueOf(String.valueOf(value));
|
||
}
|
||
|
||
private String stringValue(Object value)
|
||
{
|
||
return value == null ? "" : String.valueOf(value);
|
||
}
|
||
|
||
private String firstNonBlank(String first, String second)
|
||
{
|
||
return isBlank(first) ? second : first;
|
||
}
|
||
|
||
private boolean isBlank(String value)
|
||
{
|
||
return value == null || value.trim().isEmpty();
|
||
}
|
||
|
||
public static class LoginBody
|
||
{
|
||
private String account;
|
||
private String username;
|
||
private String password;
|
||
|
||
public String getAccount()
|
||
{
|
||
return account;
|
||
}
|
||
|
||
public void setAccount(String account)
|
||
{
|
||
this.account = account;
|
||
}
|
||
|
||
public String getUsername()
|
||
{
|
||
return username;
|
||
}
|
||
|
||
public void setUsername(String username)
|
||
{
|
||
this.username = username;
|
||
}
|
||
|
||
public String getPassword()
|
||
{
|
||
return password;
|
||
}
|
||
|
||
public void setPassword(String password)
|
||
{
|
||
this.password = password;
|
||
}
|
||
}
|
||
|
||
private static class AuthLoginCandidate
|
||
{
|
||
private final AuthPrincipal principal;
|
||
private final String passwordHash;
|
||
|
||
private AuthLoginCandidate(AuthPrincipal principal, String passwordHash)
|
||
{
|
||
this.principal = principal;
|
||
this.passwordHash = passwordHash;
|
||
}
|
||
|
||
public AuthPrincipal getPrincipal()
|
||
{
|
||
return principal;
|
||
}
|
||
|
||
public String getPasswordHash()
|
||
{
|
||
return passwordHash;
|
||
}
|
||
}
|
||
}
|
||
', 'admin', sysdate());
|
||
|
||
INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES
|
||
(920201, 9202, 'package.json.vm', NULL, 'package.json.vm', '{
|
||
"name": "${projectFileName}-admin",
|
||
"version": "1.0.0",
|
||
"private": true,
|
||
"scripts": {
|
||
"dev": "vue-cli-service serve --host 0.0.0.0",
|
||
"serve": "vue-cli-service serve --host 0.0.0.0",
|
||
"build": "vue-cli-service build"
|
||
},
|
||
"dependencies": {
|
||
"axios": "^0.27.2",
|
||
"core-js": "^3.8.3",
|
||
"echarts": "5.4.0",
|
||
"element-ui": "^2.15.14",
|
||
"quill": "^1.3.7",
|
||
"vue": "^2.6.14",
|
||
"vue-quill-editor": "^3.0.6",
|
||
"vue-router": "^3.6.5"
|
||
},
|
||
"devDependencies": {
|
||
"@vue/cli-service": "^4.5.19",
|
||
"vue-template-compiler": "^2.6.14"
|
||
}
|
||
}', 'admin', sysdate()),
|
||
(920202, 9202, 'babel.config.js.vm', NULL, 'babel.config.js.vm', 'module.exports = {
|
||
presets: [
|
||
"@vue/cli-plugin-babel/preset"
|
||
]
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920203, 9202, 'vue.config.js.vm', NULL, 'vue.config.js.vm', 'const port = process.env.PORT || 8081
|
||
const apiBaseUrl = process.env.VUE_APP_API_BASE_URL || "http://localhost:8080"
|
||
|
||
module.exports = {
|
||
transpileDependencies: [],
|
||
devServer: {
|
||
port,
|
||
proxy: {
|
||
"/api": {
|
||
target: apiBaseUrl,
|
||
changeOrigin: true,
|
||
pathRewrite: {
|
||
"^/api": ""
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920204, 9202, 'index.html.vm', NULL, 'index.html.vm', '<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>${projectName} Admin</title>
|
||
</head>
|
||
<body>
|
||
<noscript>请启用 JavaScript 后访问。</noscript>
|
||
<div id="app"></div>
|
||
</body>
|
||
</html>', 'admin', sysdate()),
|
||
(920205, 9202, 'admin-main.js.vm', NULL, 'admin-main.js.vm', 'import Vue from "vue"
|
||
import ElementUI from "element-ui"
|
||
import VueQuillEditor from "vue-quill-editor"
|
||
import "element-ui/lib/theme-chalk/index.css"
|
||
import "quill/dist/quill.core.css"
|
||
import "quill/dist/quill.snow.css"
|
||
import App from "./App.vue"
|
||
import router from "./router"
|
||
import request from "./utils/request"
|
||
import dict from "./utils/dict"
|
||
|
||
Vue.config.productionTip = false
|
||
Vue.use(ElementUI)
|
||
Vue.use(VueQuillEditor)
|
||
Vue.prototype.request = request
|
||
Vue.prototype._dict = dict
|
||
|
||
new Vue({
|
||
router,
|
||
render: h => h(App)
|
||
}).#[[$mount]]#("#app")', 'admin', sysdate()),
|
||
(920206, 9202, 'admin-App.vue.vm', NULL, 'admin-App.vue.vm', '<template>
|
||
<div id="app">
|
||
<router-view v-if="isLoginPage" />
|
||
<div v-else class="admin-shell">
|
||
<aside class="admin-sidebar">
|
||
<router-link class="brand" to="/">
|
||
<span class="brand-mark">ADM</span>
|
||
<span class="brand-text">${projectName}后台</span>
|
||
</router-link>
|
||
|
||
<nav class="sidebar-menu">
|
||
#if($hasAdminNavGroups)
|
||
#foreach($group in $adminNavGroups)
|
||
#if($group.hasChildren)
|
||
<div class="menu-group">
|
||
#if($group.clickable)
|
||
<router-link class="menu-title menu-title-link" :class=''{ active: isSidebarGroupActive(${group.activePathsLiteral}) }'' to="${group.path}" exact>
|
||
<span><i class="el-icon-menu"></i>${group.name}</span>
|
||
<i class="el-icon-arrow-up"></i>
|
||
</router-link>
|
||
#else
|
||
<div class="menu-title" :class=''{ active: isSidebarGroupActive(${group.activePathsLiteral}) }''>
|
||
<span><i class="el-icon-folder-opened"></i>${group.name}</span>
|
||
<i class="el-icon-arrow-up"></i>
|
||
</div>
|
||
#end
|
||
#foreach($child in $group.children)
|
||
<router-link class="sidebar-link is-child" to="${child.path}" exact>
|
||
<span>${child.name}</span>
|
||
</router-link>
|
||
#end
|
||
</div>
|
||
#else
|
||
<router-link class="sidebar-link" to="${group.path}" exact>
|
||
<i class="el-icon-menu"></i>
|
||
<span>${group.name}</span>
|
||
</router-link>
|
||
#end
|
||
#end
|
||
#else
|
||
<router-link class="sidebar-link" to="/empty" exact>
|
||
<i class="el-icon-warning-outline"></i>
|
||
<span>暂无菜单</span>
|
||
</router-link>
|
||
#end
|
||
</nav>
|
||
</aside>
|
||
|
||
<section class="admin-main">
|
||
<header class="topbar">
|
||
<div class="breadcrumb">
|
||
<router-link to="/">首页</router-link>
|
||
<span>/</span>
|
||
<strong>{{ currentTitle }}</strong>
|
||
</div>
|
||
<el-dropdown trigger="click" @command="handleUserCommand">
|
||
<span class="user-entry">
|
||
<span class="avatar">管</span>
|
||
<span>{{ userName }}</span>
|
||
<i class="el-icon-arrow-down"></i>
|
||
</span>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</header>
|
||
<main class="content-area">
|
||
<router-view />
|
||
</main>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "App",
|
||
computed: {
|
||
isLoginPage() {
|
||
return this.#[[$route]]#.path === "/login"
|
||
},
|
||
currentTitle() {
|
||
return this.#[[$route]]#.meta && this.#[[$route]]#.meta.title ? this.#[[$route]]#.meta.title : "系统首页"
|
||
},
|
||
userName() {
|
||
const storedUser = window.localStorage.getItem("admin-user")
|
||
if (storedUser) {
|
||
try {
|
||
const user = JSON.parse(storedUser)
|
||
return user.nickname || user.username || "管理员"
|
||
} catch (e) {
|
||
return "管理员"
|
||
}
|
||
}
|
||
return window.localStorage.getItem("adminUserName") || "管理员"
|
||
}
|
||
},
|
||
methods: {
|
||
isSidebarGroupActive(paths) {
|
||
return Array.isArray(paths) && paths.indexOf(this.#[[$route]]#.path) !== -1
|
||
},
|
||
handleUserCommand(command) {
|
||
if (command === "logout") {
|
||
this.request.post("/auth/admin/logout").finally(() => {
|
||
this.clearAdminSession()
|
||
this.#[[$router]]#.replace("/login")
|
||
})
|
||
}
|
||
},
|
||
clearAdminSession() {
|
||
window.localStorage.removeItem("admin-token")
|
||
window.localStorage.removeItem("admin-user")
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: #f3f5fa;
|
||
color: #303133;
|
||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||
}
|
||
|
||
a {
|
||
text-decoration: none;
|
||
}
|
||
|
||
.admin-shell {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
background: #f3f5fa;
|
||
}
|
||
|
||
.admin-sidebar {
|
||
width: 208px;
|
||
min-height: 100vh;
|
||
flex: 0 0 208px;
|
||
overflow-y: auto;
|
||
background: #0f172a;
|
||
color: #d8e6f0;
|
||
}
|
||
|
||
.brand {
|
||
height: 62px;
|
||
padding: 0 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
color: #fff;
|
||
background: #111827;
|
||
}
|
||
|
||
.brand-mark {
|
||
display: inline-grid;
|
||
width: 36px;
|
||
height: 36px;
|
||
place-items: center;
|
||
border-radius: 8px;
|
||
color: #ffffff;
|
||
background: #17633b;
|
||
font-size: 12px;
|
||
font-weight: 800;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.brand-text {
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
font-size: 17px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.sidebar-menu {
|
||
padding: 10px 0 24px;
|
||
}
|
||
|
||
.sidebar-link,
|
||
.menu-title {
|
||
min-height: 44px;
|
||
padding: 0 18px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
color: #d8e6f0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.menu-title {
|
||
justify-content: space-between;
|
||
background: #111f35;
|
||
border-left: 3px solid transparent;
|
||
}
|
||
|
||
.menu-title-link {
|
||
color: #d8e6f0;
|
||
}
|
||
|
||
.menu-title span {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.menu-title.active,
|
||
.menu-title:hover,
|
||
.sidebar-link:hover {
|
||
color: #ffffff;
|
||
background: #1e2f4d;
|
||
}
|
||
|
||
.sidebar-link.is-child {
|
||
padding-left: 48px;
|
||
background: #0b1220;
|
||
}
|
||
|
||
.sidebar-link.router-link-exact-active,
|
||
.sidebar-link.router-link-active {
|
||
background: #2563eb;
|
||
color: #fff;
|
||
}
|
||
|
||
.admin-main {
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.topbar {
|
||
height: 56px;
|
||
padding: 0 18px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: #ffffff;
|
||
border-bottom: 1px solid #e5e7eb;
|
||
color: #111827;
|
||
}
|
||
|
||
.breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.breadcrumb a,
|
||
.breadcrumb strong {
|
||
color: #111827;
|
||
}
|
||
|
||
.user-entry {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: #334155;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.avatar {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
display: inline-grid;
|
||
place-items: center;
|
||
color: #1d4ed8;
|
||
background: #eff6ff;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.content-area {
|
||
min-height: calc(100vh - 56px);
|
||
padding: 8px 10px 28px;
|
||
}
|
||
</style>', 'admin', sysdate()),
|
||
(920207, 9202, 'admin-router.js.vm', NULL, 'admin-router.js.vm', 'import Vue from "vue"
|
||
import Router from "vue-router"
|
||
import Login from "@/views/login/index.vue"
|
||
#if($hasAdminRouteItems)
|
||
#foreach($component in $adminRouteComponents)
|
||
import ${component.componentName} from "${component.componentPath}"
|
||
#end
|
||
#end
|
||
|
||
Vue.use(Router)
|
||
|
||
#if($hasAdminRouteItems)
|
||
const firstPath = "${defaultAdminPath}"
|
||
#else
|
||
const firstPath = "/empty"
|
||
const Empty = { template: "<div class=\"empty-page\">暂无可管理数据</div>" }
|
||
#end
|
||
|
||
const routes = [
|
||
{
|
||
path: "/login",
|
||
name: "Login",
|
||
component: Login,
|
||
meta: { title: "登录" }
|
||
},
|
||
{
|
||
path: "/",
|
||
redirect: firstPath
|
||
}#if($hasAdminRouteItems)#else,
|
||
{
|
||
path: "/empty",
|
||
name: "Empty",
|
||
component: Empty,
|
||
meta: { title: "系统首页" }
|
||
}#end
|
||
#foreach($item in $adminRouteItems),
|
||
{
|
||
path: "${item.path}",
|
||
name: "${item.code}",
|
||
component: ${item.componentName},
|
||
meta: { title: "${item.title}" }
|
||
}
|
||
#end
|
||
]
|
||
|
||
const router = new Router({
|
||
mode: "hash",
|
||
routes
|
||
})
|
||
|
||
router.beforeEach((to, from, next) => {
|
||
const hasToken = Boolean(window.localStorage.getItem("admin-token"))
|
||
if (to.path !== "/login" && !hasToken) {
|
||
next({ path: "/login", query: { redirect: to.fullPath } })
|
||
return
|
||
}
|
||
if (to.path === "/login" && hasToken) {
|
||
next(to.query.redirect || firstPath)
|
||
return
|
||
}
|
||
next()
|
||
})
|
||
|
||
export default router', 'admin', sysdate()),
|
||
(920211, 9202, 'admin-login.vue.vm', NULL, 'admin-login.vue.vm', '<template>
|
||
<div class="login-page">
|
||
<section class="login-visual">
|
||
<div class="login-brand">
|
||
<span class="brand-mark">
|
||
<i></i><i></i><i></i><i></i>
|
||
</span>
|
||
<span>${projectName}后台</span>
|
||
</div>
|
||
<h1>${projectName}</h1>
|
||
<p>统一管理分类、内容、订单与用户数据</p>
|
||
</section>
|
||
<el-form ref="loginForm" :model="form" :rules="rules" class="login-card" @keyup.enter.native="handleLogin">
|
||
<h2>欢迎登录${projectName}后台</h2>
|
||
<p>请输入管理员账号进入后台</p>
|
||
<el-form-item prop="username">
|
||
<el-input v-model="form.username" prefix-icon="el-icon-user" placeholder="请输入账号" />
|
||
</el-form-item>
|
||
<el-form-item prop="password">
|
||
<el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="请输入密码" show-password />
|
||
</el-form-item>
|
||
<div class="login-options">
|
||
<el-checkbox v-model="form.remember">记住账号</el-checkbox>
|
||
</div>
|
||
<el-button type="primary" :loading="loading" @click="handleLogin">登录</el-button>
|
||
</el-form>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
#if($hasTables)
|
||
#set($firstTable = $tables.get(0))
|
||
const defaultRedirect = "${defaultAdminPath}"
|
||
#else
|
||
const defaultRedirect = "/empty"
|
||
#end
|
||
|
||
export default {
|
||
name: "AdminLogin",
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
form: {
|
||
username: window.localStorage.getItem("adminUserName") || "admin",
|
||
password: "123456",
|
||
remember: true
|
||
},
|
||
rules: {
|
||
username: [{ required: true, message: "请输入账号", trigger: "blur" }],
|
||
password: [{ required: true, message: "请输入密码", trigger: "blur" }]
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
handleLogin() {
|
||
this.#[[$refs]]#.loginForm.validate(valid => {
|
||
if (!valid) {
|
||
return
|
||
}
|
||
this.loading = true
|
||
this.request.post("/auth/admin/login", {
|
||
username: this.form.username,
|
||
password: this.form.password
|
||
}).then(res => {
|
||
if (!res || res.code !== "200" || !res.data || !res.data.token) {
|
||
throw new Error((res && res.msg) || "登录失败")
|
||
}
|
||
window.localStorage.setItem("admin-token", res.data.token)
|
||
window.localStorage.setItem("admin-user", JSON.stringify(res.data.user || {
|
||
username: this.form.username,
|
||
nickname: this.form.username
|
||
}))
|
||
if (this.form.remember) {
|
||
window.localStorage.setItem("adminUserName", this.form.username)
|
||
} else {
|
||
window.localStorage.removeItem("adminUserName")
|
||
}
|
||
this.#[[$message]]#.success("登录成功")
|
||
this.#[[$router]]#.replace(this.#[[$route]]#.query.redirect || defaultRedirect)
|
||
}).catch(error => {
|
||
this.#[[$message]]#.error(error.message || "登录失败")
|
||
}).finally(() => {
|
||
this.loading = false
|
||
})
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.login-page {
|
||
min-height: 100vh;
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 420px;
|
||
background: #f3f5fa;
|
||
}
|
||
|
||
.login-visual {
|
||
padding: 54px 64px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
background: linear-gradient(135deg, #20a9b5 0%, #147a8f 48%, #001120 100%);
|
||
color: #fff;
|
||
}
|
||
|
||
.login-brand {
|
||
position: absolute;
|
||
top: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.brand-mark {
|
||
width: 30px;
|
||
height: 30px;
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 3px;
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
.brand-mark i {
|
||
display: block;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.brand-mark i:nth-child(1) {
|
||
background: #f4c542;
|
||
}
|
||
|
||
.brand-mark i:nth-child(2) {
|
||
background: #22b8cf;
|
||
}
|
||
|
||
.brand-mark i:nth-child(3) {
|
||
background: #2f80ed;
|
||
}
|
||
|
||
.brand-mark i:nth-child(4) {
|
||
background: #42c77b;
|
||
}
|
||
|
||
.login-visual h1 {
|
||
margin: 0;
|
||
font-size: 46px;
|
||
font-weight: 700;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.login-visual p {
|
||
max-width: 520px;
|
||
margin: 16px 0 0;
|
||
color: rgba(255, 255, 255, .82);
|
||
font-size: 18px;
|
||
}
|
||
|
||
.login-card {
|
||
align-self: center;
|
||
margin: 0 48px 0 0;
|
||
padding: 36px 34px;
|
||
border-radius: 8px;
|
||
background: #fff;
|
||
box-shadow: 0 18px 42px rgba(0, 17, 32, .16);
|
||
}
|
||
|
||
.login-card h2 {
|
||
margin: 0;
|
||
color: #17233d;
|
||
font-size: 25px;
|
||
font-weight: 700;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.login-card p {
|
||
margin: 8px 0 24px;
|
||
color: #8a95a6;
|
||
}
|
||
|
||
.login-options {
|
||
margin: -4px 0 18px;
|
||
}
|
||
|
||
.login-card .el-button {
|
||
width: 100%;
|
||
height: 42px;
|
||
border-color: #0f7dbd;
|
||
background: #0f7dbd;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.login-page {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.login-visual {
|
||
min-height: 220px;
|
||
padding: 36px 28px;
|
||
}
|
||
|
||
.login-brand {
|
||
position: static;
|
||
margin-bottom: 48px;
|
||
}
|
||
|
||
.login-visual h1 {
|
||
font-size: 34px;
|
||
}
|
||
|
||
.login-card {
|
||
margin: 24px;
|
||
}
|
||
}
|
||
</style>
|
||
', 'admin', sysdate()),
|
||
(920208, 9202, 'request.js.vm', NULL, 'request.js.vm', 'import axios from "axios"
|
||
import { Message } from "element-ui"
|
||
|
||
const request = axios.create({
|
||
baseURL: process.env.VUE_APP_API_BASE_URL || "/api",
|
||
timeout: 30000
|
||
})
|
||
|
||
request.interceptors.request.use(config => {
|
||
const token = window.localStorage.getItem("admin-token")
|
||
if (token) {
|
||
config.headers.Authorization = "Bearer " + token
|
||
}
|
||
return config
|
||
})
|
||
|
||
request.interceptors.response.use(
|
||
response => {
|
||
const data = response.data
|
||
if (data && data.code === "401") {
|
||
clearAdminSession()
|
||
Message.error(data.msg || "请先登录")
|
||
return Promise.reject(new Error(data.msg || "Unauthorized"))
|
||
}
|
||
return data
|
||
},
|
||
error => {
|
||
if (error && error.response && error.response.status === 401) {
|
||
clearAdminSession()
|
||
Message.error("请先登录")
|
||
} else {
|
||
Message.error(error && error.message ? error.message : "请求失败")
|
||
}
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
function clearAdminSession() {
|
||
window.localStorage.removeItem("admin-token")
|
||
window.localStorage.removeItem("admin-user")
|
||
if (window.location.hash.indexOf("#/login") !== 0) {
|
||
window.location.hash = "#/login"
|
||
}
|
||
}
|
||
|
||
export default request
|
||
', 'admin', sysdate()),
|
||
(920209, 9202, 'dict.js.vm', NULL, 'dict.js.vm', 'const dictData = {}
|
||
#foreach ($column in $columns)
|
||
#if($column.dictOptions && $column.dictOptions != "")
|
||
#set($dictKey = $column.dictType)
|
||
#if(!$dictKey || $dictKey == "")
|
||
#set($dictKey = $column.columnName)
|
||
#end
|
||
dictData["${dictKey}"] = ${column.dictOptions}
|
||
#end
|
||
#end
|
||
|
||
const emptyDict = []
|
||
|
||
function normalizeOptions(options) {
|
||
if (!Array.isArray(options)) {
|
||
return emptyDict
|
||
}
|
||
return options.map((option) => {
|
||
const label = option.label || option.name || option.value
|
||
const value = option.value || label
|
||
return {
|
||
...option,
|
||
label,
|
||
name: option.name || label,
|
||
value
|
||
}
|
||
})
|
||
}
|
||
|
||
export default {
|
||
getDictDataByType(type) {
|
||
return normalizeOptions(dictData[type])
|
||
},
|
||
getDictLabel(type, value) {
|
||
if (value === undefined || value === null || value === "") {
|
||
return "-"
|
||
}
|
||
const matched = normalizeOptions(dictData[type]).find((option) => String(option.value) === String(value))
|
||
return matched ? matched.label : value
|
||
}
|
||
}', 'admin', sysdate()),
|
||
(920210, 9202, 'admin-index.vue.vm', NULL, 'admin-index.vue.vm', '#set($designed = $hasCurrentPageDesign)
|
||
#set($queryColumns = $columns)
|
||
#set($tableColumns = $columns)
|
||
#set($formColumns = $columns)
|
||
#set($showAdd = true)
|
||
#set($showBatchDelete = true)
|
||
#set($showView = false)
|
||
#set($showEdit = true)
|
||
#set($showDelete = true)
|
||
#set($showExport = false)
|
||
#set($showQuery = true)
|
||
#set($showToolbar = true)
|
||
#set($showForm = true)
|
||
#set($showList = true)
|
||
#set($renderForm = true)
|
||
#if($designed)
|
||
#set($queryColumns = $pageDesignQueryColumns)
|
||
#set($tableColumns = $pageDesignTableColumns)
|
||
#set($formColumns = $pageDesignFormColumns)
|
||
#set($showAdd = $pageDesignAllowAdd)
|
||
#set($showBatchDelete = $pageDesignAllowBatchDelete)
|
||
#set($showView = $pageDesignAllowView)
|
||
#set($showEdit = $pageDesignAllowEdit)
|
||
#set($showDelete = $pageDesignAllowDelete)
|
||
#set($showExport = $pageDesignAllowExport)
|
||
#set($showQuery = $pageDesignShowQuery)
|
||
#set($showToolbar = $pageDesignShowToolbar)
|
||
#set($showForm = $pageDesignShowForm)
|
||
#set($showList = $pageDesignShowList)
|
||
#end
|
||
#if(!$showToolbar)
|
||
#set($showAdd = false)
|
||
#set($showBatchDelete = false)
|
||
#set($showExport = false)
|
||
#end
|
||
#set($renderForm = $showForm)
|
||
<template>
|
||
<div class="page-container">
|
||
#if($showQuery)
|
||
<section class="query-panel">
|
||
<div class="toolbar query-toolbar">
|
||
#foreach ($column in $queryColumns)
|
||
#set($renderQueryField = false)
|
||
#if($designed)
|
||
#set($renderQueryField = true)
|
||
#elseif($column.isQuery == "1")
|
||
#set($renderQueryField = true)
|
||
#end
|
||
#if($renderQueryField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#if($column.htmlType == "input")
|
||
<el-input class="filter-item" placeholder="请输入${columnComment}" clearable v-model="queryParams.${javaField}" @keyup.enter.native="load" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-select class="filter-item" v-model="queryParams.${javaField}" placeholder="请选择${columnComment}" clearable>
|
||
#if($remoteSelect)
|
||
<el-option
|
||
v-for="item in getSelectOptions(''${javaField}'')"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value" />
|
||
#else
|
||
<el-option
|
||
v-for="item in _dict.getDictDataByType(''${column.dictType}'')"
|
||
:key="item.value"
|
||
:label="item.name"
|
||
:value="item.value" />
|
||
#end
|
||
</el-select>
|
||
#elseif($column.htmlType == "datetime")
|
||
<el-date-picker class="filter-item" v-model="queryParams.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${columnComment}" />
|
||
#end
|
||
#end
|
||
#end
|
||
<el-button type="primary" @click="load">搜索</el-button>
|
||
<el-button @click="reset">重置</el-button>
|
||
</div>
|
||
</section>
|
||
#end
|
||
|
||
#if($showToolbar)
|
||
<section class="action-panel">
|
||
<div class="toolbar action-toolbar">
|
||
#if($showAdd)
|
||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||
#end
|
||
#if($showBatchDelete)
|
||
<el-popconfirm
|
||
confirm-button-text="确定"
|
||
cancel-button-text="取消"
|
||
icon="el-icon-info"
|
||
icon-color="red"
|
||
title="确定批量删除选中的数据吗?"
|
||
@confirm="delBatch">
|
||
<el-button slot="reference" type="danger" icon="el-icon-delete">批量删除</el-button>
|
||
</el-popconfirm>
|
||
#end
|
||
#if($showExport)
|
||
<el-button icon="el-icon-download" @click="handleExport">导出</el-button>
|
||
#end
|
||
</div>
|
||
</section>
|
||
#end
|
||
|
||
#if($showList)
|
||
<section class="table-panel">
|
||
<el-table class="data-table" :data="${businessName}List" stripe @selection-change="handleSelectionChange">
|
||
#if($showBatchDelete)
|
||
<el-table-column type="selection" width="55" />
|
||
#end
|
||
#if(!$designed)
|
||
<el-table-column prop="${pkColumn.javaField}" label="ID" width="90" />
|
||
#end
|
||
#foreach ($column in $tableColumns)
|
||
#set($renderTableField = false)
|
||
#if($designed)
|
||
#set($renderTableField = true)
|
||
#elseif($column.isList == "1")
|
||
#set($renderTableField = true)
|
||
#end
|
||
#if($renderTableField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#if($column.htmlType == "datetime")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" width="180" />
|
||
#elseif($column.htmlType == "imageUpload")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" width="110">
|
||
<template slot-scope="scope">
|
||
<el-image
|
||
v-if="scope.row.${javaField}"
|
||
class="table-image"
|
||
:src="resolveResourceUrl(scope.row.${javaField})"
|
||
:preview-src-list="[resolveResourceUrl(scope.row.${javaField})]" />
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center">
|
||
<template slot-scope="scope">
|
||
#if($remoteSelect)
|
||
{{ getOptionLabel(''${javaField}'', scope.row.${javaField}) }}
|
||
#else
|
||
{{ _dict.getDictLabel(''${column.dictType}'', scope.row.${javaField}) }}
|
||
#end
|
||
</template>
|
||
</el-table-column>
|
||
#else
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" />
|
||
#end
|
||
#end
|
||
#end
|
||
#if($showView || $showEdit || $showDelete)
|
||
<el-table-column label="操作" width="230" align="center">
|
||
<template slot-scope="scope">
|
||
#if($showView)
|
||
<el-button class="row-action view-action" type="info" icon="el-icon-view" circle @click="handleView(scope.row)"></el-button>
|
||
#end
|
||
#if($showEdit)
|
||
<el-button class="row-action edit-action" type="primary" icon="el-icon-edit" circle @click="handleEdit(scope.row)"></el-button>
|
||
#end
|
||
#if($showDelete)
|
||
<el-popconfirm
|
||
confirm-button-text="确定"
|
||
cancel-button-text="取消"
|
||
icon="el-icon-info"
|
||
icon-color="red"
|
||
title="确定删除这条数据吗?"
|
||
@confirm="del(scope.row.${pkColumn.javaField})">
|
||
<el-button slot="reference" class="row-action delete-action" type="danger" icon="el-icon-delete" circle></el-button>
|
||
</el-popconfirm>
|
||
#end
|
||
</template>
|
||
</el-table-column>
|
||
#end
|
||
</el-table>
|
||
</section>
|
||
|
||
<section class="pagination-panel">
|
||
<el-pagination
|
||
class="pagination"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
:current-page="queryParams.pageNum"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="queryParams.pageSize"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="total" />
|
||
</section>
|
||
#end
|
||
|
||
#if($renderForm)
|
||
<el-dialog :title="viewing ? ''View ${functionName}'' : (form.${pkColumn.javaField} ? ''Edit ${functionName}'' : ''Create ${functionName}'')" :visible.sync="dialogFormVisible" width="520px">
|
||
<el-form ref="form" :model="form" label-width="110px" size="small" :disabled="viewing">
|
||
#foreach ($column in $formColumns)
|
||
#set($renderFormField = false)
|
||
#if($designed)
|
||
#set($renderFormField = true)
|
||
#elseif($column.isEdit == "1")
|
||
#set($renderFormField = true)
|
||
#end
|
||
#if($renderFormField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#set($autoIncrementField=$column.isIncrement == "1")
|
||
<el-form-item#if($autoIncrementField) v-if="form.${javaField}"#end label="${columnComment}" prop="${javaField}"#if($column.isRequired == "1" && !$autoIncrementField) :rules="[{ required: true, message: ''${columnComment}不能为空'', trigger: #if($column.htmlType == "select")''change''#else''blur''#end }]"#end>
|
||
#if($column.htmlType == "input")
|
||
<el-input v-model="form.${javaField}"#if($autoIncrementField) disabled#end placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "textarea")
|
||
<el-input v-model="form.${javaField}"#if($autoIncrementField) disabled#end type="textarea" placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "editor")
|
||
<quill-editor
|
||
v-model="form.${javaField}"
|
||
class="rich-text-editor"
|
||
:disabled="viewing"
|
||
:options="{ placeholder: ''请输入${columnComment}'' }" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-select v-model="form.${javaField}" placeholder="请选择${columnComment}" clearable>
|
||
#if($remoteSelect)
|
||
<el-option
|
||
v-for="item in getSelectOptions(''${javaField}'')"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value" />
|
||
#else
|
||
<el-option
|
||
v-for="item in _dict.getDictDataByType(''${column.dictType}'')"
|
||
:key="item.value"
|
||
:label="item.name"
|
||
:value="item.value" />
|
||
#end
|
||
</el-select>
|
||
#elseif($column.htmlType == "datetime")
|
||
<el-date-picker v-model="form.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${columnComment}" />
|
||
#elseif($column.htmlType == "imageUpload")
|
||
<el-upload
|
||
class="avatar-uploader"
|
||
action="/api/files/upload"
|
||
:show-file-list="false"
|
||
:on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<img v-if="form.${javaField}" :src="resolveResourceUrl(form.${javaField})" class="avatar" />
|
||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||
</el-upload>
|
||
#elseif($column.htmlType == "fileUpload")
|
||
<el-upload
|
||
action="/api/files/upload"
|
||
:on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
</el-upload>
|
||
<div v-if="form.${javaField}" class="file-link">{{ form.${javaField} }}</div>
|
||
#end
|
||
</el-form-item>
|
||
#end
|
||
#end
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||
<el-button v-if="!viewing" type="primary" @click="save">确定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
#end
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "${BusinessName}",
|
||
data() {
|
||
return {
|
||
${businessName}List: [],
|
||
total: 0,
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
#foreach ($column in $queryColumns)
|
||
#set($renderQueryField = false)
|
||
#if($designed)
|
||
#set($renderQueryField = true)
|
||
#elseif($column.isQuery == "1")
|
||
#set($renderQueryField = true)
|
||
#end
|
||
#if($renderQueryField)
|
||
${column.javaField}: undefined,
|
||
#end
|
||
#end
|
||
},
|
||
form: {},
|
||
viewing: false,
|
||
dialogFormVisible: false,
|
||
remoteOptionMap: {},
|
||
remoteSelectConfig: {
|
||
#foreach($remote in $qingRemoteSelects)
|
||
${remote.field}: {
|
||
path: "${remote.path}",
|
||
valueField: "${remote.valueField}",
|
||
labelField: "${remote.labelField}"
|
||
}#if($foreach.hasNext),#end
|
||
#end
|
||
},
|
||
multipleSelection: []
|
||
}
|
||
},
|
||
created() {
|
||
this.loadRemoteOptions()
|
||
this.load()
|
||
},
|
||
methods: {
|
||
loadRemoteOptions() {
|
||
Object.keys(this.remoteSelectConfig).forEach(field => {
|
||
const config = this.remoteSelectConfig[field]
|
||
this.request.get(config.path, {
|
||
params: { pageNum: 1, pageSize: 999 }
|
||
}).then(res => {
|
||
const data = res.data || {}
|
||
const records = Array.isArray(data) ? data : (data.records || [])
|
||
const options = records.map(item => ({
|
||
value: item[config.valueField],
|
||
label: item[config.labelField]
|
||
}))
|
||
this.#[[$set]]#(this.remoteOptionMap, field, options)
|
||
})
|
||
})
|
||
},
|
||
getSelectOptions(field) {
|
||
return this.remoteOptionMap[field] || []
|
||
},
|
||
getOptionLabel(field, value) {
|
||
const option = this.getSelectOptions(field).find(item => String(item.value) === String(value))
|
||
if (option) {
|
||
return option.label
|
||
}
|
||
return value === undefined || value === null || value === "" ? "-" : value
|
||
},
|
||
load() {
|
||
this.request.get("${requestPath}/page", {
|
||
params: this.queryParams
|
||
}).then(res => {
|
||
const page = res.data || {}
|
||
this.${businessName}List = page.records || []
|
||
this.total = page.total || 0
|
||
})
|
||
},
|
||
save() {
|
||
this.#[[$refs]]#.form.validate(valid => {
|
||
if (!valid) {
|
||
return
|
||
}
|
||
this.request.post("${requestPath}", this.form).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("保存成功")
|
||
this.dialogFormVisible = false
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "保存失败")
|
||
}
|
||
})
|
||
})
|
||
},
|
||
handleAdd() {
|
||
this.form = {}
|
||
this.viewing = false
|
||
this.dialogFormVisible = true
|
||
this.#[[$nextTick]]#(() => this.#[[$refs]]#.form && this.#[[$refs]]#.form.clearValidate())
|
||
},
|
||
handleView(row) {
|
||
this.form = JSON.parse(JSON.stringify(row))
|
||
this.viewing = true
|
||
this.dialogFormVisible = true
|
||
},
|
||
handleEdit(row) {
|
||
this.form = JSON.parse(JSON.stringify(row))
|
||
this.viewing = false
|
||
this.dialogFormVisible = true
|
||
this.#[[$nextTick]]#(() => this.#[[$refs]]#.form && this.#[[$refs]]#.form.clearValidate())
|
||
},
|
||
del(${pkColumn.javaField}) {
|
||
this.request.delete("${requestPath}/" + ${pkColumn.javaField}).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("删除成功")
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "删除失败")
|
||
}
|
||
})
|
||
},
|
||
handleSelectionChange(val) {
|
||
this.multipleSelection = val
|
||
},
|
||
delBatch() {
|
||
const ids = this.multipleSelection.map(item => item.${pkColumn.javaField})
|
||
if (!ids.length) {
|
||
this.#[[$message]]#.warning("请先选择要删除的数据")
|
||
return
|
||
}
|
||
this.request.post("${requestPath}/del/batch", ids).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("批量删除成功")
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "批量删除失败")
|
||
}
|
||
})
|
||
},
|
||
handleExport() {
|
||
window.open("${apiRequestPath}/export", "_blank")
|
||
},
|
||
reset() {
|
||
this.queryParams = {
|
||
pageNum: 1,
|
||
pageSize: 10
|
||
}
|
||
this.load()
|
||
},
|
||
handleSizeChange(pageSize) {
|
||
this.queryParams.pageSize = pageSize
|
||
this.load()
|
||
},
|
||
handleCurrentChange(pageNum) {
|
||
this.queryParams.pageNum = pageNum
|
||
this.load()
|
||
},
|
||
resolveResourceUrl(url) {
|
||
if (!url) {
|
||
return ""
|
||
}
|
||
if (url.indexOf("http://") === 0 || url.indexOf("https://") === 0 || url.indexOf("//") === 0 || url.indexOf("data:") === 0 || url.indexOf("blob:") === 0) {
|
||
return url
|
||
}
|
||
if (url.indexOf("/api/") === 0) {
|
||
return url
|
||
}
|
||
if (url.indexOf("/files/") === 0) {
|
||
return "/api" + url
|
||
}
|
||
return url
|
||
},
|
||
uploadSuccess(field, res) {
|
||
if (res && res.code === "200" && res.data && res.data.url) {
|
||
this.#[[$set]]#(this.form, field, res.data.url)
|
||
} else {
|
||
this.#[[$message]]#.error("上传失败,请重试")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-container {
|
||
min-height: calc(100vh - 72px);
|
||
}
|
||
|
||
.query-panel,
|
||
.action-panel,
|
||
.table-panel,
|
||
.pagination-panel {
|
||
margin-bottom: 8px;
|
||
border: 1px solid #edf0f5;
|
||
border-radius: 4px;
|
||
background: #fff;
|
||
box-shadow: 0 1px 8px rgba(26, 39, 56, .08);
|
||
}
|
||
|
||
.query-panel,
|
||
.action-panel {
|
||
padding: 12px 14px;
|
||
}
|
||
|
||
.table-panel {
|
||
padding: 12px 12px 0;
|
||
}
|
||
|
||
.pagination-panel {
|
||
padding: 10px 12px;
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
align-items: center;
|
||
}
|
||
|
||
.query-toolbar .el-button--primary {
|
||
border-color: #cde8f0;
|
||
background: #eaf8fb;
|
||
color: #158a9a;
|
||
}
|
||
|
||
.query-toolbar .el-button--default {
|
||
border-color: #f6e6ba;
|
||
background: #fff8e6;
|
||
color: #c58600;
|
||
}
|
||
|
||
.action-toolbar .el-button--primary {
|
||
border-color: #9cd4ed;
|
||
background: #eefaff;
|
||
color: #0d80bd;
|
||
}
|
||
|
||
.action-toolbar .el-button--danger {
|
||
border-color: #f2c2c7;
|
||
background: #fff3f4;
|
||
color: #d64252;
|
||
}
|
||
|
||
.filter-item {
|
||
width: 220px;
|
||
}
|
||
|
||
.data-table {
|
||
width: 100%;
|
||
color: #606266;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.data-table >>> th {
|
||
height: 48px;
|
||
background: #fff;
|
||
color: #7d8794;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.data-table >>> td {
|
||
height: 58px;
|
||
border-color: #f0f2f5;
|
||
}
|
||
|
||
.data-table >>> .el-table__row--striped td {
|
||
background: #fafafa;
|
||
}
|
||
|
||
.pagination {
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.row-action {
|
||
width: 30px;
|
||
height: 30px;
|
||
padding: 0;
|
||
border: 0;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.view-action {
|
||
background: #6f7d90;
|
||
}
|
||
|
||
.edit-action {
|
||
background: #0b7ec2;
|
||
}
|
||
|
||
.delete-action {
|
||
margin-left: 10px;
|
||
background: #e82f3d;
|
||
}
|
||
|
||
.table-image {
|
||
width: 52px;
|
||
height: 52px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.avatar-uploader .avatar {
|
||
width: 96px;
|
||
height: 96px;
|
||
display: block;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.avatar-uploader-icon {
|
||
width: 96px;
|
||
height: 96px;
|
||
line-height: 96px;
|
||
border: 1px dashed #d9d9d9;
|
||
border-radius: 4px;
|
||
text-align: center;
|
||
color: #8c939d;
|
||
}
|
||
|
||
.file-link {
|
||
margin-top: 6px;
|
||
color: #606266;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.rich-text-editor >>> .ql-editor {
|
||
min-height: 160px;
|
||
}
|
||
</style>
|
||
', 'admin', sysdate());
|
||
|
||
-- Portal frontend template files
|
||
INSERT INTO sys_template_file (template_file_id, template_id, file_name, module_id, file_path, file_content, create_by, create_time) VALUES
|
||
(920301, 9203, 'package.json.vm', NULL, 'package.json.vm', '{
|
||
"name": "${projectFileName}-web",
|
||
"version": "1.0.0",
|
||
"private": true,
|
||
"scripts": {
|
||
"dev": "vue-cli-service serve --host 0.0.0.0",
|
||
"serve": "vue-cli-service serve --host 0.0.0.0",
|
||
"build": "vue-cli-service build"
|
||
},
|
||
"dependencies": {
|
||
"axios": "^0.27.2",
|
||
"core-js": "^3.8.3",
|
||
"echarts": "5.4.0",
|
||
"element-ui": "^2.15.14",
|
||
"quill": "^1.3.7",
|
||
"vue": "^2.6.14",
|
||
"vue-quill-editor": "^3.0.6",
|
||
"vue-router": "^3.6.5"
|
||
},
|
||
"devDependencies": {
|
||
"@vue/cli-service": "^4.5.19",
|
||
"vue-template-compiler": "^2.6.14"
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920302, 9203, 'babel.config.js.vm', NULL, 'babel.config.js.vm', 'module.exports = {
|
||
presets: [
|
||
"@vue/cli-plugin-babel/preset"
|
||
]
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920303, 9203, 'vue.config.js.vm', NULL, 'vue.config.js.vm', 'const port = process.env.PORT || 8082
|
||
const apiBaseUrl = process.env.VUE_APP_API_BASE_URL || "http://localhost:8080"
|
||
|
||
module.exports = {
|
||
transpileDependencies: [],
|
||
devServer: {
|
||
port,
|
||
proxy: {
|
||
"/api": {
|
||
target: apiBaseUrl,
|
||
changeOrigin: true,
|
||
pathRewrite: {
|
||
"^/api": ""
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
', 'admin', sysdate()),
|
||
(920304, 9203, 'index.html.vm', NULL, 'index.html.vm', '<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>${functionName}</title>
|
||
</head>
|
||
<body>
|
||
<noscript>请启用 JavaScript 后访问。</noscript>
|
||
<div id="app"></div>
|
||
</body>
|
||
</html>
|
||
', 'admin', sysdate()),
|
||
(920305, 9203, 'frontend-main.js.vm', NULL, 'frontend-main.js.vm', 'import Vue from "vue"
|
||
import ElementUI from "element-ui"
|
||
import VueQuillEditor from "vue-quill-editor"
|
||
import "element-ui/lib/theme-chalk/index.css"
|
||
import "quill/dist/quill.core.css"
|
||
import "quill/dist/quill.snow.css"
|
||
import App from "./App.vue"
|
||
import router from "./router"
|
||
import request from "./api/request"
|
||
import dict from "./utils/dict"
|
||
import "./style.css"
|
||
|
||
Vue.config.productionTip = false
|
||
Vue.use(ElementUI)
|
||
Vue.use(VueQuillEditor)
|
||
Vue.prototype.request = request
|
||
Vue.prototype._dict = dict
|
||
|
||
new Vue({
|
||
router,
|
||
render: h => h(App)
|
||
}).#[[$mount]]#("#app")', 'admin', sysdate()),
|
||
(920306, 9203, 'frontend-App.vue.vm', NULL, 'frontend-App.vue.vm', '#set($portalProjectName = $projectName)
|
||
#if(!$portalProjectName || $portalProjectName == "")
|
||
#set($portalProjectName = $functionName)
|
||
#end
|
||
#if(!$portalProjectName || $portalProjectName == "")
|
||
#set($portalProjectName = "Portal")
|
||
#end
|
||
#set($portalHomePath = $defaultFrontendPath)
|
||
#if(!$portalHomePath || $portalHomePath == "")
|
||
#set($portalHomePath = $requestPath)
|
||
#end
|
||
<template>
|
||
<div class="portal-shell">
|
||
<template v-if="!isLoginRoute">
|
||
<header class="top-nav">
|
||
<router-link class="brand" to="${portalHomePath}">
|
||
<span class="brand-logo" aria-hidden="true"><i></i></span>
|
||
<span>${portalProjectName}</span>
|
||
</router-link>
|
||
|
||
<nav class="portal-nav" aria-label="主导航">
|
||
#if($hasFrontendNavGroups)
|
||
#foreach($group in $frontendNavGroups)
|
||
<div v-if=''canShowMenu(${group.visibleRolesLiteral})'' class="portal-nav-group#if($group.hasChildren) has-children#end" :class=''{ active: isNavGroupActive(${group.activePathsLiteral}) }''>
|
||
#if($group.clickable)
|
||
<router-link class="portal-nav-parent" to="${group.path}" exact>${group.name}</router-link>
|
||
#else
|
||
<span class="portal-nav-parent portal-nav-directory">${group.name}</span>
|
||
#end
|
||
#if($group.hasChildren)
|
||
<button class="portal-nav-toggle" type="button" aria-label="展开子菜单">⌄</button>
|
||
<div class="portal-nav-dropdown">
|
||
#foreach($child in $group.children)
|
||
<router-link v-if=''canShowMenu(${child.visibleRolesLiteral})'' class="portal-nav-child" to="${child.path}" exact>${child.name}</router-link>
|
||
#end
|
||
</div>
|
||
#end
|
||
</div>
|
||
#end
|
||
#else
|
||
<div class="portal-nav-group">
|
||
<router-link class="portal-nav-parent" to="${portalHomePath}" exact>首页</router-link>
|
||
</div>
|
||
#end
|
||
</nav>
|
||
|
||
<div class="user-area">
|
||
<template v-if="currentUser">
|
||
<button class="user-chip" type="button">
|
||
<span class="avatar">{{ userInitial }}</span>
|
||
<span>{{ currentUserName }}</span>
|
||
</button>
|
||
<button class="logout-link" type="button" @click="logout">退出</button>
|
||
</template>
|
||
<button v-else class="login-link" type="button" @click="goLogin">登录</button>
|
||
</div>
|
||
</header>
|
||
|
||
<section v-if="isHomeRoute" class="hero-banner" aria-label="项目横幅">
|
||
<div class="hero-pattern" aria-hidden="true"></div>
|
||
<div class="hero-content">
|
||
<span class="hero-eyebrow">WELCOME</span>
|
||
<h1>${portalProjectName}</h1>
|
||
<p>发现内容,连接服务,轻松完成每一次访问。</p>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<main :class="[''portal-main'', { ''portal-main-login'': isLoginRoute }]">
|
||
<router-view />
|
||
</main>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "App",
|
||
data() {
|
||
return {
|
||
currentUser: null
|
||
}
|
||
},
|
||
computed: {
|
||
isLoginRoute() {
|
||
return this.#[[$route]]#.path === "/login"
|
||
},
|
||
isHomeRoute() {
|
||
return this.#[[$route]]#.path === "${portalHomePath}"
|
||
},
|
||
currentUserName() {
|
||
return this.currentUser && (this.currentUser.displayName || this.currentUser.account || this.currentUser.nickname || this.currentUser.username || "User")
|
||
},
|
||
userInitial() {
|
||
const name = this.currentUserName || "U"
|
||
return name.slice(0, 1).toUpperCase()
|
||
}
|
||
},
|
||
mounted() {
|
||
this.loadUser()
|
||
window.addEventListener("portal-user-change", this.loadUser)
|
||
},
|
||
beforeDestroy() {
|
||
window.removeEventListener("portal-user-change", this.loadUser)
|
||
},
|
||
methods: {
|
||
canShowMenu(visibleRoles) {
|
||
if (!Array.isArray(visibleRoles) || visibleRoles.length === 0) {
|
||
return true
|
||
}
|
||
const roleCode = this.currentUser && this.currentUser.roleCode
|
||
return Boolean(roleCode) && visibleRoles.indexOf(roleCode) !== -1
|
||
},
|
||
isNavGroupActive(paths) {
|
||
return Array.isArray(paths) && paths.indexOf(this.#[[$route]]#.path) !== -1
|
||
},
|
||
loadUser() {
|
||
const raw = localStorage.getItem("portal-user")
|
||
if (!raw) {
|
||
this.currentUser = null
|
||
return
|
||
}
|
||
try {
|
||
this.currentUser = JSON.parse(raw)
|
||
} catch (error) {
|
||
localStorage.removeItem("portal-user")
|
||
this.currentUser = null
|
||
}
|
||
},
|
||
goLogin() {
|
||
this.#[[$router]]#.push({
|
||
path: "/login",
|
||
query: { redirect: this.#[[$route]]#.fullPath }
|
||
})
|
||
},
|
||
logout() {
|
||
this.request.post("/auth/logout").catch(() => {})
|
||
localStorage.removeItem("portal-token")
|
||
localStorage.removeItem("portal-user")
|
||
window.dispatchEvent(new Event("portal-user-change"))
|
||
this.#[[$router]]#.push("/login")
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
:root {
|
||
--portal-primary: #167d83;
|
||
--portal-primary-strong: #11656a;
|
||
--portal-primary-soft: #eaf7f7;
|
||
--portal-accent: #2f72d6;
|
||
--portal-text: #172033;
|
||
--portal-text-secondary: #5f6b7a;
|
||
--portal-border: #e3e9f1;
|
||
--portal-surface: #ffffff;
|
||
--portal-background: #f5f7fb;
|
||
--portal-radius-sm: 8px;
|
||
--portal-radius-md: 12px;
|
||
--portal-radius-lg: 18px;
|
||
--portal-shadow-sm: 0 8px 24px rgba(15, 23, 42, 0.06);
|
||
--portal-shadow-md: 0 18px 44px rgba(15, 23, 42, 0.12);
|
||
--portal-content-width: 1200px;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
background: var(--portal-background);
|
||
color: var(--portal-text);
|
||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||
line-height: 1.5;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
a {
|
||
color: inherit;
|
||
text-decoration: none;
|
||
}
|
||
|
||
button {
|
||
font: inherit;
|
||
}
|
||
|
||
button:focus-visible,
|
||
a:focus-visible {
|
||
outline: 3px solid rgba(47, 114, 214, 0.28);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
.portal-shell {
|
||
min-height: 100vh;
|
||
background: var(--portal-background);
|
||
}
|
||
|
||
.top-nav {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 20;
|
||
display: grid;
|
||
grid-template-columns: minmax(180px, auto) minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 24px;
|
||
min-height: 72px;
|
||
padding: 0 32px;
|
||
color: var(--portal-text);
|
||
background: rgba(255, 255, 255, 0.96);
|
||
border-bottom: 1px solid var(--portal-border);
|
||
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.04);
|
||
backdrop-filter: blur(14px);
|
||
}
|
||
|
||
.brand,
|
||
.portal-nav,
|
||
.user-area,
|
||
.user-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.brand {
|
||
gap: 10px;
|
||
min-width: 0;
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.brand span:last-child {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.brand-logo {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 38px;
|
||
height: 38px;
|
||
flex: 0 0 38px;
|
||
place-items: center;
|
||
overflow: hidden;
|
||
border-radius: 11px;
|
||
color: #ffffff;
|
||
background: linear-gradient(135deg, var(--portal-primary), var(--portal-accent));
|
||
box-shadow: 0 7px 18px rgba(22, 125, 131, 0.24);
|
||
}
|
||
|
||
.brand-logo::before,
|
||
.brand-logo::after,
|
||
.brand-logo i {
|
||
position: absolute;
|
||
display: block;
|
||
content: "";
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.92);
|
||
transform: rotate(-35deg);
|
||
}
|
||
|
||
.brand-logo::before {
|
||
width: 20px;
|
||
height: 7px;
|
||
top: 9px;
|
||
left: 7px;
|
||
}
|
||
|
||
.brand-logo i {
|
||
width: 15px;
|
||
height: 6px;
|
||
top: 17px;
|
||
left: 11px;
|
||
}
|
||
|
||
.brand-logo::after {
|
||
width: 10px;
|
||
height: 5px;
|
||
top: 25px;
|
||
left: 15px;
|
||
}
|
||
|
||
.portal-nav {
|
||
justify-content: center;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
height: 100%;
|
||
overflow: visible;
|
||
}
|
||
|
||
.portal-nav-group {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
flex: 0 0 auto;
|
||
min-height: 72px;
|
||
}
|
||
|
||
.portal-nav-parent,
|
||
.portal-nav-toggle,
|
||
.portal-nav-child {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
border: 0;
|
||
background: transparent;
|
||
font: inherit;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.portal-nav-parent {
|
||
min-height: 36px;
|
||
padding: 0 14px;
|
||
border-radius: var(--portal-radius-sm);
|
||
color: var(--portal-text);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.portal-nav-parent:hover,
|
||
.portal-nav-parent.router-link-active,
|
||
.portal-nav-group.active .portal-nav-parent {
|
||
color: var(--portal-primary-strong);
|
||
background: var(--portal-primary-soft);
|
||
}
|
||
|
||
.portal-nav-directory {
|
||
cursor: default;
|
||
}
|
||
|
||
.portal-nav-toggle {
|
||
justify-content: center;
|
||
width: 28px;
|
||
height: 28px;
|
||
margin-left: -8px;
|
||
border-radius: 6px;
|
||
color: #64748b;
|
||
}
|
||
|
||
.portal-nav-group:hover .portal-nav-toggle,
|
||
.portal-nav-group:focus-within .portal-nav-toggle,
|
||
.portal-nav-group.active .portal-nav-toggle {
|
||
color: var(--portal-primary-strong);
|
||
background: var(--portal-primary-soft);
|
||
}
|
||
|
||
.portal-nav-dropdown {
|
||
position: absolute;
|
||
top: calc(100% - 8px);
|
||
left: 0;
|
||
z-index: 30;
|
||
display: none;
|
||
min-width: 168px;
|
||
padding: 8px;
|
||
border: 1px solid var(--portal-border);
|
||
border-radius: var(--portal-radius-md);
|
||
background: var(--portal-surface);
|
||
box-shadow: var(--portal-shadow-md);
|
||
}
|
||
|
||
.portal-nav-group:hover .portal-nav-dropdown,
|
||
.portal-nav-group:focus-within .portal-nav-dropdown {
|
||
display: grid;
|
||
gap: 4px;
|
||
}
|
||
|
||
.portal-nav-child {
|
||
min-height: 34px;
|
||
padding: 0 10px;
|
||
border-radius: 6px;
|
||
color: #334155;
|
||
font-size: 14px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.portal-nav-child:hover,
|
||
.portal-nav-child.router-link-active {
|
||
color: var(--portal-primary-strong);
|
||
background: var(--portal-primary-soft);
|
||
}
|
||
|
||
.user-area {
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
min-width: 130px;
|
||
}
|
||
|
||
.user-chip,
|
||
.login-link,
|
||
.logout-link {
|
||
border: 1px solid var(--portal-border);
|
||
color: var(--portal-text-secondary);
|
||
background: var(--portal-surface);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.user-chip {
|
||
gap: 8px;
|
||
min-height: 38px;
|
||
padding: 0 10px 0 0;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.avatar {
|
||
display: inline-grid;
|
||
width: 36px;
|
||
height: 36px;
|
||
place-items: center;
|
||
border: 1px solid #bfe4e5;
|
||
border-radius: 50%;
|
||
color: var(--portal-primary-strong);
|
||
background: var(--portal-primary-soft);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.logout-link,
|
||
.login-link {
|
||
min-height: 32px;
|
||
padding: 0 10px;
|
||
border-radius: var(--portal-radius-sm);
|
||
}
|
||
|
||
.logout-link:hover,
|
||
.login-link:hover {
|
||
color: var(--portal-primary-strong);
|
||
background: var(--portal-primary-soft);
|
||
}
|
||
|
||
.hero-banner {
|
||
position: relative;
|
||
display: grid;
|
||
min-height: 228px;
|
||
place-items: center;
|
||
overflow: hidden;
|
||
background: linear-gradient(132deg, var(--portal-primary), var(--portal-accent));
|
||
}
|
||
|
||
.hero-pattern {
|
||
position: absolute;
|
||
inset: 0;
|
||
opacity: 0.58;
|
||
background:
|
||
linear-gradient(42deg, transparent 0 18%, rgba(255, 255, 255, 0.18) 18% 27%, transparent 27% 100%),
|
||
linear-gradient(132deg, transparent 0 48%, rgba(246, 186, 51, 0.32) 48% 55%, transparent 55% 100%);
|
||
}
|
||
|
||
.hero-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
width: min(var(--portal-content-width), calc(100% - 48px));
|
||
margin: 0 auto;
|
||
text-align: left;
|
||
}
|
||
|
||
.hero-eyebrow {
|
||
display: inline-block;
|
||
margin-bottom: 12px;
|
||
color: rgba(255, 255, 255, 0.78);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
}
|
||
|
||
.hero-banner h1 {
|
||
max-width: 780px;
|
||
margin: 0;
|
||
color: #ffffff;
|
||
font-size: clamp(34px, 4vw, 48px);
|
||
font-weight: 700;
|
||
letter-spacing: 0;
|
||
line-height: 1.2;
|
||
text-shadow: 0 12px 28px rgba(15, 23, 42, 0.22);
|
||
}
|
||
|
||
.hero-banner p {
|
||
max-width: 620px;
|
||
margin: 14px 0 0;
|
||
color: rgba(255, 255, 255, 0.86);
|
||
font-size: 16px;
|
||
}
|
||
|
||
.portal-main {
|
||
width: min(var(--portal-content-width), calc(100% - 48px));
|
||
margin: 0 auto;
|
||
padding: 32px 0 52px;
|
||
}
|
||
|
||
.portal-main-login {
|
||
width: 100%;
|
||
min-height: 100vh;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.top-nav {
|
||
grid-template-columns: 1fr auto;
|
||
gap: 10px;
|
||
height: auto;
|
||
min-height: 56px;
|
||
padding: 10px 16px;
|
||
}
|
||
|
||
.portal-nav {
|
||
grid-column: 1 / -1;
|
||
justify-content: flex-start;
|
||
order: 3;
|
||
gap: 6px;
|
||
overflow-x: auto;
|
||
overflow-y: visible;
|
||
}
|
||
|
||
.portal-nav-group {
|
||
min-height: 38px;
|
||
}
|
||
|
||
.portal-nav-parent {
|
||
min-height: 34px;
|
||
padding: 0 12px;
|
||
}
|
||
|
||
.portal-nav-dropdown {
|
||
position: fixed;
|
||
top: 104px;
|
||
left: 16px;
|
||
right: 16px;
|
||
}
|
||
|
||
.hero-banner {
|
||
min-height: 176px;
|
||
}
|
||
|
||
.hero-content {
|
||
width: min(100% - 32px, var(--portal-content-width));
|
||
}
|
||
|
||
.hero-banner p {
|
||
margin-top: 10px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.portal-main {
|
||
width: min(calc(100% - 28px), var(--portal-content-width));
|
||
padding: 22px 0 36px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 560px) {
|
||
.brand {
|
||
max-width: calc(100vw - 150px);
|
||
}
|
||
|
||
.brand span:last-child {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.user-area {
|
||
min-width: 0;
|
||
}
|
||
|
||
.user-chip > span:last-child {
|
||
display: none;
|
||
}
|
||
|
||
.hero-banner {
|
||
min-height: 160px;
|
||
}
|
||
|
||
.hero-eyebrow {
|
||
margin-bottom: 8px;
|
||
}
|
||
}
|
||
</style>
|
||
', 'admin', sysdate()),
|
||
(920307, 9203, 'style.css.vm', NULL, 'style.css.vm', 'body {
|
||
margin: 0;
|
||
background: #f6f7fb;
|
||
color: #1f2937;
|
||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||
}
|
||
|
||
.el-button {
|
||
border-radius: 4px;
|
||
}', 'admin', sysdate()),
|
||
(920308, 9203, 'frontend-router.js.vm', NULL, 'frontend-router.js.vm', 'import Vue from "vue"
|
||
import Router from "vue-router"
|
||
import Login from "@/views/login/index.vue"
|
||
#set($portalDefaultPath = $defaultFrontendPath)
|
||
#if(!$portalDefaultPath || $portalDefaultPath == "")
|
||
#set($portalDefaultPath = $requestPath)
|
||
#end
|
||
#if($hasFrontendRouteItems)
|
||
#foreach($component in $frontendRouteComponents)
|
||
import ${component.componentName} from "${component.componentPath}"
|
||
#end
|
||
#else
|
||
import ${BusinessName} from "@/views/${viewPath}/index.vue"
|
||
#end
|
||
|
||
Vue.use(Router)
|
||
|
||
const router = new Router({
|
||
mode: "hash",
|
||
routes: [
|
||
{
|
||
path: "/",
|
||
redirect: "${portalDefaultPath}"
|
||
},
|
||
{
|
||
path: "/login",
|
||
name: "Login",
|
||
component: Login
|
||
},
|
||
#if($hasFrontendRouteItems)
|
||
#foreach($item in $frontendRouteItems)
|
||
{
|
||
path: "${item.path}",
|
||
name: "${item.code}",
|
||
component: ${item.componentName},
|
||
meta: { requiresAuth: ${item.requiresLogin} }
|
||
}#if($foreach.hasNext),#end
|
||
#end
|
||
#else
|
||
{
|
||
path: "${requestPath}",
|
||
name: "${BusinessName}",
|
||
component: ${BusinessName},
|
||
meta: { requiresAuth: true }
|
||
}
|
||
#end
|
||
]
|
||
})
|
||
|
||
router.beforeEach((to, from, next) => {
|
||
const requiresAuth = to.matched.some(record => record.meta && record.meta.requiresAuth)
|
||
const hasToken = Boolean(localStorage.getItem("portal-token"))
|
||
|
||
if (requiresAuth && !hasToken) {
|
||
next({
|
||
path: "/login",
|
||
query: { redirect: to.fullPath }
|
||
})
|
||
return
|
||
}
|
||
|
||
next()
|
||
})
|
||
|
||
export default router
|
||
', 'admin', sysdate()),
|
||
(920309, 9203, 'frontend-request.js.vm', NULL, 'frontend-request.js.vm', 'import axios from "axios"
|
||
import { Message } from "element-ui"
|
||
|
||
const request = axios.create({
|
||
baseURL: process.env.VUE_APP_API_BASE_URL || "/api",
|
||
timeout: 30000
|
||
})
|
||
|
||
request.interceptors.request.use(config => {
|
||
const token = localStorage.getItem("portal-token")
|
||
if (token) {
|
||
config.headers.Authorization = "Bearer " + token
|
||
}
|
||
return config
|
||
})
|
||
|
||
request.interceptors.response.use(
|
||
response => {
|
||
const data = response.data
|
||
if (data && data.code === "401") {
|
||
clearSession()
|
||
Message.error(data.msg || "请先登录")
|
||
return Promise.reject(new Error(data.msg || "Unauthorized"))
|
||
}
|
||
return data
|
||
},
|
||
error => {
|
||
if (error && error.response && error.response.status === 401) {
|
||
clearSession()
|
||
Message.error("请先登录")
|
||
} else {
|
||
Message.error(error && error.message ? error.message : "请求失败")
|
||
}
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
function clearSession() {
|
||
localStorage.removeItem("portal-token")
|
||
localStorage.removeItem("portal-user")
|
||
if (window.location.hash.indexOf("#/login") !== 0) {
|
||
window.location.hash = "#/login"
|
||
}
|
||
}
|
||
|
||
export default request
|
||
', 'admin', sysdate()),
|
||
(920310, 9203, 'frontend-api.js.vm', NULL, 'frontend-api.js.vm', 'import request from "./request"
|
||
|
||
export function list${ClassName}(query) {
|
||
return request({
|
||
url: "${requestPath}/page",
|
||
method: "get",
|
||
params: query
|
||
})
|
||
}
|
||
|
||
export function get${ClassName}(${pkColumn.javaField}) {
|
||
return request({
|
||
url: "${requestPath}/" + ${pkColumn.javaField},
|
||
method: "get"
|
||
})
|
||
}', 'admin', sysdate()),
|
||
(920311, 9203, 'frontend-index.vue.vm', NULL, 'frontend-index.vue.vm', '<template>
|
||
#set($designed = $hasCurrentFrontendPageDesign)
|
||
#set($frontendReadOnlyDefaults = true)
|
||
#set($queryColumns = $columns)
|
||
#set($tableColumns = $columns)
|
||
#set($formColumns = $columns)
|
||
#set($cardColumns = $columns)
|
||
#set($cardTitleColumn = false)
|
||
#set($cardImageColumn = false)
|
||
#set($showAdd = false)
|
||
#set($showBatchDelete = false)
|
||
#set($showView = true)
|
||
#set($showEdit = false)
|
||
#set($showDelete = false)
|
||
#set($isCardListLayout = false)
|
||
#set($isSplitListLayout = false)
|
||
#set($showQuery = false)
|
||
#set($showToolbar = true)
|
||
#set($showForm = true)
|
||
#set($showList = true)
|
||
#set($showDetail = true)
|
||
#set($renderForm = true)
|
||
#set($currentUserOnly = false)
|
||
#set($isDetailPage = $pageDesignIsDetail)
|
||
#set($isFormPage = $pageDesignIsForm)
|
||
#set($isGroupedForm = $pageDesignIsGroupedForm)
|
||
#set($formGroups = $pageDesignFormGroups)
|
||
#set($isMediaDetailLayout = false)
|
||
#set($detailColumns = $columns)
|
||
#set($detailTitleColumn = false)
|
||
#set($detailImageColumn = false)
|
||
#set($detailSummaryColumn = false)
|
||
#set($toolbarBusinessActions = $pageDesignToolbarBusinessActions)
|
||
#set($rowBusinessActions = $pageDesignRowBusinessActions)
|
||
#set($formBusinessActions = $pageDesignFormBusinessActions)
|
||
#set($allPageBusinessActions = $pageDesignBusinessActions)
|
||
#set($hasToolbarBusinessActions = $hasPageDesignToolbarBusinessActions)
|
||
#set($hasRowBusinessActions = $hasPageDesignRowBusinessActions)
|
||
#set($hasFormBusinessActions = $hasPageDesignFormBusinessActions)
|
||
#set($topBusinessBlocks = $pageDesignTopBusinessBlocks)
|
||
#set($bottomBusinessBlocks = $pageDesignBottomBusinessBlocks)
|
||
#set($embeddedBusinessBlocks = $pageDesignEmbeddedBusinessBlocks)
|
||
#if($designed)
|
||
#set($queryColumns = $pageDesignQueryColumns)
|
||
#set($tableColumns = $pageDesignTableColumns)
|
||
#set($formColumns = $pageDesignFormColumns)
|
||
#set($cardColumns = $pageDesignCardColumns)
|
||
#set($cardTitleColumn = $pageDesignCardTitleColumn)
|
||
#set($cardImageColumn = $pageDesignCardImageColumn)
|
||
#set($showAdd = $pageDesignAllowAdd)
|
||
#set($showBatchDelete = $pageDesignAllowBatchDelete)
|
||
#set($showView = $pageDesignAllowView)
|
||
#set($showEdit = $pageDesignAllowEdit)
|
||
#set($showDelete = $pageDesignAllowDelete)
|
||
#set($isCardListLayout = $pageDesignIsCardList)
|
||
#set($isSplitListLayout = $pageDesignIsSplitList)
|
||
#set($showQuery = $pageDesignShowQuery)
|
||
#set($showToolbar = $pageDesignShowToolbar)
|
||
#set($showForm = $pageDesignShowForm)
|
||
#set($showList = $pageDesignShowList)
|
||
#set($showDetail = $pageDesignShowDetail)
|
||
#set($currentUserOnly = $pageDesignIsCurrentUserList)
|
||
#set($isMediaDetailLayout = $pageDesignIsMediaDetail)
|
||
#set($detailColumns = $pageDesignDetailColumns)
|
||
#set($detailTitleColumn = $pageDesignDetailTitleColumn)
|
||
#set($detailImageColumn = $pageDesignDetailImageColumn)
|
||
#set($detailSummaryColumn = $pageDesignDetailSummaryColumn)
|
||
#end
|
||
#if(!$showToolbar)
|
||
#set($showAdd = false)
|
||
#set($showBatchDelete = false)
|
||
#end
|
||
#if(!$queryColumns || $queryColumns.size() == 0)
|
||
#set($showQuery = false)
|
||
#end
|
||
|
||
#if($isDetailPage)
|
||
#set($showQuery = false)
|
||
#set($showToolbar = false)
|
||
#set($showAdd = false)
|
||
#set($showBatchDelete = false)
|
||
#set($showView = false)
|
||
#set($showEdit = false)
|
||
#set($showDelete = false)
|
||
#set($showForm = false)
|
||
#set($renderForm = false)
|
||
#end
|
||
#if($showForm && !$isFormPage)
|
||
#set($renderForm = true)
|
||
#else
|
||
#set($renderForm = false)
|
||
#end
|
||
#macro(renderPageFormField $column)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#set($autoIncrementField=$column.isIncrement == "1")
|
||
<el-form-item#if($autoIncrementField) v-if="form.${javaField}"#end label="${columnComment}" prop="${javaField}"#if($column.isRequired == "1" && !$autoIncrementField) :rules="[{ required: true, message: ''${columnComment}不能为空'', trigger: #if($column.htmlType == "select")''change''#else''blur''#end }]"#end>
|
||
#if($column.htmlType == "input")
|
||
<el-input v-model="form.${javaField}"#if($autoIncrementField) disabled#end placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "textarea")
|
||
<el-input v-model="form.${javaField}" type="textarea" :rows="4" placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "editor")
|
||
<quill-editor
|
||
v-model="form.${javaField}"
|
||
class="rich-text-editor"
|
||
:disabled="viewing"
|
||
:options="{ placeholder: ''请输入${columnComment}'' }" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-select v-model="form.${javaField}" placeholder="请选择${columnComment}" clearable>
|
||
#if($remoteSelect)
|
||
<el-option v-for="item in getSelectOptions(''${javaField}'')" :key="item.value" :label="item.label" :value="item.value" />
|
||
#else
|
||
<el-option v-for="item in _dict.getDictDataByType(''${column.dictType}'')" :key="item.value" :label="item.name" :value="item.value" />
|
||
#end
|
||
</el-select>
|
||
#elseif($column.htmlType == "datetime")
|
||
<el-date-picker v-model="form.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${columnComment}" />
|
||
#elseif($column.htmlType == "imageUpload")
|
||
<el-upload class="avatar-uploader" action="/api/files/upload" :show-file-list="false" :on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<img v-if="form.${javaField}" :src="resolveResourceUrl(form.${javaField})" class="avatar" />
|
||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||
</el-upload>
|
||
#elseif($column.htmlType == "fileUpload")
|
||
<el-upload action="/api/files/upload" :on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
</el-upload>
|
||
<div v-if="form.${javaField}" class="file-link">{{ form.${javaField} }}</div>
|
||
#end
|
||
</el-form-item>
|
||
#end
|
||
<section class="portal-page#if($isCardListLayout) portal-page--card#elseif($isSplitListLayout) portal-page--split#elseif($isDetailPage) portal-page--detail#elseif($isFormPage) portal-page--form#else portal-page--table#end">
|
||
#if($hasPageDesignTopBusinessBlocks)
|
||
<section class="embedded-business-blocks top-business-blocks">
|
||
#foreach($block in $topBusinessBlocks)
|
||
<div class="embedded-business-block__item embedded-business-block__item--span-${block.span}">
|
||
<${block.componentName} />
|
||
</div>
|
||
#end
|
||
</section>
|
||
#end
|
||
|
||
|
||
<section class="data-panel#if($isSplitListLayout) split-data-panel#end">
|
||
<div class="panel-heading">
|
||
<div>
|
||
<h2>${currentPageTitle}</h2>
|
||
</div>
|
||
#if($showToolbar)
|
||
<div class="panel-actions">
|
||
#if($showAdd)
|
||
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||
#end
|
||
#if($showBatchDelete)
|
||
<el-popconfirm
|
||
confirm-button-text="确定"
|
||
cancel-button-text="取消"
|
||
icon="el-icon-info"
|
||
icon-color="red"
|
||
title="确定批量删除选中的数据吗?"
|
||
@confirm="delBatch">
|
||
<el-button slot="reference" type="danger" icon="el-icon-delete">批量删除</el-button>
|
||
</el-popconfirm>
|
||
#end
|
||
#foreach($action in $toolbarBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType)#set($buttonType = "primary")#end
|
||
#set($buttonIcon = $action.buttonIcon)
|
||
#if(!$buttonIcon)#set($buttonIcon = "el-icon-position")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="isBusinessActionVisible(businessActionMap[''${action.code}''])"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''])"
|
||
type="${buttonType}" icon="${buttonIcon}"
|
||
@click="handleBusinessAction(''${action.code}'')">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="overflowBusinessActions(''toolbar'').length" @command="code => handleBusinessAction(code)">
|
||
<el-button>更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''toolbar'')"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
#end
|
||
</div>
|
||
|
||
#if($isFormPage)
|
||
<div class="standalone-form-page">
|
||
<el-form ref="form" :model="form" label-width="120px" size="small">
|
||
#if($isGroupedForm && $formGroups.size() > 0)
|
||
#foreach($group in $formGroups)
|
||
<section class="form-group-card">
|
||
<h3>${group.label}</h3>
|
||
<div class="form-group-grid">
|
||
#foreach($column in $group.columns)
|
||
#renderPageFormField($column)
|
||
#end
|
||
</div>
|
||
</section>
|
||
#end
|
||
#else
|
||
<div class="form-group-grid">
|
||
#foreach($column in $formColumns)
|
||
#renderPageFormField($column)
|
||
#end
|
||
</div>
|
||
#end
|
||
</el-form>
|
||
<div class="form-page-actions">
|
||
<el-button @click="resetStandaloneForm">取消</el-button>
|
||
<el-button type="primary" @click="save">提交</el-button>
|
||
#foreach($action in $formBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType)#set($buttonType = "primary")#end
|
||
#set($buttonIcon = $action.buttonIcon)
|
||
#if(!$buttonIcon)#set($buttonIcon = "el-icon-position")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="isBusinessActionVisible(businessActionMap[''${action.code}''], form)"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''], form)"
|
||
type="${buttonType}"
|
||
icon="${buttonIcon}"
|
||
@click="handleBusinessAction(''${action.code}'', form)">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="overflowBusinessActions(''form'', form).length" @command="code => handleBusinessAction(code, form)">
|
||
<el-button>更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''form'', form)"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action, form)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
</div>
|
||
#elseif($isDetailPage)
|
||
#if($showDetail)
|
||
<div class="detail-view" v-loading="detailLoading">
|
||
<div v-if="detailLoaded && !detailRecord.${pkColumn.javaField}" class="empty-detail">
|
||
<i class="el-icon-document"></i>
|
||
<span>暂无详情数据</span>
|
||
</div>
|
||
<template v-else>
|
||
#if($isMediaDetailLayout)
|
||
<div class="media-detail-view">
|
||
<div class="media-detail-hero">
|
||
#if($detailImageColumn)
|
||
<el-image
|
||
v-if="detailRecord.${detailImageColumn.javaField}"
|
||
class="media-detail-image"
|
||
:src="resolveResourceUrl(detailRecord.${detailImageColumn.javaField})"
|
||
:preview-src-list="[resolveResourceUrl(detailRecord.${detailImageColumn.javaField})]" />
|
||
<div v-else class="media-detail-image empty"></div>
|
||
#end
|
||
#if($detailTitleColumn || $detailSummaryColumn)
|
||
<div class="media-detail-copy">
|
||
#if($detailTitleColumn)
|
||
<h2>{{ detailRecord.${detailTitleColumn.javaField} || ''-'' }}</h2>
|
||
#end
|
||
#if($detailSummaryColumn)
|
||
<p>{{ formatDetailValue(detailRecord.${detailSummaryColumn.javaField}) }}</p>
|
||
#end
|
||
</div>
|
||
#end
|
||
</div>
|
||
</div>
|
||
<dl class="detail-grid media-detail-grid">
|
||
#else
|
||
<dl class="detail-grid">
|
||
#end
|
||
#foreach ($column in $detailColumns)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
<div class="detail-field#if($column.htmlType == "textarea") wide#end">
|
||
<dt>${columnComment}</dt>
|
||
<dd>
|
||
#if($column.htmlType == "imageUpload")
|
||
<el-image
|
||
v-if="detailRecord.${javaField}"
|
||
class="detail-image"
|
||
:src="resolveResourceUrl(detailRecord.${javaField})"
|
||
:preview-src-list="[resolveResourceUrl(detailRecord.${javaField})]" />
|
||
<span v-else>-</span>
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
#if($remoteSelect)
|
||
{{ getOptionLabel(''${javaField}'', detailRecord.${javaField}) }}
|
||
#else
|
||
{{ _dict.getDictLabel(''${column.dictType}'', detailRecord.${javaField}) || ''-'' }}
|
||
#end
|
||
#else
|
||
{{ formatDetailValue(detailRecord.${javaField}) }}
|
||
#end
|
||
</dd>
|
||
</div>
|
||
#end
|
||
</dl>
|
||
#if($hasRowBusinessActions)
|
||
<div class="detail-actions">
|
||
#foreach($action in $rowBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType)#set($buttonType = "primary")#end
|
||
#set($buttonIcon = $action.buttonIcon)
|
||
#if(!$buttonIcon)#set($buttonIcon = "el-icon-position")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="isBusinessActionVisible(businessActionMap[''${action.code}''], detailRecord)"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''], detailRecord)"
|
||
type="${buttonType}" icon="${buttonIcon}"
|
||
@click="handleBusinessAction(''${action.code}'', detailRecord)">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="overflowBusinessActions(''row'', detailRecord).length" @command="code => handleBusinessAction(code, detailRecord)">
|
||
<el-button>更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''row'', detailRecord)"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action, detailRecord)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
#end
|
||
</template>
|
||
</div>
|
||
#end
|
||
#else
|
||
|
||
#if($showQuery)
|
||
<div class="filter-bar">
|
||
#foreach ($column in $queryColumns)
|
||
#set($renderQueryField = false)
|
||
#if($designed)
|
||
#set($renderQueryField = true)
|
||
#elseif($column.isQuery == "1")
|
||
#set($renderQueryField = true)
|
||
#end
|
||
#if($renderQueryField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#if($column.htmlType == "input")
|
||
<el-input class="filter-item" placeholder="请输入${columnComment}" clearable v-model="queryParams.${javaField}" @keyup.enter.native="load" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-select class="filter-item" v-model="queryParams.${javaField}" placeholder="请选择${columnComment}" clearable>
|
||
#if($remoteSelect)
|
||
<el-option
|
||
v-for="item in getSelectOptions(''${javaField}'')"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value" />
|
||
#else
|
||
<el-option
|
||
v-for="item in _dict.getDictDataByType(''${column.dictType}'')"
|
||
:key="item.value"
|
||
:label="item.name"
|
||
:value="item.value" />
|
||
#end
|
||
</el-select>
|
||
#elseif($column.htmlType == "datetime")
|
||
<el-date-picker class="filter-item" v-model="queryParams.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${columnComment}" />
|
||
#end
|
||
#end
|
||
#end
|
||
<el-button type="primary" icon="el-icon-search" @click="load">搜索</el-button>
|
||
<el-button icon="el-icon-refresh" @click="reset">重置</el-button>
|
||
</div>
|
||
#end
|
||
|
||
#if($showList)
|
||
#if($isCardListLayout)
|
||
<div class="resource-card-grid">
|
||
<article v-for="item in ${businessName}List" :key="item.${pkColumn.javaField}" class="resource-card-item">
|
||
#if($showBatchDelete)
|
||
<el-checkbox class="resource-card-check" v-model="item.__checked" @change="handleCardSelectionChange" />
|
||
#end
|
||
<div class="resource-card-body">
|
||
#if($cardImageColumn)
|
||
<el-image
|
||
v-if="item.${cardImageColumn.javaField}"
|
||
class="resource-card-image"
|
||
:src="resolveResourceUrl(item.${cardImageColumn.javaField})"
|
||
:preview-src-list="[resolveResourceUrl(item.${cardImageColumn.javaField})]" />
|
||
#end
|
||
#if($cardTitleColumn)
|
||
<h3 class="resource-card-title">{{ item.${cardTitleColumn.javaField} || ''-'' }}</h3>
|
||
#end
|
||
#foreach ($column in $cardColumns)
|
||
#set($renderCardField = false)
|
||
#if($designed)
|
||
#set($renderCardField = true)
|
||
#elseif($column.isList == "1")
|
||
#set($renderCardField = true)
|
||
#end
|
||
#if($renderCardField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#if($column.htmlType == "imageUpload")
|
||
<el-image
|
||
v-if="item.${javaField}"
|
||
class="resource-card-image"
|
||
:src="resolveResourceUrl(item.${javaField})"
|
||
:preview-src-list="[resolveResourceUrl(item.${javaField})]" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<div class="resource-card-field">
|
||
<span>${columnComment}</span>
|
||
#if($remoteSelect)
|
||
<strong>{{ getOptionLabel(''${javaField}'', item.${javaField}) }}</strong>
|
||
#else
|
||
<strong>{{ _dict.getDictLabel(''${column.dictType}'', item.${javaField}) || ''-'' }}</strong>
|
||
#end
|
||
</div>
|
||
#else
|
||
<div class="resource-card-field">
|
||
<span>${columnComment}</span>
|
||
<strong>{{ item.${javaField} || ''-'' }}</strong>
|
||
</div>
|
||
#end
|
||
#end
|
||
#end
|
||
</div>
|
||
#if($showView || $showEdit || $showDelete || $hasRowBusinessActions)
|
||
<div class="resource-card-actions">
|
||
#if($showView)
|
||
<el-button size="small" type="primary" icon="el-icon-view" class="resource-card-action" @click="handleView(item)">查看</el-button>
|
||
#end
|
||
#if($showEdit)
|
||
<el-button size="small" type="primary" icon="el-icon-edit" class="resource-card-action" @click="handleEdit(item)">编辑</el-button>
|
||
#end
|
||
#if($showDelete)
|
||
<el-popconfirm
|
||
confirm-button-text="确定"
|
||
cancel-button-text="取消"
|
||
icon="el-icon-info"
|
||
icon-color="red"
|
||
title="确定删除这条数据吗?"
|
||
@confirm="del(item.${pkColumn.javaField})">
|
||
<el-button slot="reference" size="small" type="danger" icon="el-icon-delete" class="resource-card-action">删除</el-button>
|
||
</el-popconfirm>
|
||
#end
|
||
#foreach($action in $rowBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType || $buttonType == "text")#set($buttonType = "primary")#end
|
||
#set($buttonIcon = $action.buttonIcon)
|
||
#if(!$buttonIcon)#set($buttonIcon = "el-icon-position")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="isBusinessActionVisible(businessActionMap[''${action.code}''], item)"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''], item)"
|
||
size="small" type="${buttonType}" icon="${buttonIcon}" class="resource-card-action"
|
||
@click="handleBusinessAction(''${action.code}'', item)">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="overflowBusinessActions(''row'', item).length" @command="code => handleBusinessAction(code, item)">
|
||
<el-button size="small" type="primary" class="resource-card-action">更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''row'', item)"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action, item)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
#end
|
||
</article>
|
||
</div>
|
||
#else
|
||
<el-table :data="${businessName}List" border stripe class="resource-table" @selection-change="handleSelectionChange">
|
||
#if($showBatchDelete)
|
||
<el-table-column type="selection" width="55" />
|
||
#end
|
||
#if(!$designed)
|
||
<el-table-column prop="${pkColumn.javaField}" label="ID" width="90" />
|
||
#end
|
||
#foreach ($column in $tableColumns)
|
||
#set($renderTableField = false)
|
||
#if($designed)
|
||
#set($renderTableField = true)
|
||
#elseif($column.isList == "1")
|
||
#set($renderTableField = true)
|
||
#end
|
||
#if($renderTableField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#if($column.htmlType == "datetime")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" width="180" />
|
||
#elseif($column.htmlType == "imageUpload")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" width="110">
|
||
<template slot-scope="scope">
|
||
<el-image
|
||
v-if="scope.row.${javaField}"
|
||
class="table-image"
|
||
:src="resolveResourceUrl(scope.row.${javaField})"
|
||
:preview-src-list="[resolveResourceUrl(scope.row.${javaField})]" />
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center">
|
||
<template slot-scope="scope">
|
||
#if($remoteSelect)
|
||
{{ getOptionLabel(''${javaField}'', scope.row.${javaField}) }}
|
||
#else
|
||
{{ _dict.getDictLabel(''${column.dictType}'', scope.row.${javaField}) }}
|
||
#end
|
||
</template>
|
||
</el-table-column>
|
||
#else
|
||
<el-table-column prop="${javaField}" label="${columnComment}" align="center" />
|
||
#end
|
||
#end
|
||
#end
|
||
#if($showView || $showEdit || $showDelete || $hasRowBusinessActions)
|
||
<el-table-column label="操作" width="230" align="center">
|
||
<template slot-scope="scope">
|
||
#if($showView)
|
||
<el-button type="text" icon="el-icon-view" @click="handleView(scope.row)">查看</el-button>
|
||
#end
|
||
#if($showEdit)
|
||
<el-button type="text" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||
#end
|
||
#if($showDelete)
|
||
<el-popconfirm
|
||
confirm-button-text="确定"
|
||
cancel-button-text="取消"
|
||
icon="el-icon-info"
|
||
icon-color="red"
|
||
title="确定删除这条数据吗?"
|
||
@confirm="del(scope.row.${pkColumn.javaField})">
|
||
<el-button slot="reference" type="text" icon="el-icon-delete" class="danger-text">删除</el-button>
|
||
</el-popconfirm>
|
||
#end
|
||
#foreach($action in $rowBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType)#set($buttonType = "text")#end
|
||
#set($buttonIcon = $action.buttonIcon)
|
||
#if(!$buttonIcon)#set($buttonIcon = "el-icon-position")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="isBusinessActionVisible(businessActionMap[''${action.code}''], scope.row)"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''], scope.row)"
|
||
type="${buttonType}" icon="${buttonIcon}"
|
||
@click="handleBusinessAction(''${action.code}'', scope.row)">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="overflowBusinessActions(''row'', scope.row).length" @command="code => handleBusinessAction(code, scope.row)">
|
||
<el-button type="text">更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''row'', scope.row)"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action, scope.row)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</template>
|
||
</el-table-column>
|
||
#end
|
||
</el-table>
|
||
#end
|
||
|
||
<el-pagination
|
||
class="pagination"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
:current-page="queryParams.pageNum"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="queryParams.pageSize"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="total" />
|
||
#end
|
||
#end
|
||
</section>
|
||
|
||
#if($hasPageDesignBottomBusinessBlocks)
|
||
<section class="embedded-business-blocks bottom-business-blocks">
|
||
#foreach($block in $bottomBusinessBlocks)
|
||
<div class="embedded-business-block__item embedded-business-block__item--span-${block.span}">
|
||
<${block.componentName} />
|
||
</div>
|
||
#end
|
||
</section>
|
||
#end
|
||
|
||
#if($renderForm)
|
||
<el-dialog custom-class="portal-dialog#if($isGroupedForm) portal-dialog--wide#end" :title="viewing ? ''查看${functionName}'' : (form.${pkColumn.javaField} ? ''编辑${functionName}'' : ''新增${functionName}'')" :visible.sync="dialogFormVisible" width="#if($isGroupedForm)860px#else520px#end">
|
||
<el-form ref="form" :model="form" label-width="110px" size="small" :disabled="viewing">
|
||
#if($isGroupedForm && $formGroups.size() > 0)
|
||
#foreach($group in $formGroups)
|
||
<section class="form-group-card dialog-form-group-card">
|
||
<h3>${group.label}</h3>
|
||
<div class="form-group-grid">
|
||
#foreach($column in $group.columns)
|
||
#renderPageFormField($column)
|
||
#end
|
||
</div>
|
||
</section>
|
||
#end
|
||
#else
|
||
#foreach ($column in $formColumns)
|
||
#set($renderFormField = false)
|
||
#if($designed)
|
||
#set($renderFormField = true)
|
||
#elseif($column.isEdit == "1")
|
||
#set($renderFormField = true)
|
||
#end
|
||
#if($renderFormField)
|
||
#set($javaField=$column.javaField)
|
||
#set($columnComment=$column.displayLabel)
|
||
#set($remoteSelect=$qingRemoteSelectFields.contains($javaField))
|
||
#set($autoIncrementField=$column.isIncrement == "1")
|
||
<el-form-item#if($autoIncrementField) v-if="form.${javaField}"#end label="${columnComment}" prop="${javaField}"#if($column.isRequired == "1" && !$autoIncrementField) :rules="[{ required: true, message: ''${columnComment}不能为空'', trigger: #if($column.htmlType == "select")''change''#else''blur''#end }]"#end>
|
||
#if($column.htmlType == "input")
|
||
<el-input v-model="form.${javaField}"#if($autoIncrementField) disabled#end placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "textarea")
|
||
<el-input v-model="form.${javaField}" type="textarea" placeholder="请输入${columnComment}" />
|
||
#elseif($column.htmlType == "editor")
|
||
<quill-editor
|
||
v-model="form.${javaField}"
|
||
class="rich-text-editor"
|
||
:disabled="viewing"
|
||
:options="{ placeholder: ''请输入${columnComment}'' }" />
|
||
#elseif($column.htmlType == "select" || $column.htmlType == "radio")
|
||
<el-select v-model="form.${javaField}" placeholder="请选择${columnComment}" clearable>
|
||
#if($remoteSelect)
|
||
<el-option
|
||
v-for="item in getSelectOptions(''${javaField}'')"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value" />
|
||
#else
|
||
<el-option
|
||
v-for="item in _dict.getDictDataByType(''${column.dictType}'')"
|
||
:key="item.value"
|
||
:label="item.name"
|
||
:value="item.value" />
|
||
#end
|
||
</el-select>
|
||
#elseif($column.htmlType == "datetime")
|
||
<el-date-picker v-model="form.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${columnComment}" />
|
||
#elseif($column.htmlType == "imageUpload")
|
||
<el-upload
|
||
class="avatar-uploader"
|
||
action="/api/files/upload"
|
||
:show-file-list="false"
|
||
:on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<img v-if="form.${javaField}" :src="resolveResourceUrl(form.${javaField})" class="avatar" />
|
||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||
</el-upload>
|
||
#elseif($column.htmlType == "fileUpload")
|
||
<el-upload
|
||
action="/api/files/upload"
|
||
:on-success="(res) => uploadSuccess(''${javaField}'', res)">
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
</el-upload>
|
||
<div v-if="form.${javaField}" class="file-link">{{ form.${javaField} }}</div>
|
||
#end
|
||
</el-form-item>
|
||
#end
|
||
#end
|
||
#end
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||
<el-button v-if="!viewing" type="primary" @click="save">确定</el-button>
|
||
#foreach($action in $formBusinessActions)
|
||
#set($buttonLabel = $action.buttonLabel)
|
||
#if(!$buttonLabel)#set($buttonLabel = $action.name)#end
|
||
#set($buttonType = $action.buttonType)
|
||
#if(!$buttonType)#set($buttonType = "primary")#end
|
||
#if($action.buttonDisplay != "more")
|
||
<el-button
|
||
v-if="!viewing && isBusinessActionVisible(businessActionMap[''${action.code}''], form)"
|
||
:disabled="isBusinessActionDisabled(businessActionMap[''${action.code}''], form)"
|
||
type="${buttonType}"
|
||
@click="handleBusinessAction(''${action.code}'', form)">${buttonLabel}</el-button>
|
||
#end
|
||
#end
|
||
<el-dropdown v-if="!viewing && overflowBusinessActions(''form'', form).length" @command="code => handleBusinessAction(code, form)">
|
||
<el-button>更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item
|
||
v-for="action in overflowBusinessActions(''form'', form)"
|
||
:key="action.code"
|
||
:command="action.code"
|
||
:disabled="isBusinessActionDisabled(action, form)">{{ action.buttonLabel || action.name }}</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</div>
|
||
</el-dialog>
|
||
#end
|
||
|
||
#if($allPageBusinessActions.size() > 0)
|
||
<el-dialog
|
||
custom-class="portal-dialog portal-dialog--action"
|
||
:title="businessActionDialogTitle"
|
||
:visible.sync="businessActionDialogVisible"
|
||
width="520px"
|
||
append-to-body
|
||
:show-close="!businessActionSubmitting"
|
||
:close-on-click-modal="false"
|
||
:close-on-press-escape="!businessActionSubmitting"
|
||
@closed="resetBusinessActionDialog">
|
||
<p v-if="activeBusinessAction && activeBusinessAction.confirmMessage" class="business-action-hint">
|
||
{{ activeBusinessAction.confirmMessage }}
|
||
</p>
|
||
<el-form
|
||
ref="businessActionForm"
|
||
:model="businessActionForm"
|
||
label-width="110px"
|
||
size="small">
|
||
<el-form-item
|
||
v-for="field in businessActionInputFields"
|
||
:key="field.field"
|
||
:label="field.label"
|
||
:prop="field.field"
|
||
:rules="[{ required: true, message: field.label + ''不能为空'', trigger: field.htmlType === ''select'' ? ''change'' : ''blur'' }]">
|
||
<el-date-picker
|
||
v-if="field.htmlType === ''datetime''"
|
||
v-model="businessActionForm[field.field]"
|
||
type="date"
|
||
value-format="yyyy-MM-dd"
|
||
:placeholder="''请选择'' + field.label" />
|
||
<el-select
|
||
v-else-if="field.htmlType === ''select'' && field.dictType"
|
||
v-model="businessActionForm[field.field]"
|
||
clearable
|
||
:placeholder="''请选择'' + field.label">
|
||
<el-option
|
||
v-for="option in getBusinessActionFieldOptions(field)"
|
||
:key="option.value"
|
||
:label="option.label"
|
||
:value="option.value" />
|
||
</el-select>
|
||
<el-input
|
||
v-else-if="field.htmlType === ''textarea''"
|
||
v-model="businessActionForm[field.field]"
|
||
type="textarea"
|
||
:rows="3"
|
||
:placeholder="''请输入'' + field.label" />
|
||
<el-input
|
||
v-else
|
||
v-model="businessActionForm[field.field]"
|
||
:placeholder="''请输入'' + field.label" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button
|
||
:disabled="businessActionSubmitting"
|
||
@click="businessActionDialogVisible = false">
|
||
取消
|
||
</el-button>
|
||
<el-button
|
||
type="primary"
|
||
:loading="businessActionSubmitting"
|
||
@click="submitBusinessAction">
|
||
{{ activeBusinessAction && activeBusinessAction.buttonLabel ? activeBusinessAction.buttonLabel : ''确认执行'' }}
|
||
</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
#end
|
||
</section>
|
||
</template>
|
||
|
||
<script>
|
||
#foreach($block in $embeddedBusinessBlocks)
|
||
import ${block.componentName} from "${block.relativeImportPath}"
|
||
#end
|
||
|
||
export default {
|
||
name: "${BusinessName}",
|
||
#if($hasPageDesignEmbeddedBusinessBlocks)
|
||
components: {
|
||
#foreach($block in $embeddedBusinessBlocks)
|
||
${block.componentName}#if($foreach.hasNext),#end
|
||
#end
|
||
},
|
||
#end
|
||
data() {
|
||
return {
|
||
${businessName}List: [],
|
||
total: 0,
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
#if($currentUserOnly)
|
||
__currentUserOnly: true,
|
||
#end
|
||
#foreach ($column in $queryColumns)
|
||
#set($renderQueryParam = false)
|
||
#if(!$showQuery)
|
||
#set($renderQueryParam = false)
|
||
#elseif($designed)
|
||
#set($renderQueryParam = true)
|
||
#elseif($column.isQuery == "1")
|
||
#set($renderQueryParam = true)
|
||
#end
|
||
#if($renderQueryParam)
|
||
${column.javaField}: undefined,
|
||
#end
|
||
#end
|
||
},
|
||
#if($isDetailPage)
|
||
detailRecord: {},
|
||
detailLoading: false,
|
||
detailLoaded: false,
|
||
#end
|
||
form: {},
|
||
viewing: false,
|
||
dialogFormVisible: false,
|
||
businessActionDialogVisible: false,
|
||
businessActionSubmitting: false,
|
||
activeBusinessAction: null,
|
||
businessActionBasePayload: {},
|
||
businessActionForm: {},
|
||
businessActionInputFields: [],
|
||
multipleSelection: [],
|
||
remoteOptionMap: {},
|
||
remoteSelectConfig: {
|
||
#foreach($remote in $qingRemoteSelects)
|
||
${remote.field}: {
|
||
path: "${remote.path}",
|
||
valueField: "${remote.valueField}",
|
||
labelField: "${remote.labelField}"
|
||
}#if($foreach.hasNext),#end
|
||
#end
|
||
},
|
||
businessActionMap: {
|
||
#foreach($action in $allPageBusinessActions)
|
||
"${action.code}": {
|
||
name: "${action.name}",
|
||
buttonLabel: "${action.buttonLabel}",
|
||
method: "${action.method}",
|
||
path: "${action.path}",
|
||
successMessage: "${action.successMessage}",
|
||
refreshTarget: "${action.refreshTarget}",
|
||
confirmMessage: "${action.confirmMessage}",
|
||
display: "${action.buttonDisplay}",
|
||
permission: "${action.permission}",
|
||
placement: "${action.placement}",
|
||
#set($visibleWhen = $action.visibleWhen)
|
||
#set($disabledWhen = $action.disabledWhen)
|
||
visibleWhen: {
|
||
field: "$!visibleWhen.field",
|
||
operator: "$!visibleWhen.operator",
|
||
values: [#if($visibleWhen && $visibleWhen.values)#foreach($value in $visibleWhen.values)"${value}"#if($foreach.hasNext), #end#end#end]
|
||
},
|
||
disabledWhen: {
|
||
field: "$!disabledWhen.field",
|
||
operator: "$!disabledWhen.operator",
|
||
values: [#if($disabledWhen && $disabledWhen.values)#foreach($value in $disabledWhen.values)"${value}"#if($foreach.hasNext), #end#end#end]
|
||
},
|
||
requestFields: [#foreach($field in $action.requestFields)"${field}"#if($foreach.hasNext), #end#end],
|
||
currentUserFields: [#foreach($field in $action.currentUserFields)"${field}"#if($foreach.hasNext), #end#end],
|
||
inputMapping: {#set($inputMapping = $action.inputMapping)#if($inputMapping)#foreach($entry in $inputMapping.entrySet())"${entry.key}": "${entry.value}"#if($foreach.hasNext), #end#end#end},
|
||
inputFields: [
|
||
#foreach($field in $action.inputFields)
|
||
{
|
||
field: "${field.field}",
|
||
label: "${field.label}",
|
||
htmlType: "${field.htmlType}",
|
||
dictType: "${field.dictType}"
|
||
}#if($foreach.hasNext),#end
|
||
#end
|
||
]
|
||
}#if($foreach.count != $allPageBusinessActions.size()),#end
|
||
#end
|
||
},
|
||
routeActionMap: {
|
||
#foreach($routeAction in $pageDesignRouteActionEntries)
|
||
"${routeAction.key}": {
|
||
path: "${routeAction.path}",
|
||
paramMap: {#set($paramMap = $routeAction.paramMap)#foreach($param in $paramMap.entrySet())"${param.key}":"${param.value}"#if($foreach.count != $paramMap.size()),#end#end}
|
||
}#if($foreach.count != $pageDesignRouteActionEntries.size()),#end
|
||
#end
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
businessActionDialogTitle() {
|
||
if (!this.activeBusinessAction) {
|
||
return "业务操作"
|
||
}
|
||
return this.activeBusinessAction.buttonLabel || this.activeBusinessAction.name || "业务操作"
|
||
}
|
||
},
|
||
created() {
|
||
this.loadRemoteOptions()
|
||
#if($isDetailPage)
|
||
this.loadDetail()
|
||
#else
|
||
this.load()
|
||
#end
|
||
},
|
||
methods: {
|
||
loadRemoteOptions() {
|
||
Object.keys(this.remoteSelectConfig).forEach(field => {
|
||
const config = this.remoteSelectConfig[field]
|
||
this.request.get(config.path, {
|
||
params: { pageNum: 1, pageSize: 999 }
|
||
}).then(res => {
|
||
const data = res.data || {}
|
||
const records = Array.isArray(data) ? data : (data.records || [])
|
||
const options = records.map(item => ({
|
||
value: item[config.valueField],
|
||
label: item[config.labelField]
|
||
}))
|
||
this.#[[$set]]#(this.remoteOptionMap, field, options)
|
||
})
|
||
})
|
||
},
|
||
getSelectOptions(field) {
|
||
return this.remoteOptionMap[field] || []
|
||
},
|
||
getOptionLabel(field, value) {
|
||
const option = this.getSelectOptions(field).find(item => String(item.value) === String(value))
|
||
if (option) {
|
||
return option.label
|
||
}
|
||
return value === undefined || value === null || value === "" ? "-" : value
|
||
},
|
||
#if(!$isDetailPage)
|
||
load() {
|
||
this.request.get("${requestPath}/page", {
|
||
params: this.queryParams
|
||
}).then(res => {
|
||
const page = res.data || {}
|
||
this.${businessName}List = page.records || []
|
||
this.total = page.total || 0
|
||
})
|
||
},
|
||
#end
|
||
#if($isDetailPage)
|
||
resolveDetailId() {
|
||
const params = this.#[[$route]]# && this.#[[$route]]#.params ? this.#[[$route]]#.params : {}
|
||
return params.id || params.${pkColumn.javaField} || ""
|
||
},
|
||
loadDetail() {
|
||
const detailId = this.resolveDetailId()
|
||
if (!detailId) {
|
||
this.detailRecord = {}
|
||
this.form = {}
|
||
this.detailLoaded = true
|
||
return
|
||
}
|
||
this.detailLoading = true
|
||
this.request.get("${requestPath}/" + detailId).then(res => {
|
||
this.detailRecord = res.data || {}
|
||
this.form = JSON.parse(JSON.stringify(this.detailRecord))
|
||
this.detailLoaded = true
|
||
}).finally(() => {
|
||
this.detailLoading = false
|
||
})
|
||
},
|
||
formatDetailValue(value) {
|
||
return value === undefined || value === null || value === "" ? "-" : value
|
||
},
|
||
#end
|
||
save() {
|
||
this.#[[$refs]]#.form.validate(valid => {
|
||
if (!valid) {
|
||
return
|
||
}
|
||
this.request.post("${requestPath}", this.form).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("保存成功")
|
||
this.dialogFormVisible = false
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "保存失败")
|
||
}
|
||
})
|
||
})
|
||
},
|
||
handleAdd() {
|
||
if (this.handleConfiguredRoute("toolbar:create")) {
|
||
return
|
||
}
|
||
this.form = {}
|
||
this.viewing = false
|
||
this.dialogFormVisible = true
|
||
this.#[[$nextTick]]#(() => this.#[[$refs]]#.form && this.#[[$refs]]#.form.clearValidate())
|
||
},
|
||
handleView(row) {
|
||
if (this.handleConfiguredRoute("table:view", row)) {
|
||
return
|
||
}
|
||
if (this.handleConfiguredRoute("cardActions:view", row)) {
|
||
return
|
||
}
|
||
this.form = JSON.parse(JSON.stringify(row))
|
||
this.viewing = true
|
||
this.dialogFormVisible = true
|
||
},
|
||
handleEdit(row) {
|
||
if (this.handleConfiguredRoute("table:edit", row)) {
|
||
return
|
||
}
|
||
if (this.handleConfiguredRoute("cardActions:edit", row)) {
|
||
return
|
||
}
|
||
this.form = JSON.parse(JSON.stringify(row))
|
||
this.viewing = false
|
||
this.dialogFormVisible = true
|
||
this.#[[$nextTick]]#(() => this.#[[$refs]]#.form && this.#[[$refs]]#.form.clearValidate())
|
||
},
|
||
del(${pkColumn.javaField}) {
|
||
this.request.delete("${requestPath}/" + ${pkColumn.javaField}).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("删除成功")
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "删除失败")
|
||
}
|
||
})
|
||
},
|
||
handleSelectionChange(val) {
|
||
this.multipleSelection = val
|
||
},
|
||
handleCardSelectionChange() {
|
||
this.multipleSelection = this.${businessName}List.filter(item => item.__checked)
|
||
},
|
||
handleConfiguredRoute(actionKey, row) {
|
||
const action = this.routeActionMap[actionKey]
|
||
if (!action || !action.path) {
|
||
return false
|
||
}
|
||
const path = this.buildConfiguredRoutePath(action.path, action.paramMap || {}, row)
|
||
if (!path) {
|
||
return false
|
||
}
|
||
this.#[[$router]]#.push(path)
|
||
return true
|
||
},
|
||
buildConfiguredRoutePath(routePath, paramMap, row) {
|
||
let path = routePath
|
||
Object.keys(paramMap || {}).forEach(param => {
|
||
const field = paramMap[param]
|
||
const value = row && row[field]
|
||
if (value !== undefined && value !== null && value !== "") {
|
||
path = path.replace(new RegExp(":" + param + "(?=/|$)", "g"), encodeURIComponent(value))
|
||
}
|
||
})
|
||
return this.hasUnresolvedRouteParam(path) ? "" : path
|
||
},
|
||
hasUnresolvedRouteParam(path) {
|
||
return String(path || "").split("/").some(segment => segment.indexOf(":") === 0)
|
||
},
|
||
delBatch() {
|
||
const ids = this.multipleSelection.map(item => item.${pkColumn.javaField})
|
||
if (!ids.length) {
|
||
this.#[[$message]]#.warning("请先选择要删除的数据")
|
||
return
|
||
}
|
||
this.request.post("${requestPath}/del/batch", ids).then(res => {
|
||
if (res.code === "200") {
|
||
this.#[[$message]]#.success("批量删除成功")
|
||
this.load()
|
||
} else {
|
||
this.#[[$message]]#.error(res.msg || "批量删除失败")
|
||
}
|
||
})
|
||
},
|
||
reset() {
|
||
this.queryParams = {
|
||
pageNum: 1,
|
||
pageSize: 10#if($currentUserOnly),
|
||
__currentUserOnly: true#end
|
||
}
|
||
this.load()
|
||
},
|
||
resetStandaloneForm() {
|
||
this.form = {}
|
||
this.#[[$nextTick]]#(() => this.#[[$refs]]#.form && this.#[[$refs]]#.form.clearValidate())
|
||
},
|
||
hasBusinessActionPermission(action) {
|
||
if (!action || !action.permission) {
|
||
return true
|
||
}
|
||
const permissions = typeof window !== "undefined" ? window.__PAGE_PERMISSIONS__ : null
|
||
if (!Array.isArray(permissions) || !permissions.length) {
|
||
return true
|
||
}
|
||
return permissions.includes("*:*:*") || permissions.includes(action.permission)
|
||
},
|
||
businessConditionMatches(condition, row) {
|
||
if (!condition || !condition.field) {
|
||
return false
|
||
}
|
||
const source = row || {}
|
||
const camelField = String(condition.field).replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
|
||
const actual = source[condition.field] !== undefined ? source[condition.field] : source[camelField]
|
||
const values = Array.isArray(condition.values) ? condition.values.map(value => String(value)) : []
|
||
const actualValue = actual === undefined || actual === null ? "" : String(actual)
|
||
if (condition.operator === "eq") return values.length > 0 && actualValue === values[0]
|
||
if (condition.operator === "ne") return values.length > 0 && actualValue !== values[0]
|
||
if (condition.operator === "notIn") return !values.includes(actualValue)
|
||
return values.includes(actualValue)
|
||
},
|
||
isBusinessActionVisible(action, row) {
|
||
if (!this.hasBusinessActionPermission(action)) {
|
||
return false
|
||
}
|
||
return !action || !action.visibleWhen || !action.visibleWhen.field
|
||
? true
|
||
: this.businessConditionMatches(action.visibleWhen, row)
|
||
},
|
||
isBusinessActionDisabled(action, row) {
|
||
return !this.hasBusinessActionPermission(action)
|
||
|| Boolean(action && action.disabledWhen && action.disabledWhen.field
|
||
&& this.businessConditionMatches(action.disabledWhen, row))
|
||
},
|
||
overflowBusinessActions(surface, row) {
|
||
const placements = surface === "toolbar"
|
||
? ["toolbar"]
|
||
: surface === "form"
|
||
? ["formActions"]
|
||
: ["table", "cardActions", "detailActions"]
|
||
return Object.keys(this.businessActionMap)
|
||
.map(code => Object.assign({ code }, this.businessActionMap[code]))
|
||
.filter(action => action.display === "more" && placements.includes(action.placement)
|
||
&& this.isBusinessActionVisible(action, row))
|
||
},
|
||
handleBusinessAction(code, row) {
|
||
if (this.handleConfiguredRoute("business:" + code, row) || this.handleConfiguredRoute("toolbar:" + code, row) || this.handleConfiguredRoute("table:" + code, row)) {
|
||
return
|
||
}
|
||
const action = this.businessActionMap[code]
|
||
if (!action || !action.path) {
|
||
this.#[[$message]]#.warning("动作未配置")
|
||
return
|
||
}
|
||
if (!this.isBusinessActionVisible(action, row) || this.isBusinessActionDisabled(action, row)) {
|
||
return
|
||
}
|
||
const payload = this.buildBusinessActionPayload(action, row)
|
||
const missingFields = (action.inputFields || []).filter(field => !this.hasBusinessActionValue(payload[field.field]))
|
||
if (missingFields.length > 0) {
|
||
this.openBusinessActionDialog(action, payload, missingFields)
|
||
return
|
||
}
|
||
if (action.confirmMessage) {
|
||
this.#[[$confirm]]#(action.confirmMessage, "提示", {
|
||
confirmButtonText: "确定",
|
||
cancelButtonText: "取消",
|
||
type: "warning"
|
||
}).then(() => this.executeBusinessAction(action, payload)).catch(() => {})
|
||
return
|
||
}
|
||
this.executeBusinessAction(action, payload).catch(() => {})
|
||
},
|
||
openBusinessActionDialog(action, payload, fields) {
|
||
const form = {}
|
||
fields.forEach(field => {
|
||
form[field.field] = this.hasBusinessActionValue(payload[field.field]) ? payload[field.field] : undefined
|
||
})
|
||
this.activeBusinessAction = action
|
||
this.businessActionBasePayload = Object.assign({}, payload)
|
||
this.businessActionInputFields = fields.slice()
|
||
this.businessActionForm = form
|
||
this.businessActionDialogVisible = true
|
||
this.#[[$nextTick]]#(() => {
|
||
const formRef = this.#[[$refs]]#.businessActionForm
|
||
if (formRef) {
|
||
formRef.clearValidate()
|
||
}
|
||
})
|
||
},
|
||
submitBusinessAction() {
|
||
const formRef = this.#[[$refs]]#.businessActionForm
|
||
if (!formRef || !this.activeBusinessAction) {
|
||
return
|
||
}
|
||
formRef.validate(valid => {
|
||
if (!valid) {
|
||
return
|
||
}
|
||
const action = this.activeBusinessAction
|
||
const payload = Object.assign({}, this.businessActionBasePayload, this.businessActionForm)
|
||
this.businessActionSubmitting = true
|
||
this.executeBusinessAction(action, payload)
|
||
.then(() => {
|
||
this.businessActionDialogVisible = false
|
||
})
|
||
.catch(() => {})
|
||
.finally(() => {
|
||
this.businessActionSubmitting = false
|
||
})
|
||
})
|
||
},
|
||
resetBusinessActionDialog() {
|
||
this.activeBusinessAction = null
|
||
this.businessActionBasePayload = {}
|
||
this.businessActionForm = {}
|
||
this.businessActionInputFields = []
|
||
},
|
||
hasBusinessActionValue(value) {
|
||
if (value === undefined || value === null) {
|
||
return false
|
||
}
|
||
return typeof value !== "string" || value.trim() !== ""
|
||
},
|
||
getBusinessActionFieldOptions(field) {
|
||
if (!field || !field.dictType) {
|
||
return []
|
||
}
|
||
return this._dict.getDictDataByType(field.dictType).map(option => ({
|
||
label: option.name,
|
||
value: option.value
|
||
}))
|
||
},
|
||
executeBusinessAction(action, payload) {
|
||
const method = String(action.method || "POST").toLowerCase()
|
||
const request = method === "get"
|
||
? this.request.get(action.path, { params: payload })
|
||
: this.request[method] ? this.request[method](action.path, payload) : this.request.post(action.path, payload)
|
||
return request.then(res => {
|
||
if (res.code !== "200") {
|
||
return Promise.reject(new Error(res.msg || "操作失败"))
|
||
}
|
||
this.#[[$message]]#.success(action.successMessage || "操作成功")
|
||
this.refreshBusinessActionTarget(action.refreshTarget)
|
||
return res
|
||
}).catch(error => {
|
||
const data = error && error.response ? error.response.data : null
|
||
this.#[[$message]]#.error((data && data.msg) || (error && error.message) || "操作失败")
|
||
return Promise.reject(error)
|
||
})
|
||
},
|
||
refreshBusinessActionTarget(refreshTarget) {
|
||
const target = refreshTarget || "list"
|
||
if (target === "none") {
|
||
return
|
||
}
|
||
if (target === "page") {
|
||
window.location.reload()
|
||
return
|
||
}
|
||
#if($isDetailPage)
|
||
this.loadDetail()
|
||
#else
|
||
this.load()
|
||
#end
|
||
},
|
||
buildBusinessActionPayload(action, row) {
|
||
const payload = {}
|
||
const record = row || this.detailRecord || {}
|
||
Object.keys(record).forEach(field => {
|
||
if (field.indexOf("__") !== 0 && record[field] !== undefined) {
|
||
payload[field] = record[field]
|
||
}
|
||
})
|
||
const currentUserFields = new Set(action.currentUserFields || [])
|
||
;(action.requestFields || []).forEach(field => {
|
||
if (currentUserFields.has(field)) {
|
||
return
|
||
}
|
||
const value = this.resolvePayloadValue(field, row, action.inputMapping)
|
||
if (value !== undefined) {
|
||
payload[field] = value
|
||
}
|
||
})
|
||
return payload
|
||
},
|
||
resolvePayloadValue(field, row, inputMapping) {
|
||
const mappedValue = this.resolveMappedPayloadValue(inputMapping && inputMapping[field], row)
|
||
if (mappedValue !== undefined) {
|
||
return mappedValue
|
||
}
|
||
const camelField = this.toCamelCase(field)
|
||
const sources = [row, this.detailRecord, this.form, this.queryParams]
|
||
for (const source of sources) {
|
||
const value = this.readBusinessSourceValue(source, field, camelField)
|
||
if (value !== undefined) {
|
||
return value
|
||
}
|
||
}
|
||
return undefined
|
||
},
|
||
resolveMappedPayloadValue(expression, row) {
|
||
if (!expression || String(expression).indexOf(".") < 0) {
|
||
return undefined
|
||
}
|
||
const separator = String(expression).indexOf(".")
|
||
const sourceName = String(expression).substring(0, separator)
|
||
const sourceField = String(expression).substring(separator + 1)
|
||
const routeParams = this.#[[$route]]# && this.#[[$route]]#.params ? this.#[[$route]]#.params : {}
|
||
const sources = {
|
||
row,
|
||
detail: this.detailRecord,
|
||
form: this.form,
|
||
param: Object.assign({}, this.queryParams, routeParams)
|
||
}
|
||
return this.readBusinessSourceValue(sources[sourceName], sourceField, this.toCamelCase(sourceField))
|
||
},
|
||
readBusinessSourceValue(source, field, camelField) {
|
||
if (!source) {
|
||
return undefined
|
||
}
|
||
if (source[field] !== undefined) {
|
||
return source[field]
|
||
}
|
||
return source[camelField]
|
||
},
|
||
toCamelCase(value) {
|
||
return String(value || "").replace(/_([a-zA-Z0-9])/g, (_, char) => char.toUpperCase())
|
||
},
|
||
handleSizeChange(pageSize) {
|
||
this.queryParams.pageSize = pageSize
|
||
this.load()
|
||
},
|
||
handleCurrentChange(pageNum) {
|
||
this.queryParams.pageNum = pageNum
|
||
this.load()
|
||
},
|
||
resolveResourceUrl(url) {
|
||
if (!url) {
|
||
return ""
|
||
}
|
||
if (url.indexOf("http://") === 0 || url.indexOf("https://") === 0 || url.indexOf("//") === 0 || url.indexOf("data:") === 0 || url.indexOf("blob:") === 0) {
|
||
return url
|
||
}
|
||
if (url.indexOf("/api/") === 0) {
|
||
return url
|
||
}
|
||
if (url.indexOf("/files/") === 0) {
|
||
return "/api" + url
|
||
}
|
||
return url
|
||
},
|
||
uploadSuccess(field, res) {
|
||
if (res && res.code === "200" && res.data && res.data.url) {
|
||
this.#[[$set]]#(this.form, field, res.data.url)
|
||
} else {
|
||
this.#[[$message]]#.error("上传失败,请重试")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.portal-page {
|
||
display: grid;
|
||
gap: 24px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.embedded-business-blocks {
|
||
display: grid;
|
||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||
gap: 20px;
|
||
}
|
||
|
||
.embedded-business-block__item--span-12 { grid-column: span 12; }
|
||
.embedded-business-block__item--span-6 { grid-column: span 6; }
|
||
.embedded-business-block__item--span-4 { grid-column: span 4; }
|
||
|
||
|
||
@media (max-width: 900px) {
|
||
.embedded-business-block__item {
|
||
grid-column: span 12;
|
||
}
|
||
}
|
||
|
||
.panel-heading h2 {
|
||
margin: 0;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
|
||
.data-panel {
|
||
min-width: 0;
|
||
padding: 24px;
|
||
border: 1px solid var(--portal-border, #e3e9f1);
|
||
border-radius: var(--portal-radius-md, 12px);
|
||
background: var(--portal-surface, #ffffff);
|
||
box-shadow: var(--portal-shadow-sm, 0 8px 24px rgba(15, 23, 42, 0.06));
|
||
}
|
||
|
||
.split-data-panel {
|
||
display: grid;
|
||
grid-template-columns: minmax(220px, 260px) minmax(0, 1fr);
|
||
gap: 20px;
|
||
}
|
||
|
||
.split-data-panel .panel-heading {
|
||
grid-column: 1 / -1;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.split-data-panel .filter-bar {
|
||
align-content: flex-start;
|
||
align-self: start;
|
||
flex-direction: column;
|
||
margin-bottom: 0;
|
||
padding: 14px;
|
||
border: 1px solid var(--portal-border, #e3e9f1);
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
background: #f7f9fc;
|
||
}
|
||
|
||
.split-data-panel .filter-item,
|
||
.split-data-panel .filter-bar .el-button {
|
||
width: 100%;
|
||
}
|
||
|
||
.split-data-panel .resource-table,
|
||
.split-data-panel .resource-card-grid,
|
||
.split-data-panel .pagination {
|
||
margin-top: 14px;
|
||
text-align: right;
|
||
}
|
||
|
||
.panel-heading {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 22px;
|
||
}
|
||
|
||
.panel-heading h2 {
|
||
margin: 0;
|
||
color: var(--portal-text, #172033);
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.panel-actions,
|
||
.filter-bar {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
|
||
.filter-bar {
|
||
margin-bottom: 20px;
|
||
padding: 14px;
|
||
border: 1px solid #e8edf4;
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
background: #f8fafc;
|
||
}
|
||
|
||
.filter-item {
|
||
width: 220px;
|
||
}
|
||
|
||
.resource-table {
|
||
width: 100%;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
}
|
||
|
||
.portal-page >>> .el-table th {
|
||
height: 48px;
|
||
color: #526071;
|
||
background: #f7f9fc;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.portal-page >>> .el-table td {
|
||
padding: 13px 0;
|
||
border-color: #edf1f5;
|
||
}
|
||
|
||
.portal-page >>> .el-button {
|
||
min-height: 36px;
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
}
|
||
|
||
.portal-page >>> .el-button--text {
|
||
min-height: auto;
|
||
}
|
||
|
||
.portal-page >>> .el-button--primary {
|
||
border-color: var(--portal-primary, #167d83);
|
||
background: var(--portal-primary, #167d83);
|
||
}
|
||
|
||
.portal-page >>> .el-button--primary.is-plain {
|
||
color: var(--portal-primary-strong, #11656a);
|
||
border-color: #b9dddd;
|
||
background: var(--portal-primary-soft, #eaf7f7);
|
||
}
|
||
|
||
.portal-page >>> .el-input__inner,
|
||
.portal-page >>> .el-textarea__inner {
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
}
|
||
|
||
.resource-card-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||
gap: 18px;
|
||
}
|
||
|
||
.resource-card-item {
|
||
position: relative;
|
||
display: grid;
|
||
gap: 14px;
|
||
min-height: 190px;
|
||
padding: 18px;
|
||
border: 1px solid var(--portal-border, #e3e9f1);
|
||
border-radius: var(--portal-radius-md, 12px);
|
||
background: var(--portal-surface, #ffffff);
|
||
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.04);
|
||
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
|
||
}
|
||
|
||
.resource-card-item:hover {
|
||
border-color: #c8d6e6;
|
||
box-shadow: 0 14px 30px rgba(15, 23, 42, 0.09);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.resource-card-check {
|
||
position: absolute;
|
||
top: 12px;
|
||
right: 12px;
|
||
}
|
||
|
||
.resource-card-body {
|
||
display: grid;
|
||
gap: 10px;
|
||
}
|
||
|
||
.resource-card-field {
|
||
display: grid;
|
||
gap: 4px;
|
||
}
|
||
|
||
.resource-card-title {
|
||
margin: 0;
|
||
color: var(--portal-text, #172033);
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.resource-card-field span {
|
||
color: #7b8493;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.resource-card-field strong {
|
||
color: var(--portal-text, #172033);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.resource-card-image {
|
||
width: 100%;
|
||
height: 168px;
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
object-fit: cover;
|
||
background: #eef3f8;
|
||
}
|
||
|
||
.resource-card-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-end;
|
||
gap: 8px;
|
||
padding-top: 12px;
|
||
border-top: 1px solid var(--portal-border, #edf0f5);
|
||
}
|
||
|
||
.resource-card-actions >>> .resource-card-action.el-button {
|
||
min-width: 84px;
|
||
height: 32px;
|
||
margin-left: 0;
|
||
padding: 7px 14px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.detail-view {
|
||
min-height: 180px;
|
||
}
|
||
|
||
.detail-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||
gap: 14px 18px;
|
||
margin: 0;
|
||
}
|
||
|
||
.media-detail-view {
|
||
margin-bottom: 22px;
|
||
}
|
||
|
||
.media-detail-hero {
|
||
display: grid;
|
||
grid-template-columns: minmax(220px, 340px) minmax(0, 1fr);
|
||
gap: 28px;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.media-detail-image {
|
||
width: 100%;
|
||
min-height: 220px;
|
||
border-radius: var(--portal-radius-md, 12px);
|
||
object-fit: cover;
|
||
background: #eef3f8;
|
||
}
|
||
|
||
.media-detail-image.empty {
|
||
border: 1px dashed #d8e0ea;
|
||
}
|
||
|
||
.media-detail-copy {
|
||
display: grid;
|
||
align-content: center;
|
||
gap: 12px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.media-detail-copy h2 {
|
||
margin: 0;
|
||
color: #172033;
|
||
font-size: 28px;
|
||
line-height: 1.28;
|
||
}
|
||
|
||
.media-detail-copy p {
|
||
margin: 0;
|
||
color: #5f6b7a;
|
||
font-size: 15px;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.media-detail-grid {
|
||
padding-top: 18px;
|
||
border-top: 1px solid #edf0f5;
|
||
}
|
||
|
||
.detail-field {
|
||
display: grid;
|
||
gap: 6px;
|
||
padding: 14px 0;
|
||
border-bottom: 1px solid #edf0f5;
|
||
}
|
||
|
||
.detail-field.wide {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.detail-field dt {
|
||
color: #7b8493;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.detail-field dd {
|
||
margin: 0;
|
||
color: #172033;
|
||
font-size: 15px;
|
||
line-height: 1.65;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.detail-image {
|
||
width: 180px;
|
||
height: 128px;
|
||
border-radius: 4px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.detail-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-top: 18px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid var(--portal-border, #e3e9f1);
|
||
}
|
||
|
||
.standalone-form-page {
|
||
max-width: 920px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.form-group-card {
|
||
margin-bottom: 18px;
|
||
padding: 20px;
|
||
border: 1px solid var(--portal-border, #e3e9f1);
|
||
border-radius: var(--portal-radius-md, 12px);
|
||
background: #f9fbfd;
|
||
}
|
||
|
||
.form-group-card h3 {
|
||
margin: 0 0 16px;
|
||
color: #172033;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.form-group-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 0 18px;
|
||
}
|
||
|
||
.form-page-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid var(--portal-border, #e3e9f1);
|
||
}
|
||
|
||
.standalone-form-page >>> .el-date-editor,
|
||
.standalone-form-page >>> .el-select,
|
||
.standalone-form-page >>> .el-input {
|
||
width: 100%;
|
||
}
|
||
|
||
@media (max-width: 720px) {
|
||
.form-group-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.empty-detail {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-height: 120px;
|
||
color: #7b8493;
|
||
}
|
||
|
||
.pagination {
|
||
max-width: 100%;
|
||
margin-top: 14px;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
text-align: right;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog {
|
||
max-width: calc(100vw - 32px);
|
||
border-radius: var(--portal-radius-md, 12px);
|
||
overflow: hidden;
|
||
box-shadow: var(--portal-shadow-md, 0 18px 44px rgba(15, 23, 42, 0.12));
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__header {
|
||
padding: 22px 24px 16px;
|
||
border-bottom: 1px solid var(--portal-border, #e3e9f1);
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__title {
|
||
color: var(--portal-text, #172033);
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__body {
|
||
max-height: min(68vh, 720px);
|
||
padding: 22px 24px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__footer {
|
||
padding: 16px 24px 20px;
|
||
border-top: 1px solid var(--portal-border, #e3e9f1);
|
||
}
|
||
|
||
.danger-text {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
.table-image {
|
||
width: 52px;
|
||
height: 52px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.avatar-uploader .avatar {
|
||
display: block;
|
||
width: 96px;
|
||
height: 96px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.avatar-uploader-icon {
|
||
width: 96px;
|
||
height: 96px;
|
||
border: 1px dashed #d9d9d9;
|
||
border-radius: 4px;
|
||
color: #8c939d;
|
||
line-height: 96px;
|
||
text-align: center;
|
||
}
|
||
|
||
.file-link {
|
||
margin-top: 6px;
|
||
color: #606266;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.rich-text-editor >>> .ql-editor {
|
||
min-height: 160px;
|
||
}
|
||
|
||
.business-action-hint {
|
||
margin: 0 0 18px;
|
||
padding: 10px 12px;
|
||
border-radius: 4px;
|
||
color: #606266;
|
||
background: #f5f7fa;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.business-action-hint + .el-form .el-date-editor,
|
||
.business-action-hint + .el-form .el-select,
|
||
.business-action-hint + .el-form .el-input,
|
||
.el-dialog .el-form .el-date-editor,
|
||
.el-dialog .el-form .el-select {
|
||
width: 100%;
|
||
}
|
||
|
||
|
||
@media (max-width: 720px) {
|
||
.split-data-panel {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.split-data-panel .panel-heading,
|
||
.split-data-panel .resource-table,
|
||
.split-data-panel .resource-card-grid,
|
||
.split-data-panel .pagination {
|
||
grid-column: 1;
|
||
}
|
||
|
||
.panel-heading {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.filter-item {
|
||
width: 100%;
|
||
}
|
||
|
||
.data-panel {
|
||
padding: 16px;
|
||
border-radius: var(--portal-radius-sm, 8px);
|
||
}
|
||
|
||
.panel-heading {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.panel-heading h2 {
|
||
font-size: 21px;
|
||
}
|
||
|
||
.panel-actions,
|
||
.filter-bar {
|
||
width: 100%;
|
||
}
|
||
|
||
.filter-bar {
|
||
padding: 12px;
|
||
}
|
||
|
||
.filter-bar .el-button {
|
||
flex: 1 1 auto;
|
||
}
|
||
|
||
.resource-card-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.resource-card-item {
|
||
padding: 16px;
|
||
}
|
||
|
||
.media-detail-hero {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.media-detail-image {
|
||
min-height: 200px;
|
||
max-height: 340px;
|
||
}
|
||
|
||
.pagination {
|
||
text-align: center;
|
||
}
|
||
|
||
.pagination >>> .el-pagination__sizes,
|
||
.pagination >>> .el-pagination__jump {
|
||
display: none;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog {
|
||
width: calc(100vw - 24px) !important;
|
||
margin-top: 6vh !important;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__header,
|
||
.portal-page >>> .portal-dialog .el-dialog__body,
|
||
.portal-page >>> .portal-dialog .el-dialog__footer {
|
||
padding-left: 16px;
|
||
padding-right: 16px;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-dialog__body {
|
||
max-height: 72vh;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-form-item__label,
|
||
.standalone-form-page >>> .el-form-item__label {
|
||
float: none;
|
||
width: auto !important;
|
||
padding: 0 0 8px;
|
||
line-height: 1.4;
|
||
text-align: left;
|
||
}
|
||
|
||
.portal-page >>> .portal-dialog .el-form-item__content,
|
||
.standalone-form-page >>> .el-form-item__content {
|
||
margin-left: 0 !important;
|
||
}
|
||
}
|
||
</style>
|
||
', 'admin', sysdate()),
|
||
(920312, 9203, 'frontend-login.vue.vm', NULL, 'frontend-login.vue.vm', '#set($portalProjectName = $projectName)
|
||
#if(!$portalProjectName || $portalProjectName == "")
|
||
#set($portalProjectName = $functionName)
|
||
#end
|
||
#if(!$portalProjectName || $portalProjectName == "")
|
||
#set($portalProjectName = "Portal")
|
||
#end
|
||
#set($portalDefaultPath = $defaultFrontendPath)
|
||
#if(!$portalDefaultPath || $portalDefaultPath == "")
|
||
#set($portalDefaultPath = $requestPath)
|
||
#end
|
||
<template>
|
||
<section class="portal-login">
|
||
<div class="login-visual" aria-hidden="true">
|
||
<div class="login-brand">
|
||
<span class="login-logo"></span>
|
||
<strong>${portalProjectName}</strong>
|
||
</div>
|
||
<h1>欢迎使用</h1>
|
||
<p>登录后继续访问项目功能与个人服务。</p>
|
||
</div>
|
||
|
||
<div class="login-panel">
|
||
<div class="login-heading">
|
||
<span>欢迎回来</span>
|
||
<h2>账号登录</h2>
|
||
</div>
|
||
|
||
<el-alert
|
||
v-if="roleOptions.length === 0"
|
||
title="当前没有可登录的前台角色,请联系管理员检查系统角色配置。"
|
||
type="warning"
|
||
:closable="false"
|
||
class="login-alert"
|
||
/>
|
||
|
||
<el-form :model="form" label-position="top" class="login-form" @submit.native.prevent>
|
||
#if($showPortalRoleSelector)
|
||
<el-form-item label="登录角色">
|
||
<el-select v-model="form.roleCode" placeholder="请选择登录角色" class="role-select">
|
||
<el-option
|
||
v-for="role in roleOptions"
|
||
:key="role.value"
|
||
:label="role.label"
|
||
:value="role.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
#end
|
||
<el-form-item label="账号">
|
||
<el-input v-model="form.account" placeholder="请输入账号" prefix-icon="el-icon-user" />
|
||
</el-form-item>
|
||
<el-form-item label="密码">
|
||
<el-input v-model="form.password" type="password" placeholder="请输入密码" prefix-icon="el-icon-lock" show-password />
|
||
</el-form-item>
|
||
<el-button type="primary" class="login-button" :loading="loading" :disabled="roleOptions.length === 0" @click="handleLogin">登录</el-button>
|
||
</el-form>
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<script>
|
||
const roleOptions = [
|
||
#foreach($role in $portalAuthBindings)
|
||
{ label: "${role.roleNameLiteral}", value: "${role.roleCodeLiteral}", sampleAccount: "${role.sampleAccountLiteral}" }#if($foreach.hasNext),#end
|
||
#end
|
||
]
|
||
|
||
const defaultRole = roleOptions.length > 0 ? roleOptions[0] : null
|
||
|
||
export default {
|
||
name: "PortalLogin",
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
roleOptions,
|
||
form: {
|
||
roleCode: defaultRole ? defaultRole.value : "",
|
||
account: defaultRole ? defaultRole.sampleAccount : "",
|
||
password: "123456"
|
||
}
|
||
}
|
||
},
|
||
watch: {
|
||
"form.roleCode"(roleCode) {
|
||
const role = this.roleOptions.find(item => item.value === roleCode)
|
||
if (role && (!this.form.account || this.roleOptions.some(item => item.sampleAccount === this.form.account))) {
|
||
this.form.account = role.sampleAccount
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
handleLogin() {
|
||
if (!this.form.roleCode) {
|
||
this.#[[$message]]#.warning("请选择登录角色")
|
||
return
|
||
}
|
||
if (!this.form.account || !this.form.password) {
|
||
this.#[[$message]]#.warning("请输入账号和密码")
|
||
return
|
||
}
|
||
|
||
this.loading = true
|
||
this.request.post("/auth/login", this.form)
|
||
.then(res => {
|
||
if (!res || res.code !== "200" || !res.data || !res.data.token) {
|
||
throw new Error((res && res.msg) || "登录失败")
|
||
}
|
||
localStorage.setItem("portal-token", res.data.token)
|
||
localStorage.setItem("portal-user", JSON.stringify(res.data.user || {
|
||
account: this.form.account,
|
||
displayName: this.form.account,
|
||
roleCode: this.form.roleCode
|
||
}))
|
||
window.dispatchEvent(new Event("portal-user-change"))
|
||
this.#[[$message]]#.success("登录成功")
|
||
const redirect = this.#[[$route]]#.query.redirect || "${portalDefaultPath}"
|
||
this.#[[$router]]#.push(redirect)
|
||
})
|
||
.catch(error => {
|
||
this.#[[$message]]#.error(error.message || "登录失败")
|
||
})
|
||
.finally(() => {
|
||
this.loading = false
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.portal-login {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(430px, 36vw);
|
||
min-height: 100vh;
|
||
background: linear-gradient(132deg, var(--portal-primary), var(--portal-accent));
|
||
}
|
||
|
||
.login-visual {
|
||
position: relative;
|
||
display: flex;
|
||
min-width: 0;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
padding: 72px clamp(48px, 8vw, 128px);
|
||
color: #ffffff;
|
||
}
|
||
|
||
.login-visual::before {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: block;
|
||
content: "";
|
||
opacity: 0.58;
|
||
background:
|
||
linear-gradient(42deg, transparent 0 18%, rgba(255, 255, 255, 0.18) 18% 27%, transparent 27% 100%),
|
||
linear-gradient(132deg, transparent 0 48%, rgba(246, 186, 51, 0.32) 48% 55%, transparent 55% 100%);
|
||
}
|
||
|
||
.login-brand,
|
||
.login-visual h1,
|
||
.login-visual p {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.login-brand {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 40px;
|
||
font-size: 22px;
|
||
}
|
||
|
||
.login-logo {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 9px 19px 9px 19px;
|
||
background: linear-gradient(135deg, #6de5e8 0 38%, #f6c85b 38% 66%, #ffffff 66%);
|
||
transform: rotate(45deg);
|
||
box-shadow: 0 8px 22px rgba(15, 23, 42, 0.18);
|
||
}
|
||
|
||
.login-visual h1,
|
||
.login-visual p {
|
||
margin: 0;
|
||
}
|
||
|
||
.login-visual h1 {
|
||
max-width: 680px;
|
||
font-size: clamp(42px, 5vw, 64px);
|
||
font-weight: 700;
|
||
letter-spacing: 0;
|
||
line-height: 1.18;
|
||
}
|
||
|
||
.login-visual p {
|
||
max-width: 520px;
|
||
margin-top: 20px;
|
||
color: rgba(255, 255, 255, 0.88);
|
||
font-size: 17px;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.login-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
padding: clamp(40px, 5vw, 64px);
|
||
background: #ffffff;
|
||
box-shadow: -18px 0 48px rgba(15, 23, 42, 0.08);
|
||
}
|
||
|
||
.login-heading span {
|
||
color: var(--portal-primary, #167d83);
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.login-heading h2 {
|
||
margin: 8px 0 28px;
|
||
color: #111827;
|
||
font-size: 30px;
|
||
font-weight: 700;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
.login-alert {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.login-form {
|
||
display: grid;
|
||
gap: 2px;
|
||
}
|
||
|
||
.role-select,
|
||
.login-button {
|
||
width: 100%;
|
||
}
|
||
|
||
.login-form >>> .el-input__inner,
|
||
.login-form >>> .el-select .el-input__inner {
|
||
height: 44px;
|
||
border-color: #dfe5ec;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.login-form >>> .el-input__inner:focus {
|
||
border-color: var(--portal-primary, #167d83);
|
||
box-shadow: 0 0 0 3px rgba(22, 125, 131, 0.12);
|
||
}
|
||
|
||
.login-button {
|
||
height: 44px;
|
||
margin-top: 10px;
|
||
border-color: var(--portal-primary, #167d83);
|
||
border-radius: 8px;
|
||
background: var(--portal-primary, #167d83);
|
||
font-weight: 600;
|
||
box-shadow: 0 10px 22px rgba(22, 125, 131, 0.18);
|
||
}
|
||
|
||
.login-button:hover,
|
||
.login-button:focus {
|
||
border-color: var(--portal-primary-strong, #11656a);
|
||
background: var(--portal-primary-strong, #11656a);
|
||
}
|
||
|
||
@media (max-width: 880px) {
|
||
.portal-login {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.login-visual {
|
||
min-height: 220px;
|
||
padding: 34px 26px;
|
||
}
|
||
|
||
.login-visual h1 {
|
||
font-size: 34px;
|
||
}
|
||
|
||
.login-brand {
|
||
margin-bottom: 28px;
|
||
}
|
||
|
||
.login-panel {
|
||
padding: 34px 24px 44px;
|
||
box-shadow: none;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 520px) {
|
||
.login-visual {
|
||
min-height: 184px;
|
||
padding: 26px 22px;
|
||
}
|
||
|
||
.login-brand {
|
||
margin-bottom: 20px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.login-visual h1 {
|
||
font-size: 30px;
|
||
}
|
||
|
||
.login-visual p {
|
||
margin-top: 10px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
</style>
|
||
', 'admin', sysdate()),
|
||
(920313, 9203, 'frontend-dict.js.vm', NULL, 'frontend-dict.js.vm', 'const dictData = {}
|
||
#foreach ($column in $columns)
|
||
#if($column.dictOptions && $column.dictOptions != "")
|
||
#set($dictKey = $column.dictType)
|
||
#if(!$dictKey || $dictKey == "")
|
||
#set($dictKey = $column.columnName)
|
||
#end
|
||
dictData["${dictKey}"] = ${column.dictOptions}
|
||
#end
|
||
#end
|
||
|
||
const emptyDict = []
|
||
|
||
function normalizeOptions(options) {
|
||
if (!Array.isArray(options)) {
|
||
return emptyDict
|
||
}
|
||
return options.map((option) => {
|
||
const label = option.label || option.name || option.value
|
||
const value = option.value || label
|
||
return {
|
||
...option,
|
||
label,
|
||
name: option.name || label,
|
||
value
|
||
}
|
||
})
|
||
}
|
||
|
||
export default {
|
||
getDictDataByType(type) {
|
||
return normalizeOptions(dictData[type])
|
||
},
|
||
getDictLabel(type, value) {
|
||
if (value === undefined || value === null || value === "") {
|
||
return "-"
|
||
}
|
||
const matched = normalizeOptions(dictData[type]).find((option) => String(option.value) === String(value))
|
||
return matched ? matched.label : value
|
||
}
|
||
}', 'admin', sysdate());
|
||
|
||
-- Backend project structure
|
||
INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES
|
||
(920100, 0, '{projectName}-backend', 'folder', NULL, 9201, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920101, 920100, 'pom.xml', 'file', NULL, 9201, -1, 'pom.xml.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920102, 920100, 'README.md', 'file', NULL, 9201, -1, 'README.md.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920103, 920100, 'sql', 'folder', NULL, 9201, NULL, NULL, 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920104, 920103, '{businessName}.sql', 'file', NULL, 9201, 0, 'sql.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920110, 920100, 'src', 'folder', NULL, 9201, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920111, 920110, 'main', 'folder', NULL, 9201, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920112, 920111, 'java', 'folder', NULL, 9201, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920113, 920111, 'resources', 'folder', NULL, 9201, NULL, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920114, 920112, '{packagePath}', 'folder', NULL, 9201, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920115, 920114, '{projectClassName}Application.java', 'file', NULL, 9201, -1, 'Application.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920116, 920114, 'common', 'folder', NULL, 9201, NULL, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920117, 920116, 'Result.java', 'file', NULL, 9201, -1, 'Result.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920118, 920114, 'config', 'folder', NULL, 9201, NULL, NULL, 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920119, 920118, 'MybatisPlusConfig.java', 'file', NULL, 9201, -1, 'MybatisPlusConfig.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920120, 920118, 'CorsConfig.java', 'file', NULL, 9201, -1, 'CorsConfig.java.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920121, 920114, 'controller', 'folder', NULL, 9201, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920122, 920121, 'FileController.java', 'file', NULL, 9201, -1, 'FileController.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920123, 920121, '{ClassName}Controller.java', 'file', NULL, 9201, 0, 'controller.java.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920124, 920114, 'entity', 'folder', NULL, 9201, NULL, NULL, 5, '0', 'admin', sysdate(), '', NULL),
|
||
(920125, 920124, '{ClassName}.java', 'file', NULL, 9201, 0, 'entity.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920126, 920114, 'mapper', 'folder', NULL, 9201, NULL, NULL, 6, '0', 'admin', sysdate(), '', NULL),
|
||
(920127, 920126, '{ClassName}Mapper.java', 'file', NULL, 9201, 0, 'mapper.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920128, 920114, 'service', 'folder', NULL, 9201, NULL, NULL, 7, '0', 'admin', sysdate(), '', NULL),
|
||
(920129, 920128, 'I{ClassName}Service.java', 'file', NULL, 9201, 0, 'service.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920130, 920128, 'impl', 'folder', NULL, 9201, NULL, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920131, 920130, '{ClassName}ServiceImpl.java', 'file', NULL, 9201, 0, 'serviceImpl.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920132, 920113, 'application.yml', 'file', NULL, 9201, -1, 'application.yml.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920133, 920113, 'mapper', 'folder', NULL, 9201, NULL, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920134, 920133, '{moduleName}', 'folder', NULL, 9201, 0, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920135, 920134, '{ClassName}Mapper.xml', 'file', NULL, 9201, 0, 'mapper.xml.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920136, 920138, 'AuthPrincipal.java', 'file', NULL, 9201, -1, 'AuthPrincipal.java.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920138, 920114, 'security', 'folder', NULL, 9201, NULL, NULL, 8, '0', 'admin', sysdate(), '', NULL),
|
||
(920139, 920138, 'PortalAuthTokenStore.java', 'file', NULL, 9201, -1, 'PortalAuthTokenStore.java.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920140, 920138, 'PortalAuthInterceptor.java', 'file', NULL, 9201, -1, 'PortalAuthInterceptor.java.vm', 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920141, 920121, 'PortalAuthController.java', 'file', NULL, 9201, -1, 'PortalAuthController.java.vm', 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920144, 920121, 'AdminAuthController.java', 'file', NULL, 9201, -1, 'AdminAuthController.java.vm', 4, '0', 'admin', sysdate(), '', NULL);
|
||
|
||
-- Admin frontend project structure
|
||
INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES
|
||
(920200, 0, '{projectName}-admin', 'folder', NULL, 9202, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920201, 920200, 'package.json', 'file', NULL, 9202, -1, 'package.json.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920202, 920200, 'babel.config.js', 'file', NULL, 9202, -1, 'babel.config.js.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920203, 920200, 'vue.config.js', 'file', NULL, 9202, -1, 'vue.config.js.vm', 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920204, 920200, 'public', 'folder', NULL, 9202, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920205, 920204, 'index.html', 'file', NULL, 9202, -1, 'index.html.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920206, 920200, 'src', 'folder', NULL, 9202, NULL, NULL, 5, '0', 'admin', sysdate(), '', NULL),
|
||
(920207, 920206, 'main.js', 'file', NULL, 9202, -1, 'admin-main.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920208, 920206, 'App.vue', 'file', NULL, 9202, -1, 'admin-App.vue.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920209, 920206, 'router', 'folder', NULL, 9202, NULL, NULL, 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920210, 920209, 'index.js', 'file', NULL, 9202, -1, 'admin-router.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920211, 920206, 'utils', 'folder', NULL, 9202, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920212, 920211, 'request.js', 'file', NULL, 9202, -1, 'request.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920213, 920211, 'dict.js', 'file', NULL, 9202, -1, 'dict.js.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920214, 920206, 'views', 'folder', NULL, 9202, NULL, NULL, 5, '0', 'admin', sysdate(), '', NULL),
|
||
(920218, 920214, 'login', 'folder', NULL, 9202, -1, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920219, 920218, 'index.vue', 'file', NULL, 9202, -1, 'admin-login.vue.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920215, 920214, '{moduleName}', 'folder', NULL, 9202, 0, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920216, 920215, '{businessName}', 'folder', NULL, 9202, 0, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920217, 920216, 'index.vue', 'file', NULL, 9202, 0, 'admin-index.vue.vm', 1, '0', 'admin', sysdate(), '', NULL);
|
||
|
||
-- Portal frontend project structure
|
||
INSERT INTO sys_project_structure (node_id, parent_id, node_name, node_type, module, template_id, table_id, category, sort_order, status, create_by, create_time, update_by, update_time) VALUES
|
||
(920300, 0, '{projectName}-web', 'folder', NULL, 9203, NULL, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920301, 920300, 'package.json', 'file', NULL, 9203, -1, 'package.json.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920302, 920300, 'babel.config.js', 'file', NULL, 9203, -1, 'babel.config.js.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920303, 920300, 'vue.config.js', 'file', NULL, 9203, -1, 'vue.config.js.vm', 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920304, 920300, 'public', 'folder', NULL, 9203, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920305, 920304, 'index.html', 'file', NULL, 9203, -1, 'index.html.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920306, 920300, 'src', 'folder', NULL, 9203, NULL, NULL, 5, '0', 'admin', sysdate(), '', NULL),
|
||
(920307, 920306, 'main.js', 'file', NULL, 9203, -1, 'frontend-main.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920308, 920306, 'App.vue', 'file', NULL, 9203, -1, 'frontend-App.vue.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920309, 920306, 'style.css', 'file', NULL, 9203, -1, 'style.css.vm', 3, '0', 'admin', sysdate(), '', NULL),
|
||
(920310, 920306, 'router', 'folder', NULL, 9203, NULL, NULL, 4, '0', 'admin', sysdate(), '', NULL),
|
||
(920311, 920310, 'index.js', 'file', NULL, 9203, -1, 'frontend-router.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920312, 920306, 'api', 'folder', NULL, 9203, NULL, NULL, 5, '0', 'admin', sysdate(), '', NULL),
|
||
(920313, 920312, 'request.js', 'file', NULL, 9203, -1, 'frontend-request.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920314, 920312, '{businessName}.js', 'file', NULL, 9203, 0, 'frontend-api.js.vm', 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920321, 920306, 'utils', 'folder', NULL, 9203, NULL, NULL, 6, '0', 'admin', sysdate(), '', NULL),
|
||
(920322, 920321, 'dict.js', 'file', NULL, 9203, -1, 'frontend-dict.js.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920315, 920306, 'views', 'folder', NULL, 9203, NULL, NULL, 7, '0', 'admin', sysdate(), '', NULL),
|
||
(920316, 920315, '{moduleName}', 'folder', NULL, 9203, 0, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920317, 920316, '{businessName}', 'folder', NULL, 9203, 0, NULL, 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920318, 920317, 'index.vue', 'file', NULL, 9203, 0, 'frontend-index.vue.vm', 1, '0', 'admin', sysdate(), '', NULL),
|
||
(920319, 920315, 'login', 'folder', NULL, 9203, NULL, NULL, 2, '0', 'admin', sysdate(), '', NULL),
|
||
(920320, 920319, 'index.vue', 'file', NULL, 9203, -1, 'frontend-login.vue.vm', 1, '0', 'admin', sysdate(), '', NULL);
|
||
SET FOREIGN_KEY_CHECKS = 1;
|