jeecgboot-vue 1.0.0 版本发布

pull/22/head
zhangdaiscott 2022-03-10 09:47:29 +08:00
parent 8fc58eee4c
commit a2d39b4363
634 changed files with 55040 additions and 9659 deletions

22
.env
View File

@ -1,8 +1,22 @@
# port
VITE_PORT = 3100
# spa-title
VITE_GLOB_APP_TITLE = Jeecg Boot
# 网站标题
VITE_GLOB_APP_TITLE = JeecgBoot 企业级低代码平台
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin
# 单点登录服务端地址
VITE_GLOBE_APP_CAS_BASE_URL=http://cas.test.com:8443/cas
# 是否开启单点登录
VITE_GLOB_APP_OPEN_SSO = false
# 开启微前端模式
VITE_GLOB_APP_OPEN_QIANKUN=true
# 文件预览地址
VITE_GLOB_ONLINE_VIEW_URL=http://fileview.jeecg.com/onlinePreview
# spa shortname
VITE_GLOB_APP_SHORT_NAME = Jeecg-Boot-Admin

View File

@ -1,21 +1,23 @@
# 是否打开mock
VITE_USE_MOCK = false
VITE_USE_MOCK = true
# 公共路径
# 发布路径
VITE_PUBLIC_PATH = /
# 跨域代理,您可以配置多个 ,请注意,没有换行符
VITE_PROXY = [["/jeecg-boot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
# VITE_PROXY=[["/api","https://vvbin.cn/test"]]
VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
# 控制台不输出
VITE_DROP_CONSOLE = false
# 接口父路径
VITE_GLOB_API_URL= /jeecg-boot
#后台接口父地址(必填)
VITE_GLOB_API_URL=/jeecgboot
# 文件上次地址(可选)
VITE_GLOB_UPLOAD_URL=/upload
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot
# 接口前缀
VITE_GLOB_API_URL_PREFIX=
#微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
VITE_APP_SUB_jeecg-app-1 = '//localhost:8092'

View File

@ -1,7 +1,7 @@
# 是否启用mock
VITE_USE_MOCK = true
# 公共路径
# 发布路径
VITE_PUBLIC_PATH = /
# 控制台不输出
@ -10,19 +10,18 @@ VITE_DROP_CONSOLE = true
# 是否启用gzip或brotli压缩
# 选项值: gzip | brotli | none
# 如果需要多个可以使用“,”分隔
VITE_BUILD_COMPRESS = 'none'
VITE_BUILD_COMPRESS = 'gzip'
# 使用压缩时是否删除原始文件默认为false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# 接口父路径
VITE_GLOB_API_URL=/basic-api
#后台接口父地址(必填)
VITE_GLOB_API_URL=/jeecgboot
# 文件上次地址(可选)
# 它可以由nginx转发也可以直接写入实际地址
VITE_GLOB_UPLOAD_URL=/upload
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://api3.boot.jeecg.com
# 接口父路径
# 接口父路径前缀
VITE_GLOB_API_URL_PREFIX=
# 是否启用图像压缩

View File

@ -1,36 +1,31 @@
NODE_ENV=production
# Whether to open mock
# 是否启用mock
VITE_USE_MOCK = true
# public path
# 发布路径
VITE_PUBLIC_PATH = /
# Delete console
# 控制台不输出
VITE_DROP_CONSOLE = true
# Whether to enable gzip or brotli compression
# Optional: gzip | brotli | none
# If you need multiple forms, you can use `,` to separate
VITE_BUILD_COMPRESS = 'none'
# 是否启用gzip或brotli压缩
# 选项值: gzip | brotli | none
# 如果需要多个可以使用“,”分隔
VITE_BUILD_COMPRESS = 'gzip'
# Whether to delete origin files when using compress, default false
# 使用压缩时是否删除原始文件,默认为false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# Basic interface address SPA
VITE_GLOB_API_URL=/basic-api
#后台接口地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot
# File upload address optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=/upload
# Interface prefix
# 接口父路径前缀
VITE_GLOB_API_URL_PREFIX=
# Whether to enable image compression
# 是否启用图像压缩
VITE_USE_IMAGEMIN= true
# use pwa
# 使用pwa
VITE_USE_PWA = false
# Is it compatible with older browsers
# 是否兼容旧浏览器
VITE_LEGACY = false

View File

@ -5,7 +5,7 @@
JEECG BOOT 低代码平台Vue3前端版本
===============
当前最新版本: 1.0.0-beta发布日期:未正式发布
当前最新版本: 1.0.0-beta预计发布日期 20220321
## 简介

View File

@ -1,6 +1,6 @@
import { generate } from '@ant-design/colors';
export const primaryColor = '#0960bd';
export const primaryColor = '#1890FF';
export const darkMode = 'light';

View File

@ -5,18 +5,19 @@ import { GLOB_CONFIG_FILE_NAME, OUTPUT_DIR } from '../constant';
import fs, { writeFileSync } from 'fs-extra';
import chalk from 'chalk';
import { getRootPath, getEnvConfig } from '../utils';
import { getEnvConfig, getRootPath } from '../utils';
import { getConfigFileName } from '../getConfigFileName';
import pkg from '../../package.json';
function createConfig(
{
configName,
config,
configFileName = GLOB_CONFIG_FILE_NAME,
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} }
) {
interface CreateConfigParams {
configName: string;
config: any;
configFileName?: string;
}
function createConfig(params: CreateConfigParams) {
const { configName, config, configFileName } = params;
try {
const windowConf = `window.${configName}`;
// Ensure that the variable will not be modified
@ -40,5 +41,5 @@ function createConfig(
export function runBuildConfig() {
const config = getEnvConfig();
const configFileName = getConfigFileName(config);
createConfig({ config, configName: configFileName });
createConfig({ config, configName: configFileName, configFileName: GLOB_CONFIG_FILE_NAME });
}

View File

@ -28,12 +28,12 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
if (envName === 'VITE_PORT') {
realName = Number(realName);
}
if (envName === 'VITE_PROXY') {
try {
realName = JSON.parse(realName);
} catch (error) {
realName = '';
}
if (envName === 'VITE_PROXY' && realName) {
try {
realName = JSON.parse(realName.replace(/'/g, '"'));
} catch (error) {
realName = '';
}
}
ret[envName] = realName;
if (typeof realName === 'string') {
@ -50,7 +50,7 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
*/
function getConfFiles() {
const script = process.env.npm_lifecycle_script;
const reg = new RegExp('--mode ([a-z]+)');
const reg = new RegExp('--mode ([a-z_\\d]+)');
const result = reg.exec(script as string) as any;
if (result) {
const mode = result[1] as string;

View File

@ -4,6 +4,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
import purgeIcons from 'vite-plugin-purge-icons';
import windiCSS from 'vite-plugin-windicss';
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
import { configHtmlPlugin } from './html';
import { configPwaConfig } from './pwa';
import { configMockPlugin } from './mock';
@ -29,7 +30,10 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vue(),
// have to
vueJsx(),
// support name
vueSetupExtend(),
];
// vite-plugin-windicss
vitePlugins.push(windiCSS());
@ -67,7 +71,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// rollup-plugin-gzip
vitePlugins.push(
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE)
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
);
// vite-plugin-pwa

View File

@ -14,7 +14,52 @@ export function configStyleImportPlugin(isBuild: boolean) {
libraryName: 'ant-design-vue',
esModule: true,
resolveStyle: (name) => {
return `ant-design-vue/es/${name}/style/index`;
// 这里是“子组件”列表,无需额外引入样式文件
const ignoreList = [
'typography-text',
'typography-title',
'typography-paragraph',
'typography-link',
'anchor-link',
'sub-menu',
'menu-item',
'menu-item-group',
'dropdown-button',
'breadcrumb-item',
'breadcrumb-separator',
'input-password',
'input-search',
'input-group',
'form-item',
'radio-group',
'checkbox-group',
'layout-sider',
'layout-content',
'layout-footer',
'layout-header',
'step',
'select-option',
'select-opt-group',
'card-grid',
'card-meta',
'collapse-panel',
'descriptions-item',
'list-item',
'list-item-meta',
'table-column',
'table-column-group',
'tab-pane',
'tab-content',
'timeline-item',
'tree-node',
'skeleton-input',
'skeleton-avatar',
'skeleton-title',
'skeleton-paragraph',
'skeleton-image',
'skeleton-button',
];
return ignoreList.includes(name) ? '' : `ant-design-vue/es/${name}/style/index`;
},
},
],

View File

@ -66,7 +66,7 @@ export function configThemePlugin(isBuild: boolean): Plugin[] {
'border-color-base': '#303030',
// 'border-color-split': '#30363d',
'item-active-bg': '#111b26',
'app-content-background': 'rgb(255 255 255 / 4%)',
'app-content-background': '#1e1e1e',
'tree-node-selected-bg': '#11263c',
'alert-success-border-color': '#274916',

View File

@ -7,7 +7,7 @@ type ProxyItem = [string, string];
type ProxyList = ProxyItem[];
type ProxyTargetList = Record<string, ProxyOptions & { rewrite: (path: string) => string }>;
type ProxyTargetList = Record<string, ProxyOptions>;
const httpsRE = /^https:\/\//;

View File

@ -1,137 +0,0 @@
## ✨ 功能优化---zhangyafei---2021-07-19
- **添加增删改查demo**
- src/views/demo/system/test/TestDrawer.vue
- src/views/demo/system/test/test.data.ts
- src/api/demo/model/systemModel.ts
- src/api/demo/system.ts
- mock/demo/system.ts
- src/views/demo/system/test/index.vue
- **添加代码高亮编辑器**
- src/views/demo/codemirror/index.vue
- **添加日历组件**
- src/views/demo/fullcalendar/event-utils.ts
- src/views/demo/fullcalendar/index.vue
- **添加vexTable示例**
- src/views/demo/vextable/index.vue
- **添加JAreaLinkage示例**
- src/components/Form/src/componentMap.ts
- src/components/Form/src/types/index.ts
- src/components/Form/index.ts
- src/views/demo/form/index.vue
- src/assets/less/JAreaLinkage.less
- src/components/Form/src/components/JAreaLinkage.vue
- **修改示例路由配置**
- src/router/routes/modules/demo/feat.ts
- src/router/routes/modules/demo/comp.ts
- **修改路由国际化**
- src/locales/lang/zh_CN/routes/demo.ts
- **全局组件注册**
- src/main.ts
- **package添加组件依赖**
- package.json
- **路由跳转暂时屏蔽动画效果有bug冲突**
- src/layouts/page/index.vue
## ✨ 功能优化---zhangyafei---2021-07-29
- **添加一对多,一对一示例**
- src/views/demo/vextable/VexTableModal.vue
- src/views/demo/vextable/OneToOneModal.vue
- src/views/demo/vextable/modal.vue
- src/views/demo/vextable/index2.vue
- src/views/demo/vextable/index.vue
- src/views/demo/vextable/drawer.vue
- **添加嵌套子表格示例**
- src/views/demo/table/NestedTable.vue
- **常用antd 组件全局注入**
- src/components/registerGlobComp.ts
- **添加权限,指令用法示例代码**
- src/views/demo/permission/front/Btn.vue
- **添加三方组件注册文件**
- src/settings/registerThirdComp.ts
- **main.ts注释汉化**
- src/main.ts
## ✨ 功能优化---liusq---2021-08-19
- **增加接口token**
- src/enums/httpEnum.ts
- src/utils/http/axios/index.ts
- **新增用户管理、角色管理**
- src/views/demo/system/roles/*
- src/views/demo/system/user/*
- **登录验证码功能**
- src/api/demo/model/systemModel.ts
- src/api/demo/system.ts
- src/api/model/baseModel.ts
- src/api/sys/model/userModel.ts
- src/api/sys/user.ts
- src/locales/lang/zh_CN/routes/demo.ts
- src/locales/lang/zh_CN/sys.ts
- src/router/routes/modules/demo/system.ts
- src/store/modules/user.ts
- **接口和moke路径修改**
- src/mock/demo/account.ts
- src/mock/demo/select-demo.ts
- src/mock/demo/system.ts
- src/mock/demo/table-demo.ts
- src/mock/demo/tree-demo.ts
- src/mock/sys/menu.ts
- src/mock/sys/user.ts
- src/mock/_util.ts
- src/api/sys/menu.ts
- src/api/sys/user.ts
- **table配置项修改**
- src/settings/componentSetting.ts
- **上传返回值修改**
- src/components/Upload/src/UploadModal.vue
## ✨ 功能完善---zhangyafei---2021-08-27
- **添加租户功能**
-src/views/system/tenant/**
- **修改antd注册方式,改为全局注册**
-src/main.ts
-src/settings/registerThirdComp.ts
- **网络请求类翻译,添加全局操作成功顶部消息提示**
-src/utils/http/axios/Axios.ts
-src/utils/http/axios/index.ts
-src/-types/axios.d.ts
- **表格选择工具类样式修改**
-src/components/Table/src/BasicTable.vue
- **底层代码优化**
- src/api/demo/system.ts
- src/api/sys/user.ts
- src/router/guard/permissionGuard.ts
- src/store/modules/user.ts
- src/settings/projectSetting.ts
- src/main.ts
- mock/sys/user.ts
- package.json
## ✨ 功能完善---liusq---2021-08-27
- **完善用户管理、角色管理功能**
- system/user/UserRecycleBinModal.vue
- system/user/UserDrawer.vue
- system/user/user.data.ts
- system/user/user.api.ts
- system/user/index.vue
- system/role/UserRoleDrawer.vue
- system/role/RoleDrawer.vue
- system/role/role.data.ts
- system/role/role.api.ts
- system/role/index.vue
- /locales/lang/zh-CN/routes/demo.ts
- /locales/lang/zh-CN/sys.ts
- /api/demo/system.ts
- **完善登录注册功能**
- src/api/sys/user.ts
- src/store/modules/user.ts
- src/views/sys/forget-password/step1.vue
- src/views/sys/forget-password/step2.vue
- src/views/sys/forget-password/step3.vue
- src/views/sys/login/ForgetPasswordForm.vue
- src/views/sys/login/MobileForm.vue
- src/views/sys/login/RegisterForm.vue
- src/views/sys/login/useLogin.ts
- src/assets/images/checkcode.png
## ✨ 还原路由走本地---scott---2021-08-31
- src\settings\projectSetting.ts
## ✨ 功能完善---zyf---2021-08-31
测试

View File

@ -1,5 +0,0 @@
###---zhangyafei---2021-08-31 租户、用户、角色
update sys_permission set url='/system/tenant' ,component='/system/tenant/index' where id='1280350452934307841';
update sys_permission set url='/system/user' ,component='/system/user/index' where id='3f915b2769fc80648e92d04e84ca059d';
update sys_permission set url='/system/role' ,component='/system/role/index' where id='190c2b43bec6a5f7a4194a85db67d96a';
###---zhangyafei---2021-08-31

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" id="htmlRoot">
<html lang="zh_CN" id="htmlRoot">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
@ -10,7 +10,11 @@
/>
<title><%= title %></title>
<link rel="icon" href="/favicon.ico" />
<link rel="icon" href="/logo.png" />
<!-- 全局配置 -->
<script>
window._CONFIG = {};
</script>
</head>
<body>
<script>

View File

@ -58,3 +58,6 @@ export interface requestParams {
export function getRequestToken({ headers }: requestParams): string | undefined {
return headers?.authorization;
}
//TODO 接口父路径(写死不够灵活)
export const baseUrl = '/jeecgboot/mock';

View File

@ -1,6 +1,6 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess, resultError } from '../_util';
import { resultSuccess, resultError, baseUrl } from '../_util';
import { ResultEnum } from '../../src/enums/httpEnum';
const userInfo = {
name: 'Jeecg',
userid: '00000001',
@ -44,7 +44,7 @@ const userInfo = {
export default [
{
url: '/jeecg-boot/account/getAccountInfo',
url: `${baseUrl}/account/getAccountInfo`,
timeout: 1000,
method: 'get',
response: () => {
@ -52,11 +52,19 @@ export default [
},
},
{
url: '/jeecg-boot/user/sessionTimeout',
url: `${baseUrl}/user/sessionTimeout`,
method: 'post',
statusCode: 401,
response: () => {
return resultError();
},
},
{
url: '/basic-api/user/tokenExpired',
method: 'post',
statusCode: 200,
response: () => {
return resultError('Token Expired!', { code: ResultEnum.TIMEOUT as number });
},
},
] as MockMethod[];

View File

@ -1,11 +1,11 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess } from '../_util';
import { resultSuccess, baseUrl } from '../_util';
const demoList = (keyword) => {
const demoList = (keyword, count = 20) => {
const result = {
list: [] as any[],
};
for (let index = 0; index < 20; index++) {
for (let index = 0; index < count; index++) {
result.list.push({
name: `${keyword ?? ''}选项${index}`,
id: `${index}`,
@ -16,13 +16,13 @@ const demoList = (keyword) => {
export default [
{
url: '/jeecg-boot/select/getDemoOptions',
url: `${baseUrl}/select/getDemoOptions`,
timeout: 1000,
method: 'get',
response: ({ query }) => {
const { keyword } = query;
const { keyword,count} = query;
console.log(keyword);
return resultSuccess(demoList(keyword));
return resultSuccess(demoList(keyword,count));
},
},
] as MockMethod[];

View File

@ -1,5 +1,5 @@
import {MockMethod} from 'vite-plugin-mock';
import {resultError, resultPageSuccess, resultSuccess} from '../_util';
import { MockMethod } from 'vite-plugin-mock';
import { resultError, resultPageSuccess, resultSuccess, baseUrl } from '../_util';
const accountList = (() => {
const result: any[] = [];
@ -150,7 +150,7 @@ const menuList = (() => {
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index],
component: [
'/dashboard/welcome/index',
'/dashboard/analysis/index',
'/dashboard/Analysis/index',
'/dashboard/workbench/index',
'/dashboard/test/index',
][j],
@ -172,7 +172,7 @@ const menuList = (() => {
(k + 1),
component: [
'/dashboard/welcome/index',
'/dashboard/analysis/index',
'/dashboard/Analysis/index',
'/dashboard/workbench/index',
'/dashboard/test/index',
][j],
@ -195,104 +195,104 @@ const menuList = (() => {
})();
export default [
{
url: '/jeecg-boot/system/getAccountList',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, accountList);
},
{
url: `${baseUrl}/system/getAccountList`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, accountList);
},
{
url: '/jeecg-boot/sys/user/list',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, userList);
},
},
{
url: `${baseUrl}/sys/user/list`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, userList);
},
{
url: '/jeecg-boot/system/getRoleListByPage',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, roleList);
},
},
{
url: `${baseUrl}/system/getRoleListByPage`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, roleList);
},
{
url: '/jeecg-boot/sys/role/list',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, newRoleList);
},
},
{
url: `${baseUrl}/sys/role/list`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, newRoleList);
},
{
url: '/jeecg-boot/system/getTestListByPage',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, testList);
},
},
{
url: `${baseUrl}/system/getTestListByPage`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, testList);
},
{
url: '/jeecg-boot/system/getDemoTableListByPage',
timeout: 100,
method: 'get',
response: ({query}) => {
const {page = 1, pageSize = 20} = query;
return resultPageSuccess(page, pageSize, tableDemoList);
},
},
{
url: `${baseUrl}/system/getDemoTableListByPage`,
timeout: 100,
method: 'get',
response: ({ query }) => {
const { page = 1, pageSize = 20 } = query;
return resultPageSuccess(page, pageSize, tableDemoList);
},
{
url: '/jeecg-boot/system/setRoleStatus',
timeout: 500,
method: 'post',
response: ({query}) => {
const {id, status} = query;
return resultSuccess({id, status});
},
},
{
url: `${baseUrl}/system/setRoleStatus`,
timeout: 500,
method: 'post',
response: ({ query }) => {
const { id, status } = query;
return resultSuccess({ id, status });
},
{
url: '/jeecg-boot/system/getAllRoleList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(roleList);
},
},
{
url: `${baseUrl}/system/getAllRoleList`,
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(roleList);
},
{
url: '/jeecg-boot/system/getDeptList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(deptList);
},
},
{
url: `${baseUrl}/system/getDeptList`,
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(deptList);
},
{
url: '/jeecg-boot/system/getMenuList',
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(menuList);
},
},
{
url: `${baseUrl}/system/getMenuList`,
timeout: 100,
method: 'get',
response: () => {
return resultSuccess(menuList);
},
{
url: '/jeecg-boot/system/accountExist',
timeout: 500,
method: 'post',
response: ({body}) => {
const {account} = body || {};
if (account && account.indexOf('admin') !== -1) {
return resultError('该字段不能包含admin');
} else {
return resultSuccess(`${account} can use`);
}
},
},
{
url: `${baseUrl}/system/accountExist`,
timeout: 500,
method: 'post',
response: ({ body }) => {
const { account } = body || {};
if (account && account.indexOf('admin') !== -1) {
return resultError('该字段不能包含admin');
} else {
return resultSuccess(`${account} can use`);
}
},
},
] as MockMethod[];

View File

@ -1,6 +1,6 @@
import { MockMethod } from 'vite-plugin-mock';
import { Random } from 'mockjs';
import { resultPageSuccess } from '../_util';
import { resultPageSuccess, baseUrl } from '../_util';
function getRandomPics(count = 10): string[] {
const arr: string[] = [];
@ -12,7 +12,7 @@ function getRandomPics(count = 10): string[] {
const demoList = (() => {
const result: any[] = [];
for (let index = 0; index < 60; index++) {
for (let index = 0; index < 200; index++) {
result.push({
id: `${index}`,
beginTime: '@datetime',
@ -41,7 +41,7 @@ const demoList = (() => {
export default [
{
url: '/jeecg-boot/table/getDemoList',
url: `${baseUrl}/table/getDemoList`,
timeout: 100,
method: 'get',
response: ({ query }) => {

View File

@ -1,5 +1,5 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess } from '../_util';
import { resultSuccess, baseUrl } from '../_util';
const demoTreeList = (keyword) => {
const result = {
@ -26,7 +26,7 @@ const demoTreeList = (keyword) => {
export default [
{
url: '/jeecg-boot/tree/getDemoOptions',
url: `${baseUrl}/tree/getDemoOptions`,
timeout: 1000,
method: 'get',
response: ({ query }) => {

View File

@ -1,4 +1,4 @@
import { resultSuccess, resultError, getRequestToken, requestParams } from '../_util';
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util';
import { MockMethod } from 'vite-plugin-mock';
import { createFakeUserList } from './user';
@ -17,7 +17,7 @@ const dashboardRoute = {
{
path: 'analysis',
name: 'Analysis',
component: '/dashboard/analysis/index',
component: '/dashboard/Analysis/index',
meta: {
hideMenu: true,
hideBreadcrumb: true,
@ -237,7 +237,7 @@ const linkRoute = {
export default [
{
url: '/jeecg-boot/sys/permission/getUserPermissionByToken',
url: `${baseUrl}/sys/permission/getUserPermissionByToken`,
timeout: 1000,
method: 'get',
response: (request: requestParams) => {

View File

@ -1,11 +1,10 @@
import { MockMethod } from 'vite-plugin-mock';
import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util';
import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util';
export function createFakeUserList() {
return [
{
userId: '1',
username: 'jeecg',
username: 'admin',
realname: '管理员',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640',
desc: 'manager',
@ -21,7 +20,7 @@ export function createFakeUserList() {
},
{
userId: '2',
username: 'test',
username: 'jeecg',
password: '123456',
realname: '测试用户',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
@ -47,7 +46,7 @@ const fakeCodeList: any = {
export default [
// mock user login
{
url: '/jeecg-boot/sys/login',
url: `${baseUrl}/sys/login`,
timeout: 200,
method: 'post',
response: ({ body }) => {
@ -58,19 +57,19 @@ export default [
if (!checkUser) {
return resultError('Incorrect account or password');
}
const { userId, username: _username, token, realName, desc, roles } = checkUser;
const { userId, username: _username, token, realname, desc, roles } = checkUser;
return resultSuccess({
roles,
userId,
username: _username,
token,
realName,
realname,
desc,
});
},
},
{
url: '/jeecg-boot/sys/user/getUserInfo',
url: `${baseUrl}/sys/user/getUserInfo`,
method: 'get',
response: (request: requestParams) => {
const token = getRequestToken(request);
@ -83,7 +82,7 @@ export default [
},
},
{
url: '/jeecg-boot/sys/permission/getPermCode',
url: `${baseUrl}/sys/permission/getPermCode`,
timeout: 200,
method: 'get',
response: (request: requestParams) => {
@ -99,7 +98,7 @@ export default [
},
},
{
url: '/jeecg-boot/sys/logout',
url: `${baseUrl}/sys/logout`,
timeout: 200,
method: 'get',
response: (request: requestParams) => {
@ -113,11 +112,12 @@ export default [
},
},
{
url: `/jeecg-boot/sys/randomImage/1629428467008`,
url: `${baseUrl}/sys/randomImage/1629428467008`,
timeout: 200,
method: 'get',
response: (request: requestParams) => {
var result = "data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAjAGkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3h/ME5lErCKNSHi8rO44yCp65/P060gmdbbIaKecxl0VDsEmOmMk8cgZ96dcypFGpkEm0uOUzxznJI6DjnPH54ryTWNW1+P436T4ftNev4LTU7Brhw9tbCSHiZxGrNCcKCijkMeuSSOAD1KJ7hrTZNK0d1Iz7egGVPRSV6HGRkE4z1xV5SWQEqVJGSpxke3FeYL4n1PSfi5pXhK7vxrFlf27XVveyQRrcQHa4KFo1CMhMLdFUjfy2F59NjZm3Bl2kMRxnGO3JA7Y/HI7UAVrjfbWt3NJLNKmCwVAoaNcc4PHTk8+n5rKs1tDGtsdw5X94GkOT90ls5xnr14PYDNeUfDzxvq3xCuNZvG8SNp1zBKHtdFgtYpFjhAADuWXfKpJwwRkIwcFd6geg+Dm12Tw9bN4hkX+0Y5bmKcLGVV9s7KjLkA7dijBPLAgnJ5oWgGrb36zBtqyPh9oKwuvG4DncByCeeexPsLHm7jH5amSNxnzFI2gY479/bNVrxYZpRD57Q3JRkikRFLxlgfmUspGQEbrkccg8V5l8PfEOt6h4p8YW+r+JJf7M8OXZhjWWC2jjMQaZSZWWNSMLGDkFQD1BHFAHq7usMcksjnYoLHI+6AOen0pqllZfNkUMWZVUdG5yOvOcD+dcclt4j1/XlvtM8T3dn4cIc7kgt2a4PGwwBoTiLqfMZm34+VQpVz0Ou2t/eWfk2GrXGmTNxHcW9ukxV8EAOrqwKZIJ+6fl+8M0AXjHcb5GWdcN9xWjyF6ehGe/5j05jmdri3cxPJGI3YOAOXABGARnGTjkcjpwenmvwt8Y61czeIdM8b6g0esaW3mTR3SwQJFAB99dijcOpZySoBjI+8TXR+EtK16SNdR1rWL64WUNPaWtxbxQGBXbKCVY0VjKq/f525dgBxuKA6i4ZfsSEyq0R275Wm8v5f7wZe/TjgHNWqiiSWNEV5vNwp3MygFj68cAdeMen4y0wKk6Mtysp3yQsvktEoyPmI+YgnGB9O57dPIfGML3H7SnhaGO+msXfS2C3EIjLqcXPTzFZeenIPXjnFeyiIJIzx4XzH3SZBO75ccc8dF/L3zXHah4D0K58US+ILuLUPtcMeI5l1G5WT5i+VjYSDYCW2hVIHLDaMg0AX9K8FaVZ+IJPEVxPc6rrTAxLf3rqzRJgKURUVUToeQoPzNk8mt0qRJF5uTMVdBNGuAucHoScdByeOPcAxRw3MdzOpuC3nZkQiEBY8EcMf4sggfRT0qYQSJBJGJWlGwKodirZxjlxzzxzjIOfYAA8Tn+HehfErRoPGvhDUP7J1uQCaWK3YmJLpQWZT0aN95X5xxgBgp3ZPb/AAi8U6r4q8BRajriv9qW5khFy6hBcrkEOoCqAAW2cZ5Q85yBdtPAfhSTSv7Og0mWxiWH7PcQ288lq86Y2/vjEy+cCM8sW6t6mukt9PttNsobLTbC0gtY34gjURIgzuJVVGM55xxz3oAnZf8ASI38vcQrLu3fdBwenccfy96+abbwjqHiu8+K1lpt/NFJBqYlW1MwSO5KzzECRmBJwA2ASBuKljxkfSF9ai7jeESzRtJGy5R3UAdCcoVIOGOCCD36qMc9oHgHw/oGrSalpMd1a3DuWnRb6Z1lYr/y2VnYOw3sQT03Z96AMn4W+PP+Et0xrLVZmi8TaerRX9pJH5Rba2BIE9egbGMMSCACtdxOHuYmXy3CCVRjIHmLkbs5HTrx3A9DXJN8LvCraj/adpa3SajtZBqC6rdGaMhdgw3mZOB8uMjgY9q39X0Sx1myuLLUknWwbLSLDdyQrKGUhgxRlOPvZUnac5OT0AseQfEHT7u71CP4keHrbTZJtFSGWQ/Zmk+3gMytMByDGm0BXwrbVdwwVYmPqXhvxDZeKdEj1bRL6AWM42NvT9/DLtVQkmWOXBx16jbjIINGl+GdPs9I/seG6nSAfIY7e/n3qqEBVSQuZI1A25RWABOOhO7P8NeA/DejRveaBpb2IuW2k/bJmDxjIDlJNyk4LYyOjHBGaAOwjeQogYxtIuBNtbhTjPH6cHsalqlbWMFrcSNuVnkkeZAwG5c/eI79wOO2O+SbtABSMiuMMoYZBwRnkHIP50UUALRRRQAUUUUAFFFFACBVUsVUAscsQOpxjn8AKWiigBFVUQIihVUYAAwAKY8EUkqSOgZ0BCk9uQf5qD+FFFAElFFFAH//2Q==";
const result =
'data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAjAGkDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3h/ME5lErCKNSHi8rO44yCp65/P060gmdbbIaKecxl0VDsEmOmMk8cgZ96dcypFGpkEm0uOUzxznJI6DjnPH54ryTWNW1+P436T4ftNev4LTU7Brhw9tbCSHiZxGrNCcKCijkMeuSSOAD1KJ7hrTZNK0d1Iz7egGVPRSV6HGRkE4z1xV5SWQEqVJGSpxke3FeYL4n1PSfi5pXhK7vxrFlf27XVveyQRrcQHa4KFo1CMhMLdFUjfy2F59NjZm3Bl2kMRxnGO3JA7Y/HI7UAVrjfbWt3NJLNKmCwVAoaNcc4PHTk8+n5rKs1tDGtsdw5X94GkOT90ls5xnr14PYDNeUfDzxvq3xCuNZvG8SNp1zBKHtdFgtYpFjhAADuWXfKpJwwRkIwcFd6geg+Dm12Tw9bN4hkX+0Y5bmKcLGVV9s7KjLkA7dijBPLAgnJ5oWgGrb36zBtqyPh9oKwuvG4DncByCeeexPsLHm7jH5amSNxnzFI2gY479/bNVrxYZpRD57Q3JRkikRFLxlgfmUspGQEbrkccg8V5l8PfEOt6h4p8YW+r+JJf7M8OXZhjWWC2jjMQaZSZWWNSMLGDkFQD1BHFAHq7usMcksjnYoLHI+6AOen0pqllZfNkUMWZVUdG5yOvOcD+dcclt4j1/XlvtM8T3dn4cIc7kgt2a4PGwwBoTiLqfMZm34+VQpVz0Ou2t/eWfk2GrXGmTNxHcW9ukxV8EAOrqwKZIJ+6fl+8M0AXjHcb5GWdcN9xWjyF6ehGe/5j05jmdri3cxPJGI3YOAOXABGARnGTjkcjpwenmvwt8Y61czeIdM8b6g0esaW3mTR3SwQJFAB99dijcOpZySoBjI+8TXR+EtK16SNdR1rWL64WUNPaWtxbxQGBXbKCVY0VjKq/f525dgBxuKA6i4ZfsSEyq0R275Wm8v5f7wZe/TjgHNWqiiSWNEV5vNwp3MygFj68cAdeMen4y0wKk6Mtysp3yQsvktEoyPmI+YgnGB9O57dPIfGML3H7SnhaGO+msXfS2C3EIjLqcXPTzFZeenIPXjnFeyiIJIzx4XzH3SZBO75ccc8dF/L3zXHah4D0K58US+ILuLUPtcMeI5l1G5WT5i+VjYSDYCW2hVIHLDaMg0AX9K8FaVZ+IJPEVxPc6rrTAxLf3rqzRJgKURUVUToeQoPzNk8mt0qRJF5uTMVdBNGuAucHoScdByeOPcAxRw3MdzOpuC3nZkQiEBY8EcMf4sggfRT0qYQSJBJGJWlGwKodirZxjlxzzxzjIOfYAA8Tn+HehfErRoPGvhDUP7J1uQCaWK3YmJLpQWZT0aN95X5xxgBgp3ZPb/AAi8U6r4q8BRajriv9qW5khFy6hBcrkEOoCqAAW2cZ5Q85yBdtPAfhSTSv7Og0mWxiWH7PcQ288lq86Y2/vjEy+cCM8sW6t6mukt9PttNsobLTbC0gtY34gjURIgzuJVVGM55xxz3oAnZf8ASI38vcQrLu3fdBwenccfy96+abbwjqHiu8+K1lpt/NFJBqYlW1MwSO5KzzECRmBJwA2ASBuKljxkfSF9ai7jeESzRtJGy5R3UAdCcoVIOGOCCD36qMc9oHgHw/oGrSalpMd1a3DuWnRb6Z1lYr/y2VnYOw3sQT03Z96AMn4W+PP+Et0xrLVZmi8TaerRX9pJH5Rba2BIE9egbGMMSCACtdxOHuYmXy3CCVRjIHmLkbs5HTrx3A9DXJN8LvCraj/adpa3SajtZBqC6rdGaMhdgw3mZOB8uMjgY9q39X0Sx1myuLLUknWwbLSLDdyQrKGUhgxRlOPvZUnac5OT0AseQfEHT7u71CP4keHrbTZJtFSGWQ/Zmk+3gMytMByDGm0BXwrbVdwwVYmPqXhvxDZeKdEj1bRL6AWM42NvT9/DLtVQkmWOXBx16jbjIINGl+GdPs9I/seG6nSAfIY7e/n3qqEBVSQuZI1A25RWABOOhO7P8NeA/DejRveaBpb2IuW2k/bJmDxjIDlJNyk4LYyOjHBGaAOwjeQogYxtIuBNtbhTjPH6cHsalqlbWMFrcSNuVnkkeZAwG5c/eI79wOO2O+SbtABSMiuMMoYZBwRnkHIP50UUALRRRQAUUUUAFFFFACBVUsVUAscsQOpxjn8AKWiigBFVUQIihVUYAAwAKY8EUkqSOgZ0BCk9uQf5qD+FFFAElFFFAH//2Q==';
return resultSuccess(result);
},
},

View File

@ -1,10 +1,10 @@
{
"name": "jeecg-boot-vue3",
"name": "jeecgboot-vue3",
"version": "1.0.0",
"author": {
"name": "jeecg",
"email": "jeecgos@163.com",
"url": "https://gitee.com/jeecg/jeecg-boot-vue3"
"url": "https://github.com/jeecgboot/jeecgboot-vue3"
},
"scripts": {
"bootstrap": "yarn install",
@ -35,28 +35,26 @@
},
"dependencies": {
"@iconify/iconify": "^2.0.4",
"@logicflow/core": "^0.6.15",
"@logicflow/extension": "^0.6.15",
"@fullcalendar/core": "^5.8.0",
"@fullcalendar/daygrid": "^5.8.0",
"@fullcalendar/interaction": "^5.8.0",
"@fullcalendar/timegrid": "^5.8.0",
"@fullcalendar/vue3": "^5.8.0",
"@vueuse/core": "^6.0.0",
"@vueuse/core": "^6.6.2",
"@zxcvbn-ts/core": "^1.0.0-beta.0",
"ant-design-vue": "^2.2.6",
"axios": "^0.21.1",
"ant-design-vue": "2.2.8",
"axios": "^0.23.0",
"china-area-data": "^5.0.1",
"clipboard": "^2.0.8",
"codemirror": "^5.62.3",
"codemirror": "^5.63.3",
"cron-parser": "^3.5.0",
"cropperjs": "^1.5.12",
"crypto-js": "^4.1.1",
"dayjs": "^1.10.6",
"dom-align": "^1.12.2",
"echarts": "^5.1.2",
"echarts": "^5.2.1",
"enquire.js": "^2.1.6",
"intro.js": "^4.1.0",
"intro.js": "^4.2.2",
"js-cookie": "^2.2.1",
"lodash-es": "^4.17.21",
"lodash.get": "^4.4.2",
@ -65,98 +63,103 @@
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0",
"pinia": "2.0.0-rc.6",
"pinia": "2.0.0-rc.14",
"print-js": "^1.6.0",
"qrcode": "^1.4.4",
"qrcodejs2": "0.0.2",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^1.9.1",
"sortablejs": "^1.14.0",
"tinymce": "^5.8.2",
"vditor": "^3.8.6",
"vue": "3.2.4",
"tinymce": "^5.10.0",
"vditor": "^3.8.7",
"vue": "^3.2.20",
"vue-cropper": "^0.5.6",
"vue-cropperjs": "^5.0.0",
"vue-i18n": "9.1.7",
"vue-i18n": "^9.1.9",
"vue-infinite-scroll": "^2.0.2",
"vue-router": "^4.0.11",
"vue-types": "^4.0.3",
"vxe-table": "^4.0.24",
"vue-print-nb-jeecg": "^1.0.10",
"vue-router": "^4.0.12",
"vue-types": "^4.1.1",
"vxe-table": "4.1.0",
"vxe-table-plugin-antd": "^3.0.3",
"xe-utils": "^3.3.1",
"xlsx": "^0.17.1",
"vue-json-pretty": "1.8.1"
"xlsx": "^0.17.3",
"qiankun": "^2.5.1",
"vue-json-pretty": "^2.0.4"
},
"devDependencies": {
"@commitlint/cli": "^13.1.0",
"@commitlint/config-conventional": "^13.1.0",
"@iconify/json": "^1.1.392",
"@commitlint/cli": "^13.2.1",
"@commitlint/config-conventional": "^13.2.0",
"@iconify/json": "^1.1.399",
"@purge-icons/generated": "^0.7.0",
"@types/codemirror": "^5.60.2",
"@types/codemirror": "^5.60.5",
"@types/crypto-js": "^4.0.2",
"@types/fs-extra": "^9.0.12",
"@types/inquirer": "^7.3.3",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.1.3",
"@types/intro.js": "^3.0.2",
"@types/jest": "^27.0.1",
"@types/lodash-es": "^4.17.4",
"@types/jest": "^27.0.2",
"@types/lodash-es": "^4.17.5",
"@types/mockjs": "^1.0.4",
"@types/node": "^16.7.1",
"@types/node": "^16.11.1",
"@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.4.1",
"@types/qs": "^6.9.7",
"@types/showdown": "^1.9.4",
"@types/sortablejs": "^1.10.7",
"@typescript-eslint/eslint-plugin": "^4.29.3",
"@typescript-eslint/parser": "^4.29.3",
"@vitejs/plugin-legacy": "^1.5.1",
"@vitejs/plugin-vue": "^1.4.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "3.2.4",
"@vue/test-utils": "^2.0.0-rc.12",
"autoprefixer": "^10.3.2",
"@typescript-eslint/eslint-plugin": "^5.1.0",
"@typescript-eslint/parser": "^5.1.0",
"@vitejs/plugin-legacy": "^1.6.2",
"@vitejs/plugin-vue": "^1.9.3",
"@vitejs/plugin-vue-jsx": "^1.2.0",
"@vue/compiler-sfc": "3.2.20",
"@vue/test-utils": "^2.0.0-rc.16",
"autoprefixer": "^10.3.7",
"commitizen": "^4.2.4",
"conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3",
"dotenv": "^10.0.0",
"eslint": "^7.32.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-define-config": "^1.0.9",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-vue": "^7.16.0",
"esno": "^0.9.1",
"eslint-define-config": "^1.1.1",
"eslint-plugin-jest": "^25.2.2",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^7.19.1",
"esno": "^0.10.1",
"fs-extra": "^10.0.0",
"http-server": "^13.0.1",
"husky": "^7.0.1",
"inquirer": "^8.1.2",
"http-server": "^14.0.0",
"husky": "^7.0.2",
"inquirer": "^8.2.0",
"is-ci": "^3.0.0",
"jest": "^27.0.6",
"less": "^4.1.1",
"lint-staged": "^11.1.2",
"jest": "^27.3.1",
"less": "^4.1.2",
"lint-staged": "^11.2.3",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.6",
"prettier": "^2.3.2",
"postcss": "^8.3.9",
"prettier": "^2.4.1",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "5.5.2",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"ts-jest": "^27.0.5",
"ts-node": "^10.2.1",
"typescript": "4.3.5",
"vite": "2.5.0",
"ts-jest": "^27.0.7",
"ts-node": "^10.3.0",
"typescript": "^4.4.4",
"vite": "^2.6.10",
"vite-plugin-compression": "^0.3.5",
"vite-plugin-html": "^2.1.0",
"vite-plugin-imagemin": "^0.4.5",
"vite-plugin-imagemin": "^0.4.6",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-purge-icons": "^0.7.0",
"vite-plugin-pwa": "^0.11.0",
"vite-plugin-pwa": "^0.11.3",
"vite-plugin-style-import": "^1.2.1",
"vite-plugin-svg-icons": "^1.0.4",
"vite-plugin-windicss": "^1.2.8",
"vite-plugin-svg-icons": "^1.0.5",
"vite-plugin-theme": "^0.8.1",
"vue-eslint-parser": "^7.10.0",
"vue-tsc": "^0.3.0"
"vite-plugin-vue-setup-extend": "^0.1.0",
"vite-plugin-windicss": "^1.4.12",
"vue-eslint-parser": "^8.0.0",
"vue-tsc": "^0.28.7"
},
"resolutions": {
"//": "Used to install imagemin dependencies, because imagemin may not be installed in China. If it is abroad, you can delete it",
@ -165,13 +168,13 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/jeecgboot/jeecg-boot-vue3"
"url": "git+https://github.com/jeecgboot/jeecgboot-vue3.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/jeecgboot/jeecg-boot-vue3/issues"
"url": "https://github.com/jeecgboot/jeecgboot-vue3/issues"
},
"homepage": "https://github.com/jeecgboot/jeecg-boot-vue3",
"homepage": "https://github.com/jeecgboot/jeecgboot-vue3",
"engines": {
"node": "^12 || >=14"
}

View File

@ -8,7 +8,6 @@ module.exports = {
quoteProps: 'as-needed',
bracketSpacing: true,
trailingComma: 'es5',
jsxBracketSameLine: false,
jsxSingleQuote: false,
arrowParens: 'always',
insertPragma: false,

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -0,0 +1,711 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.mce-content-body .mce-item-anchor {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
cursor: default;
display: inline-block;
height: 12px !important;
padding: 0 2px;
-webkit-user-modify: read-only;
-moz-user-modify: read-only;
-webkit-user-select: all;
-ms-user-select: all;
user-select: all;
width: 8px !important;
}
.mce-content-body .mce-item-anchor[data-mce-selected] {
outline-offset: 1px;
}
.tox-comments-visible .tox-comment {
background-color: #fff0b7;
}
.tox-comments-visible .tox-comment--active {
background-color: #ffe168;
}
.tox-checklist > li:not(.tox-checklist--hidden) {
list-style: none;
margin: 0.25em 0;
}
.tox-checklist > li:not(.tox-checklist--hidden)::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
cursor: pointer;
height: 1em;
margin-left: -1.5em;
margin-top: 0.125em;
position: absolute;
width: 1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
}
[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before {
margin-left: 0;
margin-right: -1.5em;
}
/* stylelint-disable */
/* http://prismjs.com/ */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* stylelint-enable */
.mce-content-body {
overflow-wrap: break-word;
word-wrap: break-word;
}
.mce-content-body .mce-visual-caret {
background-color: black;
background-color: currentColor;
position: absolute;
}
.mce-content-body .mce-visual-caret-hidden {
display: none;
}
.mce-content-body *[data-mce-caret] {
left: -1000px;
margin: 0;
padding: 0;
position: absolute;
right: auto;
top: 0;
}
.mce-content-body .mce-offscreen-selection {
left: -2000000px;
max-width: 1000000px;
position: absolute;
}
.mce-content-body *[contentEditable=false] {
cursor: default;
}
.mce-content-body *[contentEditable=true] {
cursor: text;
}
.tox-cursor-format-painter {
cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default;
}
.mce-content-body figure.align-left {
float: left;
}
.mce-content-body figure.align-right {
float: right;
}
.mce-content-body figure.image.align-center {
display: table;
margin-left: auto;
margin-right: auto;
}
.mce-preview-object {
border: 1px solid gray;
display: inline-block;
line-height: 0;
margin: 0 2px 0 2px;
position: relative;
}
.mce-preview-object .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-preview-object[data-mce-selected="2"] .mce-shim {
display: none;
}
.mce-object {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
border: 1px dashed #aaa;
}
.mce-pagebreak {
border: 1px dashed #aaa;
cursor: default;
display: block;
height: 5px;
margin-top: 15px;
page-break-before: always;
width: 100%;
}
@media print {
.mce-pagebreak {
border: 0;
}
}
.tiny-pageembed .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tiny-pageembed[data-mce-selected="2"] .mce-shim {
display: none;
}
.tiny-pageembed {
display: inline-block;
position: relative;
}
.tiny-pageembed--21by9,
.tiny-pageembed--16by9,
.tiny-pageembed--4by3,
.tiny-pageembed--1by1 {
display: block;
overflow: hidden;
padding: 0;
position: relative;
width: 100%;
}
.tiny-pageembed--21by9 {
padding-top: 42.857143%;
}
.tiny-pageembed--16by9 {
padding-top: 56.25%;
}
.tiny-pageembed--4by3 {
padding-top: 75%;
}
.tiny-pageembed--1by1 {
padding-top: 100%;
}
.tiny-pageembed--21by9 iframe,
.tiny-pageembed--16by9 iframe,
.tiny-pageembed--4by3 iframe,
.tiny-pageembed--1by1 iframe {
border: 0;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-content-body[data-mce-placeholder] {
position: relative;
}
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
color: rgba(84, 111, 94, 0.7);
content: attr(data-mce-placeholder);
position: absolute;
}
.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
left: 1px;
}
.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before {
right: 1px;
}
.mce-content-body div.mce-resizehandle {
background-color: #4099ff;
border-color: #4099ff;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
height: 10px;
position: absolute;
width: 10px;
z-index: 10000;
}
.mce-content-body div.mce-resizehandle:hover {
background-color: #4099ff;
}
.mce-content-body div.mce-resizehandle:nth-of-type(1) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(2) {
cursor: nesw-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(3) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(4) {
cursor: nesw-resize;
}
.mce-content-body .mce-resize-backdrop {
z-index: 10000;
}
.mce-content-body .mce-clonedresizable {
cursor: default;
opacity: 0.5;
outline: 1px dashed black;
position: absolute;
z-index: 10001;
}
.mce-content-body .mce-clonedresizable.mce-resizetable-columns th,
.mce-content-body .mce-clonedresizable.mce-resizetable-columns td {
border: 0;
}
.mce-content-body .mce-resize-helper {
background: #555;
background: rgba(0, 0, 0, 0.75);
border: 1px;
border-radius: 3px;
color: white;
display: none;
font-family: sans-serif;
font-size: 12px;
line-height: 14px;
margin: 5px 10px;
padding: 5px;
position: absolute;
white-space: nowrap;
z-index: 10002;
}
.tox-rtc-user-selection {
position: relative;
}
.tox-rtc-user-cursor {
bottom: 0;
cursor: default;
position: absolute;
top: 0;
width: 2px;
}
.tox-rtc-user-cursor::before {
background-color: inherit;
border-radius: 50%;
content: '';
display: block;
height: 8px;
position: absolute;
right: -3px;
top: -3px;
width: 8px;
}
.tox-rtc-user-cursor:hover::after {
background-color: inherit;
border-radius: 100px;
box-sizing: border-box;
color: #fff;
content: attr(data-user);
display: block;
font-size: 12px;
font-weight: normal;
left: -5px;
min-height: 8px;
min-width: 8px;
padding: 0 12px;
position: absolute;
top: -11px;
white-space: nowrap;
z-index: 1000;
}
.tox-rtc-user-selection--1 .tox-rtc-user-cursor {
background-color: #2dc26b;
}
.tox-rtc-user-selection--2 .tox-rtc-user-cursor {
background-color: #e03e2d;
}
.tox-rtc-user-selection--3 .tox-rtc-user-cursor {
background-color: #f1c40f;
}
.tox-rtc-user-selection--4 .tox-rtc-user-cursor {
background-color: #3598db;
}
.tox-rtc-user-selection--5 .tox-rtc-user-cursor {
background-color: #b96ad9;
}
.tox-rtc-user-selection--6 .tox-rtc-user-cursor {
background-color: #e67e23;
}
.tox-rtc-user-selection--7 .tox-rtc-user-cursor {
background-color: #aaa69d;
}
.tox-rtc-user-selection--8 .tox-rtc-user-cursor {
background-color: #f368e0;
}
.tox-rtc-remote-image {
background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;
border: 1px solid #ccc;
min-height: 240px;
min-width: 320px;
}
.mce-match-marker {
background: #aaa;
color: #fff;
}
.mce-match-marker-selected {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::selection {
background: #39f;
color: #fff;
}
.mce-content-body img[data-mce-selected],
.mce-content-body video[data-mce-selected],
.mce-content-body audio[data-mce-selected],
.mce-content-body object[data-mce-selected],
.mce-content-body embed[data-mce-selected],
.mce-content-body table[data-mce-selected] {
outline: 3px solid #b4d7ff;
}
.mce-content-body hr[data-mce-selected] {
outline: 3px solid #b4d7ff;
outline-offset: 1px;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false][data-mce-selected] {
cursor: not-allowed;
outline: 3px solid #b4d7ff;
}
.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,
.mce-content-body.mce-content-readonly *[contentEditable=true]:hover {
outline: none;
}
.mce-content-body *[data-mce-selected="inline-boundary"] {
background-color: #b4d7ff;
}
.mce-content-body .mce-edit-focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body td[data-mce-selected],
.mce-content-body th[data-mce-selected] {
position: relative;
}
.mce-content-body td[data-mce-selected]::selection,
.mce-content-body th[data-mce-selected]::selection {
background: none;
}
.mce-content-body td[data-mce-selected] *,
.mce-content-body th[data-mce-selected] * {
outline: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
background-color: rgba(180, 215, 255, 0.7);
border: 1px solid rgba(180, 215, 255, 0.7);
bottom: -1px;
content: '';
left: -1px;
mix-blend-mode: multiply;
position: absolute;
right: -1px;
top: -1px;
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
border-color: rgba(0, 84, 180, 0.7);
}
}
.mce-content-body img::selection {
background: none;
}
.ephox-snooker-resizer-bar {
background-color: #b4d7ff;
opacity: 0;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ephox-snooker-resizer-cols {
cursor: col-resize;
}
.ephox-snooker-resizer-rows {
cursor: row-resize;
}
.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging {
opacity: 1;
}
.mce-spellchecker-word {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
height: 2rem;
}
.mce-spellchecker-grammar {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
}
.mce-toc {
border: 1px solid gray;
}
.mce-toc h2 {
margin: 4px;
}
.mce-toc li {
list-style-type: none;
}
table[style*="border-width: 0px"],
.mce-item-table:not([border]),
.mce-item-table[border="0"],
table[style*="border-width: 0px"] td,
.mce-item-table:not([border]) td,
.mce-item-table[border="0"] td,
table[style*="border-width: 0px"] th,
.mce-item-table:not([border]) th,
.mce-item-table[border="0"] th,
table[style*="border-width: 0px"] caption,
.mce-item-table:not([border]) caption,
.mce-item-table[border="0"] caption {
border: 1px dashed #bbb;
}
.mce-visualblocks p,
.mce-visualblocks h1,
.mce-visualblocks h2,
.mce-visualblocks h3,
.mce-visualblocks h4,
.mce-visualblocks h5,
.mce-visualblocks h6,
.mce-visualblocks div:not([data-mce-bogus]),
.mce-visualblocks section,
.mce-visualblocks article,
.mce-visualblocks blockquote,
.mce-visualblocks address,
.mce-visualblocks pre,
.mce-visualblocks figure,
.mce-visualblocks figcaption,
.mce-visualblocks hgroup,
.mce-visualblocks aside,
.mce-visualblocks ul,
.mce-visualblocks ol,
.mce-visualblocks dl {
background-repeat: no-repeat;
border: 1px dashed #bbb;
margin-left: 3px;
padding-top: 10px;
}
.mce-visualblocks p {
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
}
.mce-visualblocks h1 {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
}
.mce-visualblocks h2 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
}
.mce-visualblocks h3 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
}
.mce-visualblocks h4 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
}
.mce-visualblocks h5 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
}
.mce-visualblocks h6 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
}
.mce-visualblocks div:not([data-mce-bogus]) {
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
}
.mce-visualblocks section {
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
}
.mce-visualblocks article {
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
}
.mce-visualblocks blockquote {
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
}
.mce-visualblocks address {
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
}
.mce-visualblocks pre {
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
}
.mce-visualblocks figure {
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
}
.mce-visualblocks figcaption {
border: 1px dashed #bbb;
}
.mce-visualblocks hgroup {
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
}
.mce-visualblocks aside {
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
}
.mce-visualblocks ul {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
}
.mce-visualblocks ol {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
}
.mce-visualblocks dl {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
}
.mce-visualblocks:not([dir=rtl]) p,
.mce-visualblocks:not([dir=rtl]) h1,
.mce-visualblocks:not([dir=rtl]) h2,
.mce-visualblocks:not([dir=rtl]) h3,
.mce-visualblocks:not([dir=rtl]) h4,
.mce-visualblocks:not([dir=rtl]) h5,
.mce-visualblocks:not([dir=rtl]) h6,
.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),
.mce-visualblocks:not([dir=rtl]) section,
.mce-visualblocks:not([dir=rtl]) article,
.mce-visualblocks:not([dir=rtl]) blockquote,
.mce-visualblocks:not([dir=rtl]) address,
.mce-visualblocks:not([dir=rtl]) pre,
.mce-visualblocks:not([dir=rtl]) figure,
.mce-visualblocks:not([dir=rtl]) figcaption,
.mce-visualblocks:not([dir=rtl]) hgroup,
.mce-visualblocks:not([dir=rtl]) aside,
.mce-visualblocks:not([dir=rtl]) ul,
.mce-visualblocks:not([dir=rtl]) ol,
.mce-visualblocks:not([dir=rtl]) dl {
margin-left: 3px;
}
.mce-visualblocks[dir=rtl] p,
.mce-visualblocks[dir=rtl] h1,
.mce-visualblocks[dir=rtl] h2,
.mce-visualblocks[dir=rtl] h3,
.mce-visualblocks[dir=rtl] h4,
.mce-visualblocks[dir=rtl] h5,
.mce-visualblocks[dir=rtl] h6,
.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),
.mce-visualblocks[dir=rtl] section,
.mce-visualblocks[dir=rtl] article,
.mce-visualblocks[dir=rtl] blockquote,
.mce-visualblocks[dir=rtl] address,
.mce-visualblocks[dir=rtl] pre,
.mce-visualblocks[dir=rtl] figure,
.mce-visualblocks[dir=rtl] figcaption,
.mce-visualblocks[dir=rtl] hgroup,
.mce-visualblocks[dir=rtl] aside,
.mce-visualblocks[dir=rtl] ul,
.mce-visualblocks[dir=rtl] ol,
.mce-visualblocks[dir=rtl] dl {
background-position-x: right;
margin-right: 3px;
}
.mce-nbsp,
.mce-shy {
background: #aaa;
}
.mce-shy::after {
content: '-';
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}

View File

@ -0,0 +1,705 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.mce-content-body .mce-item-anchor {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
cursor: default;
display: inline-block;
height: 12px !important;
padding: 0 2px;
-webkit-user-modify: read-only;
-moz-user-modify: read-only;
-webkit-user-select: all;
-ms-user-select: all;
user-select: all;
width: 8px !important;
}
.mce-content-body .mce-item-anchor[data-mce-selected] {
outline-offset: 1px;
}
.tox-comments-visible .tox-comment {
background-color: #fff0b7;
}
.tox-comments-visible .tox-comment--active {
background-color: #ffe168;
}
.tox-checklist > li:not(.tox-checklist--hidden) {
list-style: none;
margin: 0.25em 0;
}
.tox-checklist > li:not(.tox-checklist--hidden)::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
cursor: pointer;
height: 1em;
margin-left: -1.5em;
margin-top: 0.125em;
position: absolute;
width: 1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
}
[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before {
margin-left: 0;
margin-right: -1.5em;
}
/* stylelint-disable */
/* http://prismjs.com/ */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* stylelint-enable */
.mce-content-body {
overflow-wrap: break-word;
word-wrap: break-word;
}
.mce-content-body .mce-visual-caret {
background-color: black;
background-color: currentColor;
position: absolute;
}
.mce-content-body .mce-visual-caret-hidden {
display: none;
}
.mce-content-body *[data-mce-caret] {
left: -1000px;
margin: 0;
padding: 0;
position: absolute;
right: auto;
top: 0;
}
.mce-content-body .mce-offscreen-selection {
left: -2000000px;
max-width: 1000000px;
position: absolute;
}
.mce-content-body *[contentEditable=false] {
cursor: default;
}
.mce-content-body *[contentEditable=true] {
cursor: text;
}
.tox-cursor-format-painter {
cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default;
}
.mce-content-body figure.align-left {
float: left;
}
.mce-content-body figure.align-right {
float: right;
}
.mce-content-body figure.image.align-center {
display: table;
margin-left: auto;
margin-right: auto;
}
.mce-preview-object {
border: 1px solid gray;
display: inline-block;
line-height: 0;
margin: 0 2px 0 2px;
position: relative;
}
.mce-preview-object .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-preview-object[data-mce-selected="2"] .mce-shim {
display: none;
}
.mce-object {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
border: 1px dashed #aaa;
}
.mce-pagebreak {
border: 1px dashed #aaa;
cursor: default;
display: block;
height: 5px;
margin-top: 15px;
page-break-before: always;
width: 100%;
}
@media print {
.mce-pagebreak {
border: 0;
}
}
.tiny-pageembed .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tiny-pageembed[data-mce-selected="2"] .mce-shim {
display: none;
}
.tiny-pageembed {
display: inline-block;
position: relative;
}
.tiny-pageembed--21by9,
.tiny-pageembed--16by9,
.tiny-pageembed--4by3,
.tiny-pageembed--1by1 {
display: block;
overflow: hidden;
padding: 0;
position: relative;
width: 100%;
}
.tiny-pageembed--21by9 {
padding-top: 42.857143%;
}
.tiny-pageembed--16by9 {
padding-top: 56.25%;
}
.tiny-pageembed--4by3 {
padding-top: 75%;
}
.tiny-pageembed--1by1 {
padding-top: 100%;
}
.tiny-pageembed--21by9 iframe,
.tiny-pageembed--16by9 iframe,
.tiny-pageembed--4by3 iframe,
.tiny-pageembed--1by1 iframe {
border: 0;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-content-body[data-mce-placeholder] {
position: relative;
}
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
color: rgba(84, 111, 94, 0.7);
content: attr(data-mce-placeholder);
position: absolute;
}
.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before {
left: 1px;
}
.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before {
right: 1px;
}
.mce-content-body div.mce-resizehandle {
background-color: #4099ff;
border-color: #4099ff;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
height: 10px;
position: absolute;
width: 10px;
z-index: 10000;
}
.mce-content-body div.mce-resizehandle:hover {
background-color: #4099ff;
}
.mce-content-body div.mce-resizehandle:nth-of-type(1) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(2) {
cursor: nesw-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(3) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(4) {
cursor: nesw-resize;
}
.mce-content-body .mce-resize-backdrop {
z-index: 10000;
}
.mce-content-body .mce-clonedresizable {
cursor: default;
opacity: 0.5;
outline: 1px dashed black;
position: absolute;
z-index: 10001;
}
.mce-content-body .mce-clonedresizable.mce-resizetable-columns th,
.mce-content-body .mce-clonedresizable.mce-resizetable-columns td {
border: 0;
}
.mce-content-body .mce-resize-helper {
background: #555;
background: rgba(0, 0, 0, 0.75);
border: 1px;
border-radius: 3px;
color: white;
display: none;
font-family: sans-serif;
font-size: 12px;
line-height: 14px;
margin: 5px 10px;
padding: 5px;
position: absolute;
white-space: nowrap;
z-index: 10002;
}
.tox-rtc-user-selection {
position: relative;
}
.tox-rtc-user-cursor {
bottom: 0;
cursor: default;
position: absolute;
top: 0;
width: 2px;
}
.tox-rtc-user-cursor::before {
background-color: inherit;
border-radius: 50%;
content: '';
display: block;
height: 8px;
position: absolute;
right: -3px;
top: -3px;
width: 8px;
}
.tox-rtc-user-cursor:hover::after {
background-color: inherit;
border-radius: 100px;
box-sizing: border-box;
color: #fff;
content: attr(data-user);
display: block;
font-size: 12px;
font-weight: normal;
left: -5px;
min-height: 8px;
min-width: 8px;
padding: 0 12px;
position: absolute;
top: -11px;
white-space: nowrap;
z-index: 1000;
}
.tox-rtc-user-selection--1 .tox-rtc-user-cursor {
background-color: #2dc26b;
}
.tox-rtc-user-selection--2 .tox-rtc-user-cursor {
background-color: #e03e2d;
}
.tox-rtc-user-selection--3 .tox-rtc-user-cursor {
background-color: #f1c40f;
}
.tox-rtc-user-selection--4 .tox-rtc-user-cursor {
background-color: #3598db;
}
.tox-rtc-user-selection--5 .tox-rtc-user-cursor {
background-color: #b96ad9;
}
.tox-rtc-user-selection--6 .tox-rtc-user-cursor {
background-color: #e67e23;
}
.tox-rtc-user-selection--7 .tox-rtc-user-cursor {
background-color: #aaa69d;
}
.tox-rtc-user-selection--8 .tox-rtc-user-cursor {
background-color: #f368e0;
}
.tox-rtc-remote-image {
background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;
border: 1px solid #ccc;
min-height: 240px;
min-width: 320px;
}
.mce-match-marker {
background: #aaa;
color: #fff;
}
.mce-match-marker-selected {
background: #39f;
color: #fff;
}
.mce-match-marker-selected::selection {
background: #39f;
color: #fff;
}
.mce-content-body img[data-mce-selected],
.mce-content-body video[data-mce-selected],
.mce-content-body audio[data-mce-selected],
.mce-content-body object[data-mce-selected],
.mce-content-body embed[data-mce-selected],
.mce-content-body table[data-mce-selected] {
outline: 3px solid #b4d7ff;
}
.mce-content-body hr[data-mce-selected] {
outline: 3px solid #b4d7ff;
outline-offset: 1px;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false][data-mce-selected] {
cursor: not-allowed;
outline: 3px solid #b4d7ff;
}
.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,
.mce-content-body.mce-content-readonly *[contentEditable=true]:hover {
outline: none;
}
.mce-content-body *[data-mce-selected="inline-boundary"] {
background-color: #b4d7ff;
}
.mce-content-body .mce-edit-focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body td[data-mce-selected],
.mce-content-body th[data-mce-selected] {
position: relative;
}
.mce-content-body td[data-mce-selected]::selection,
.mce-content-body th[data-mce-selected]::selection {
background: none;
}
.mce-content-body td[data-mce-selected] *,
.mce-content-body th[data-mce-selected] * {
outline: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
background-color: rgba(180, 215, 255, 0.7);
border: 1px solid rgba(180, 215, 255, 0.7);
bottom: -1px;
content: '';
left: -1px;
mix-blend-mode: multiply;
position: absolute;
right: -1px;
top: -1px;
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.mce-content-body td[data-mce-selected]::after,
.mce-content-body th[data-mce-selected]::after {
border-color: rgba(0, 84, 180, 0.7);
}
}
.mce-content-body img::selection {
background: none;
}
.ephox-snooker-resizer-bar {
background-color: #b4d7ff;
opacity: 0;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ephox-snooker-resizer-cols {
cursor: col-resize;
}
.ephox-snooker-resizer-rows {
cursor: row-resize;
}
.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging {
opacity: 1;
}
.mce-spellchecker-word {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
height: 2rem;
}
.mce-spellchecker-grammar {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
}
.mce-toc {
border: 1px solid gray;
}
.mce-toc h2 {
margin: 4px;
}
.mce-toc li {
list-style-type: none;
}
table[style*="border-width: 0px"],
.mce-item-table:not([border]),
.mce-item-table[border="0"],
table[style*="border-width: 0px"] td,
.mce-item-table:not([border]) td,
.mce-item-table[border="0"] td,
table[style*="border-width: 0px"] th,
.mce-item-table:not([border]) th,
.mce-item-table[border="0"] th,
table[style*="border-width: 0px"] caption,
.mce-item-table:not([border]) caption,
.mce-item-table[border="0"] caption {
border: 1px dashed #bbb;
}
.mce-visualblocks p,
.mce-visualblocks h1,
.mce-visualblocks h2,
.mce-visualblocks h3,
.mce-visualblocks h4,
.mce-visualblocks h5,
.mce-visualblocks h6,
.mce-visualblocks div:not([data-mce-bogus]),
.mce-visualblocks section,
.mce-visualblocks article,
.mce-visualblocks blockquote,
.mce-visualblocks address,
.mce-visualblocks pre,
.mce-visualblocks figure,
.mce-visualblocks figcaption,
.mce-visualblocks hgroup,
.mce-visualblocks aside,
.mce-visualblocks ul,
.mce-visualblocks ol,
.mce-visualblocks dl {
background-repeat: no-repeat;
border: 1px dashed #bbb;
margin-left: 3px;
padding-top: 10px;
}
.mce-visualblocks p {
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
}
.mce-visualblocks h1 {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
}
.mce-visualblocks h2 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
}
.mce-visualblocks h3 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
}
.mce-visualblocks h4 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
}
.mce-visualblocks h5 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
}
.mce-visualblocks h6 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
}
.mce-visualblocks div:not([data-mce-bogus]) {
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
}
.mce-visualblocks section {
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
}
.mce-visualblocks article {
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
}
.mce-visualblocks blockquote {
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
}
.mce-visualblocks address {
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
}
.mce-visualblocks pre {
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
}
.mce-visualblocks figure {
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
}
.mce-visualblocks figcaption {
border: 1px dashed #bbb;
}
.mce-visualblocks hgroup {
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
}
.mce-visualblocks aside {
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
}
.mce-visualblocks ul {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
}
.mce-visualblocks ol {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
}
.mce-visualblocks dl {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
}
.mce-visualblocks:not([dir=rtl]) p,
.mce-visualblocks:not([dir=rtl]) h1,
.mce-visualblocks:not([dir=rtl]) h2,
.mce-visualblocks:not([dir=rtl]) h3,
.mce-visualblocks:not([dir=rtl]) h4,
.mce-visualblocks:not([dir=rtl]) h5,
.mce-visualblocks:not([dir=rtl]) h6,
.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),
.mce-visualblocks:not([dir=rtl]) section,
.mce-visualblocks:not([dir=rtl]) article,
.mce-visualblocks:not([dir=rtl]) blockquote,
.mce-visualblocks:not([dir=rtl]) address,
.mce-visualblocks:not([dir=rtl]) pre,
.mce-visualblocks:not([dir=rtl]) figure,
.mce-visualblocks:not([dir=rtl]) figcaption,
.mce-visualblocks:not([dir=rtl]) hgroup,
.mce-visualblocks:not([dir=rtl]) aside,
.mce-visualblocks:not([dir=rtl]) ul,
.mce-visualblocks:not([dir=rtl]) ol,
.mce-visualblocks:not([dir=rtl]) dl {
margin-left: 3px;
}
.mce-visualblocks[dir=rtl] p,
.mce-visualblocks[dir=rtl] h1,
.mce-visualblocks[dir=rtl] h2,
.mce-visualblocks[dir=rtl] h3,
.mce-visualblocks[dir=rtl] h4,
.mce-visualblocks[dir=rtl] h5,
.mce-visualblocks[dir=rtl] h6,
.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),
.mce-visualblocks[dir=rtl] section,
.mce-visualblocks[dir=rtl] article,
.mce-visualblocks[dir=rtl] blockquote,
.mce-visualblocks[dir=rtl] address,
.mce-visualblocks[dir=rtl] pre,
.mce-visualblocks[dir=rtl] figure,
.mce-visualblocks[dir=rtl] figcaption,
.mce-visualblocks[dir=rtl] hgroup,
.mce-visualblocks[dir=rtl] aside,
.mce-visualblocks[dir=rtl] ul,
.mce-visualblocks[dir=rtl] ol,
.mce-visualblocks[dir=rtl] dl {
background-position-x: right;
margin-right: 3px;
}
.mce-nbsp,
.mce-shy {
background: #aaa;
}
.mce-shy::after {
content: '-';
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection {
/* Note: this file is used inside the content, so isn't part of theming */
background-color: green;
display: inline-block;
opacity: 0.5;
position: absolute;
}
body {
-webkit-text-size-adjust: none;
}
body img {
/* this is related to the content margin */
max-width: 96vw;
}
body table img {
max-width: 95%;
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}

View File

@ -0,0 +1,7 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,677 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
/* RESET all the things! */
.tinymce-mobile-outer-container {
all: initial;
display: block;
}
.tinymce-mobile-outer-container * {
border: 0;
box-sizing: initial;
cursor: inherit;
float: none;
line-height: 1;
margin: 0;
outline: 0;
padding: 0;
-webkit-tap-highlight-color: transparent;
/* TBIO-3691, stop the gray flicker on touch. */
text-shadow: none;
white-space: nowrap;
}
.tinymce-mobile-icon-arrow-back::before {
content: "\e5cd";
}
.tinymce-mobile-icon-image::before {
content: "\e412";
}
.tinymce-mobile-icon-cancel-circle::before {
content: "\e5c9";
}
.tinymce-mobile-icon-full-dot::before {
content: "\e061";
}
.tinymce-mobile-icon-align-center::before {
content: "\e234";
}
.tinymce-mobile-icon-align-left::before {
content: "\e236";
}
.tinymce-mobile-icon-align-right::before {
content: "\e237";
}
.tinymce-mobile-icon-bold::before {
content: "\e238";
}
.tinymce-mobile-icon-italic::before {
content: "\e23f";
}
.tinymce-mobile-icon-unordered-list::before {
content: "\e241";
}
.tinymce-mobile-icon-ordered-list::before {
content: "\e242";
}
.tinymce-mobile-icon-font-size::before {
content: "\e245";
}
.tinymce-mobile-icon-underline::before {
content: "\e249";
}
.tinymce-mobile-icon-link::before {
content: "\e157";
}
.tinymce-mobile-icon-unlink::before {
content: "\eca2";
}
.tinymce-mobile-icon-color::before {
content: "\e891";
}
.tinymce-mobile-icon-previous::before {
content: "\e314";
}
.tinymce-mobile-icon-next::before {
content: "\e315";
}
.tinymce-mobile-icon-large-font::before,
.tinymce-mobile-icon-style-formats::before {
content: "\e264";
}
.tinymce-mobile-icon-undo::before {
content: "\e166";
}
.tinymce-mobile-icon-redo::before {
content: "\e15a";
}
.tinymce-mobile-icon-removeformat::before {
content: "\e239";
}
.tinymce-mobile-icon-small-font::before {
content: "\e906";
}
.tinymce-mobile-icon-readonly-back::before,
.tinymce-mobile-format-matches::after {
content: "\e5ca";
}
.tinymce-mobile-icon-small-heading::before {
content: "small";
}
.tinymce-mobile-icon-large-heading::before {
content: "large";
}
.tinymce-mobile-icon-small-heading::before,
.tinymce-mobile-icon-large-heading::before {
font-family: sans-serif;
font-size: 80%;
}
.tinymce-mobile-mask-edit-icon::before {
content: "\e254";
}
.tinymce-mobile-icon-back::before {
content: "\e5c4";
}
.tinymce-mobile-icon-heading::before {
/* TODO: Translate */
content: "Headings";
font-family: sans-serif;
font-size: 80%;
font-weight: bold;
}
.tinymce-mobile-icon-h1::before {
content: "H1";
font-weight: bold;
}
.tinymce-mobile-icon-h2::before {
content: "H2";
font-weight: bold;
}
.tinymce-mobile-icon-h3::before {
content: "H3";
font-weight: bold;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask {
align-items: center;
display: flex;
justify-content: center;
background: rgba(51, 51, 51, 0.5);
height: 100%;
position: absolute;
top: 0;
width: 100%;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container {
align-items: center;
border-radius: 50%;
display: flex;
flex-direction: column;
font-family: sans-serif;
font-size: 1em;
justify-content: space-between;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .mixin-menu-item {
align-items: center;
display: flex;
justify-content: center;
border-radius: 50%;
height: 2.1em;
width: 2.1em;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section {
align-items: center;
display: flex;
justify-content: center;
flex-direction: column;
font-size: 1em;
}
@media only screen and (min-device-width:700px) {
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section {
font-size: 1.2em;
}
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon {
align-items: center;
display: flex;
justify-content: center;
border-radius: 50%;
height: 2.1em;
width: 2.1em;
background-color: white;
color: #207ab7;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon::before {
content: "\e900";
font-family: 'tinymce-mobile', sans-serif;
}
.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section:not(.tinymce-mobile-mask-tap-icon-selected) .tinymce-mobile-mask-tap-icon {
z-index: 2;
}
.tinymce-mobile-android-container.tinymce-mobile-android-maximized {
background: #ffffff;
border: none;
bottom: 0;
display: flex;
flex-direction: column;
left: 0;
position: fixed;
right: 0;
top: 0;
}
.tinymce-mobile-android-container:not(.tinymce-mobile-android-maximized) {
position: relative;
}
.tinymce-mobile-android-container .tinymce-mobile-editor-socket {
display: flex;
flex-grow: 1;
}
.tinymce-mobile-android-container .tinymce-mobile-editor-socket iframe {
display: flex !important;
flex-grow: 1;
height: auto !important;
}
.tinymce-mobile-android-scroll-reload {
overflow: hidden;
}
:not(.tinymce-mobile-readonly-mode) > .tinymce-mobile-android-selection-context-toolbar {
margin-top: 23px;
}
.tinymce-mobile-toolstrip {
background: #fff;
display: flex;
flex: 0 0 auto;
z-index: 1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar {
align-items: center;
background-color: #fff;
border-bottom: 1px solid #cccccc;
display: flex;
flex: 1;
height: 2.5em;
width: 100%;
/* Make it no larger than the toolstrip, so that it needs to scroll */
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group {
align-items: center;
display: flex;
height: 100%;
flex-shrink: 1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group > div {
align-items: center;
display: flex;
height: 100%;
flex: 1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-exit-container {
background: #f44336;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-toolbar-scrollable-group {
flex-grow: 1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item {
padding-left: 0.5em;
padding-right: 0.5em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button {
align-items: center;
display: flex;
height: 80%;
margin-left: 2px;
margin-right: 2px;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button.tinymce-mobile-toolbar-button-selected {
background: #d4dbd7;
color: #cccccc;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:first-of-type,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:last-of-type {
background: #207ab7;
color: #eceff1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar {
/* Note, this file is imported inside .tinymce-mobile-context-toolbar, so that prefix is on everything here. */
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group {
align-items: center;
display: flex;
height: 100%;
flex: 1;
padding-bottom: 0.4em;
padding-top: 0.4em;
/* Make any buttons appearing on the left and right display in the centre (e.g. color edges) */
/* For widgets like the colour picker, use the whole height */
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog {
display: flex;
min-height: 1.5em;
overflow: hidden;
padding-left: 0;
padding-right: 0;
position: relative;
width: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain {
display: flex;
height: 100%;
transition: left cubic-bezier(0.4, 0, 1, 1) 0.15s;
width: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen {
display: flex;
flex: 0 0 auto;
justify-content: space-between;
width: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen input {
font-family: Sans-serif;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container {
display: flex;
flex-grow: 1;
position: relative;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container .tinymce-mobile-input-container-x {
-ms-grid-row-align: center;
align-self: center;
background: inherit;
border: none;
border-radius: 50%;
color: #888;
font-size: 0.6em;
font-weight: bold;
height: 100%;
padding-right: 2px;
position: absolute;
right: 0;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container.tinymce-mobile-input-container-empty .tinymce-mobile-input-container-x {
display: none;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next {
align-items: center;
display: flex;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous::before,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next::before {
align-items: center;
display: flex;
font-weight: bold;
height: 100%;
padding-left: 0.5em;
padding-right: 0.5em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous.tinymce-mobile-toolbar-navigation-disabled::before,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next.tinymce-mobile-toolbar-navigation-disabled::before {
visibility: hidden;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item {
color: #cccccc;
font-size: 10px;
line-height: 10px;
margin: 0 2px;
padding-top: 3px;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item.tinymce-mobile-dot-active {
color: #d4dbd7;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-font::before,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-heading::before {
margin-left: 0.5em;
margin-right: 0.9em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-font::before,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-heading::before {
margin-left: 0.9em;
margin-right: 0.5em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider {
display: flex;
flex: 1;
margin-left: 0;
margin-right: 0;
padding: 0.28em 0;
position: relative;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container {
align-items: center;
display: flex;
flex-grow: 1;
height: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container .tinymce-mobile-slider-size-line {
background: #cccccc;
display: flex;
flex: 1;
height: 0.2em;
margin-bottom: 0.3em;
margin-top: 0.3em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container {
padding-left: 2em;
padding-right: 2em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container {
align-items: center;
display: flex;
flex-grow: 1;
height: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container .tinymce-mobile-slider-gradient {
background: linear-gradient(to right, hsl(0, 100%, 50%) 0%, hsl(60, 100%, 50%) 17%, hsl(120, 100%, 50%) 33%, hsl(180, 100%, 50%) 50%, hsl(240, 100%, 50%) 67%, hsl(300, 100%, 50%) 83%, hsl(0, 100%, 50%) 100%);
display: flex;
flex: 1;
height: 0.2em;
margin-bottom: 0.3em;
margin-top: 0.3em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-black {
/* Not part of theming */
background: black;
height: 0.2em;
margin-bottom: 0.3em;
margin-top: 0.3em;
width: 1.2em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-white {
/* Not part of theming */
background: white;
height: 0.2em;
margin-bottom: 0.3em;
margin-top: 0.3em;
width: 1.2em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb {
/* vertically centering trick (margin: auto, top: 0, bottom: 0). On iOS and Safari, if you leave
* out these values, then it shows the thumb at the top of the spectrum. This is probably because it is
* absolutely positioned with only a left value, and not a top. Note, on Chrome it seems to be fine without
* this approach.
*/
align-items: center;
background-clip: padding-box;
background-color: #455a64;
border: 0.5em solid rgba(136, 136, 136, 0);
border-radius: 3em;
bottom: 0;
color: #fff;
display: flex;
height: 0.5em;
justify-content: center;
left: -10px;
margin: auto;
position: absolute;
top: 0;
transition: border 120ms cubic-bezier(0.39, 0.58, 0.57, 1);
width: 0.5em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb.tinymce-mobile-thumb-active {
border: 0.5em solid rgba(136, 136, 136, 0.39);
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper,
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group > div {
align-items: center;
display: flex;
height: 100%;
flex: 1;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper {
flex-direction: column;
justify-content: center;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item {
align-items: center;
display: flex;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item:not(.tinymce-mobile-serialised-dialog) {
height: 100%;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-container {
display: flex;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input {
background: #ffffff;
border: none;
border-radius: 0;
color: #455a64;
flex-grow: 1;
font-size: 0.85em;
padding-bottom: 0.1em;
padding-left: 5px;
padding-top: 0.1em;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::-webkit-input-placeholder {
/* WebKit, Blink, Edge */
color: #888;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input:-ms-input-placeholder {
/* WebKit, Blink, Edge */
color: #888;
}
.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::placeholder {
/* WebKit, Blink, Edge */
color: #888;
}
/* dropup */
.tinymce-mobile-dropup {
background: white;
display: flex;
overflow: hidden;
width: 100%;
}
.tinymce-mobile-dropup.tinymce-mobile-dropup-shrinking {
transition: height 0.3s ease-out;
}
.tinymce-mobile-dropup.tinymce-mobile-dropup-growing {
transition: height 0.3s ease-in;
}
.tinymce-mobile-dropup.tinymce-mobile-dropup-closed {
flex-grow: 0;
}
.tinymce-mobile-dropup.tinymce-mobile-dropup-open:not(.tinymce-mobile-dropup-growing) {
flex-grow: 1;
}
/* TODO min-height for device size and orientation */
.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) {
min-height: 200px;
}
@media only screen and (orientation: landscape) {
.tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) {
min-height: 200px;
}
}
@media only screen and (min-device-width : 320px) and (max-device-width : 568px) and (orientation : landscape) {
.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) {
min-height: 150px;
}
}
/* styles menu */
.tinymce-mobile-styles-menu {
font-family: sans-serif;
outline: 4px solid black;
overflow: hidden;
position: relative;
width: 100%;
}
.tinymce-mobile-styles-menu [role="menu"] {
display: flex;
flex-direction: column;
height: 100%;
position: absolute;
width: 100%;
}
.tinymce-mobile-styles-menu [role="menu"].transitioning {
transition: transform 0.5s ease-in-out;
}
.tinymce-mobile-styles-menu .tinymce-mobile-styles-item {
border-bottom: 1px solid #ddd;
color: #455a64;
cursor: pointer;
display: flex;
padding: 1em 1em;
position: relative;
}
.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser .tinymce-mobile-styles-collapse-icon::before {
color: #455a64;
content: "\e314";
font-family: 'tinymce-mobile', sans-serif;
}
.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-styles-item-is-menu::after {
color: #455a64;
content: "\e315";
font-family: 'tinymce-mobile', sans-serif;
padding-left: 1em;
padding-right: 1em;
position: absolute;
right: 0;
}
.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-format-matches::after {
font-family: 'tinymce-mobile', sans-serif;
padding-left: 1em;
padding-right: 1em;
position: absolute;
right: 0;
}
.tinymce-mobile-styles-menu .tinymce-mobile-styles-separator,
.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser {
align-items: center;
background: #fff;
border-top: #455a64;
color: #455a64;
display: flex;
min-height: 2.5em;
padding-left: 1em;
padding-right: 1em;
}
.tinymce-mobile-styles-menu [data-transitioning-destination="before"][data-transitioning-state],
.tinymce-mobile-styles-menu [data-transitioning-state="before"] {
transform: translate(-100%);
}
.tinymce-mobile-styles-menu [data-transitioning-destination="current"][data-transitioning-state],
.tinymce-mobile-styles-menu [data-transitioning-state="current"] {
transform: translate(0%);
}
.tinymce-mobile-styles-menu [data-transitioning-destination="after"][data-transitioning-state],
.tinymce-mobile-styles-menu [data-transitioning-state="after"] {
transform: translate(100%);
}
@font-face {
font-family: 'tinymce-mobile';
font-style: normal;
font-weight: normal;
src: url('fonts/tinymce-mobile.woff?8x92w3') format('woff');
}
@media (min-device-width: 700px) {
.tinymce-mobile-outer-container,
.tinymce-mobile-outer-container input {
font-size: 25px;
}
}
@media (max-device-width: 700px) {
.tinymce-mobile-outer-container,
.tinymce-mobile-outer-container input {
font-size: 18px;
}
}
.tinymce-mobile-icon {
font-family: 'tinymce-mobile', sans-serif;
}
.mixin-flex-and-centre {
align-items: center;
display: flex;
justify-content: center;
}
.mixin-flex-bar {
align-items: center;
display: flex;
height: 100%;
}
.tinymce-mobile-outer-container .tinymce-mobile-editor-socket iframe {
background-color: #fff;
width: 100%;
}
.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon {
/* Note, on the iPod touch in landscape, this isn't visible when the navbar appears */
background-color: #207ab7;
border-radius: 50%;
bottom: 1em;
color: white;
font-size: 1em;
height: 2.1em;
position: fixed;
right: 2em;
width: 2.1em;
align-items: center;
display: flex;
justify-content: center;
}
@media only screen and (min-device-width:700px) {
.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon {
font-size: 1.2em;
}
}
.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket {
height: 300px;
overflow: hidden;
}
.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket iframe {
height: 100%;
}
.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-toolstrip {
display: none;
}
/*
Note, that if you don't include this (::-webkit-file-upload-button), the toolbar width gets
increased and the whole body becomes scrollable. It's important!
*/
input[type="file"]::-webkit-file-upload-button {
display: none;
}
@media only screen and (min-device-width : 320px) and (max-device-width : 568px) and (orientation : landscape) {
.tinymce-mobile-ios-container .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon {
bottom: 50%;
}
}

File diff suppressed because one or more lines are too long

98
src/api/common/api.ts Normal file
View File

@ -0,0 +1,98 @@
import { defHttp } from '/@/utils/http/axios';
import { useGlobSetting } from '/@/hooks/setting';
const globSetting = useGlobSetting();
const baseUploadUrl = globSetting.uploadUrl;
enum Api {
positionList = '/sys/position/list',
userList = '/sys/user/list',
roleList = '/sys/role/list',
queryDepartTreeSync = '/sys/sysDepart/queryDepartTreeSync',
queryTreeList = '/sys/sysDepart/queryTreeList',
loadTreeData = '/sys/category/loadTreeData',
loadDictItem = '/sys/category/loadDictItem/',
getDictItems = '/sys/dict/getDictItems/',
getTableList = '/sys/user/queryUserComponentData',
getCategoryData = '/sys/category/loadAllData',
}
/**
*
*/
export const uploadUrl=`${baseUploadUrl}/sys/common/upload`;
/**
*
* @param params
*/
export const getPositionList = (params) => {
return defHttp.get({ url: Api.positionList, params });
};
/**
*
* @param params
*/
export const getUserList = (params) => {
return defHttp.get({ url: Api.userList, params });
};
/**
*
* @param params
*/
export const getRoleList = (params) => {
return defHttp.get({ url: Api.roleList, params });
};
/**
*
*/
export const queryDepartTreeSync = (params?) =>{
return defHttp.get({ url: Api.queryDepartTreeSync, params });
}
/**
*
*/
export const queryTreeList = (params?) =>{
return defHttp.get({ url: Api.queryTreeList, params });
}
/**
*
*/
export const loadTreeData = (params?) =>{
return defHttp.get({ url: Api.loadTreeData, params });
}
/**
* codetext
*/
export const loadDictItem = (params?) =>{
return defHttp.get({ url: Api.loadDictItem, params });
}
/**
* codetext
*/
export const getDictItems = (dictCode) =>{
return defHttp.get({ url: Api.getDictItems+dictCode},{joinTime:false});
}
/**
* modallist
*/
export const getTableList = (params)=>{
return defHttp.get({url:Api.getTableList,params})
}
/**
*
*/
export const loadCategoryData = (params)=>{
return defHttp.get({url:Api.getCategoryData,params})
}
/**
*
*/
export const uploadFile = (params,success)=>{
return defHttp.uploadFile({url:uploadUrl}, params,{success})
}

View File

@ -2,8 +2,9 @@ import { defHttp } from '/@/utils/http/axios';
import { GetAccountInfoModel } from './model/accountModel';
enum Api {
ACCOUNT_INFO = '/account/getAccountInfo',
SESSION_TIMEOUT = '/user/sessionTimeout',
ACCOUNT_INFO = '/mock/account/getAccountInfo',
SESSION_TIMEOUT = '/mock/user/sessionTimeout',
TOKEN_EXPIRED = '/mock/user/tokenExpired',
}
// Get personal center-basic settings
@ -11,3 +12,5 @@ enum Api {
export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO });
export const sessionTimeoutApi = () => defHttp.post<void>({ url: Api.SESSION_TIMEOUT });
export const tokenExpiredApi = () => defHttp.post<void>({ url: Api.TOKEN_EXPIRED });

View File

@ -1,7 +1,7 @@
import { defHttp } from '/@/utils/http/axios';
import { DemoOptionsItem, selectParams } from './model/optionsModel';
enum Api {
OPTIONS_LIST = '/select/getDemoOptions',
OPTIONS_LIST = '/mock/select/getDemoOptions',
}
/**

View File

@ -4,28 +4,26 @@ import {
MenuParams,
RoleParams,
TestPageParams,
UserPageParams,
RolePageParams,
MenuListGetResultModel,
DeptListGetResultModel,
AccountListGetResultModel,
RolePageListGetResultModel,
RoleListGetResultModel,
TestListGetResultModel,
UserListGetResultModel,
TestListGetResultModel
} from './model/systemModel';
import {defHttp} from '/@/utils/http/axios';
enum Api {
AccountList = '/system/getAccountList',
IsAccountExist = '/system/accountExist',
DeptList = '/system/getDeptList',
setRoleStatus = '/system/setRoleStatus',
MenuList = '/system/getMenuList',
RolePageList = '/system/getRoleListByPage',
DemoTableList = '/system/getDemoTableListByPage',
TestPageList = '/system/getTestListByPage',
GetAllRoleList = '/system/getAllRoleList',
AccountList = '/mock/system/getAccountList',
IsAccountExist = '/mock/system/accountExist',
DeptList = '/mock/system/getDeptList',
setRoleStatus = '/mock/system/setRoleStatus',
MenuList = '/mock/system/getMenuList',
RolePageList = '/mock/system/getRoleListByPage',
DemoTableList = '/mock/system/getDemoTableListByPage',
TestPageList = '/mock/system/getTestListByPage',
GetAllRoleList = '/mock/system/getAllRoleList',
}
export const getAccountList = (params: AccountParams) =>
@ -54,29 +52,3 @@ export const getDemoTableListByPage = (params) =>
export const isAccountExist = (account: string) =>
defHttp.post({url: Api.IsAccountExist, params: {account}}, {errorMessageMode: 'none'});
export const isRoleExist = (params) =>
defHttp.get({url: Api.isRoleExist, params},{isTransformResponse:false});
export const getUserListByPage = (params?: UserPageParams) =>
defHttp.get({url: Api.UserList, params});
export const getRolesListByPage = (params?: RolePageParams) =>
defHttp.get<RolePageListGetResultModel>({url: Api.RolesList, params});
export const getAllRolesList = (params?: RoleParams) =>
defHttp.get<RoleListGetResultModel>({url: Api.allRolesList, params});
export const getAllTenantList = (params?: RoleParams) =>
defHttp.get({url: Api.allTenantList, params});
export const getUserRoles = (params) =>
defHttp.get({url: Api.getUserRole, params}, {errorMessageMode: 'none'});
export const getAllPostList = (params) => {
return new Promise((resolve, reject) => {
defHttp.get({url: Api.allPostList, params}).then(res => {
resolve(res.records)
});
})
}

View File

@ -2,7 +2,7 @@ import { defHttp } from '/@/utils/http/axios';
import { DemoParams, DemoListGetResultModel } from './model/tableModel';
enum Api {
DEMO_LIST = '/table/getDemoList',
DEMO_LIST = '/mock/table/getDemoList',
}
/**

View File

@ -1,7 +1,7 @@
import { defHttp } from '/@/utils/http/axios';
enum Api {
TREE_OPTIONS_LIST = '/tree/getDemoOptions',
TREE_OPTIONS_LIST = '/mock/tree/getDemoOptions',
}
/**

View File

@ -10,13 +10,13 @@ enum Api {
*/
export const getMenuList = () => {
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
//为了兼容mock和接口数据
defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList }).then(res=>{
if(Array.isArray(res)){
resolve(res)
}else{
resolve(res.menu)
resolve(res['menu'])
}
});
})

View File

@ -6,6 +6,11 @@ export interface LoginParams {
password: string;
}
export interface ThirdLoginParams {
token: string;
thirdType: string;
}
export interface RoleInfo {
roleName: string;
value: string;
@ -30,11 +35,15 @@ export interface GetUserInfoModel {
// 用户名
username: string;
// 真实名字
realName: string;
realname: string;
// 头像
avatar: string;
// 介绍
desc?: string;
// 用户信息
userInfo?: any;
// 缓存字典项
sysAllDictItems?: any;
}
/**

View File

@ -20,3 +20,18 @@ export function uploadApi(
params
);
}
/**
* @description: Upload interface
*/
export function uploadImg(
params: UploadFileParams,
onUploadProgress: (progressEvent: ProgressEvent) => void
) {
return defHttp.uploadFile<UploadApiResult>(
{
url: `${uploadUrl}/sys/common/upload`,
onUploadProgress,
},
params, {isReturnResponse:true}
);
}

View File

@ -11,6 +11,10 @@ enum Api {
phoneLogin = '/sys/phoneLogin',
Logout = '/sys/logout',
GetUserInfo = '/sys/user/getUserInfo',
// 获取系统权限
// 1、查询用户拥有的按钮/表单访问权限
// 2、所有权限
// 3、系统安全模式
GetPermCode = '/sys/permission/getPermCode',
//新加的获取图形验证码的接口
getInputCode = '/sys/randomImage',
@ -20,10 +24,20 @@ enum Api {
registerApi = '/sys/user/register',
//校验用户接口
checkOnlyUser = '/sys/user/checkOnlyUser',
//SSO登录校验
validateCasLogin = '/sys/cas/client/validateLogin',
//校验手机号
phoneVerify = '/sys/user/phoneVerification',
//修改密码
passwordChange = '/sys/user/passwordChange',
//第三方登录
thirdLogin = '/sys/thirdLogin/getLoginUser',
//第三方登录
getThirdCaptcha = '/sys/thirdSms',
//获取二维码信息
getLoginQrcode = '/sys/getLoginQrcode',
//监控二维码扫描状态
getQrcodeToken = '/sys/getQrcodeToken',
}
/**
@ -60,11 +74,11 @@ export function phoneLoginApi(params: LoginParams, mode: ErrorMessageMode = 'mod
* @description: getUserInfo
*/
export function getUserInfo() {
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo });
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' });
}
export function getPermCode() {
return defHttp.get<string[]>({ url: Api.GetPermCode });
return defHttp.get({ url: Api.GetPermCode });
}
export function doLogout() {
@ -80,7 +94,7 @@ export function getCodeInfo(currdatetime) {
*/
export function getCaptcha(params) {
return new Promise((resolve, reject) => {
defHttp.post({url: Api.getCaptcha,params},{isTransformResponse: false}).then(res=>{
defHttp.post({url:Api.getCaptcha,params},{isTransformResponse: false}).then(res=>{
console.log(res)
if(res.success){
resolve(true)
@ -117,3 +131,56 @@ export const phoneVerify = (params) =>
*/
export const passwordChange = (params) =>
defHttp.get({url: Api.passwordChange, params},{isTransformResponse:false});
/**
* @description:
*/
export function thirdLogin(params, mode: ErrorMessageMode = 'modal') {
return defHttp.get<LoginResultModel>(
{
url: `${Api.thirdLogin}/${params.token}/${params.thirdType}`,
},
{
errorMessageMode: mode,
}
);
}
/**
* @description:
*/
export function setThirdCaptcha(params) {
return new Promise((resolve, reject) => {
defHttp.post({url:Api.getThirdCaptcha,params},{isTransformResponse: false}).then(res=>{
console.log(res)
if(res.success){
resolve(true)
}else{
createErrorModal({ title: '错误提示', content: res.message||'未知问题' });
reject()
}
});
})
}
/**
*
*/
export function getLoginQrcode() {
let url = Api.getLoginQrcode
return defHttp.get({ url: url });
}
/**
*
*/
export function getQrcodeToken(params) {
let url = Api.getQrcodeToken
return defHttp.get({ url: url,params});
}
/**
* SSO
*/
export async function validateCasLogin(params) {
let url = Api.validateCasLogin
return defHttp.get({ url: url,params});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/assets/images/duban.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
src/assets/images/guaz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
src/assets/images/pdf4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -87,6 +87,7 @@
font-size: 16px;
font-weight: 700;
transition: all 0.5s;
line-height: normal;
}
}
</style>

View File

@ -1,9 +1,11 @@
import { withInstall } from '/@/utils';
import type { ExtractPropTypes } from 'vue';
import button from './src/BasicButton.vue';
import uploadButton from './src/UploadButton.vue';
import popConfirmButton from './src/PopConfirmButton.vue';
import { buttonProps } from './src/props';
export const Button = withInstall(button);
export const UploadButton = withInstall(uploadButton);
export const PopConfirmButton = withInstall(popConfirmButton);
export declare type ButtonProps = Partial<ExtractPropTypes<typeof buttonProps>>;

View File

@ -21,7 +21,6 @@
import Icon from '/@/components/Icon/src/Icon.vue';
import { buttonProps } from './props';
import { useAttrs } from '/@/hooks/core/useAttrs';
const props = defineProps(buttonProps);
// get component class
const attrs = useAttrs({ excludeDefaultKeys: false });

View File

@ -0,0 +1,41 @@
<template>
<a-upload name="file" :showUploadList="false" :customRequest="(file)=>onClick(file)">
<Button :type="type" :class="getButtonClass" >
<template #default="data">
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
<slot v-bind="data || {}"></slot>
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
</template>
</Button>
</a-upload>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'JUploadButton',
inheritAttrs: false,
});
</script>
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { Button } from 'ant-design-vue';
import Icon from '/@/components/Icon/src/Icon.vue';
import { buttonProps } from './props';
import { useAttrs } from '/@/hooks/core/useAttrs';
const props = defineProps(buttonProps);
// get component class
const attrs = useAttrs({ excludeDefaultKeys: false });
const getButtonClass = computed(() => {
const { color, disabled } = props;
return [
{
[`ant-btn-${color}`]: !!color,
[`is-disabled`]: disabled,
},
];
});
// get inherit binding value
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
</script>

View File

@ -10,10 +10,12 @@ export const buttonProps = {
* Text after icon.
*/
postIcon: { type: String },
type: { type: String },
/**
* preIcon and postIcon icon size.
* @default: 14
*/
iconSize: { type: Number, default: 14 },
isUpload:{type:Boolean,default:false},
onClick: { type: Function as PropType<(...args) => any>, default: null },
};

View File

@ -0,0 +1,4 @@
import { withInstall } from '/@/utils';
import cardList from './src/CardList.vue';
export const CardList = withInstall(cardList);

View File

@ -0,0 +1,178 @@
<template>
<div class="p-2">
<div class="bg-white mb-2 p-4">
<BasicForm @register="registerForm" />
</div>
{{ sliderProp.width }}
<div class="bg-white p-2">
<List
:grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }"
:data-source="data"
:pagination="paginationProp"
>
<template #header>
<div class="flex justify-end space-x-2"
><slot name="header"></slot>
<Tooltip>
<template #title>
<div class="w-50">每行显示数量</div
><Slider
id="slider"
v-bind="sliderProp"
v-model:value="grid"
@change="sliderChange"
/></template>
<Button><TableOutlined /></Button>
</Tooltip>
<Tooltip @click="fetch">
<template #title>刷新</template>
<Button><RedoOutlined /></Button>
</Tooltip>
</div>
</template>
<template #renderItem="{ item }">
<ListItem>
<Card>
<template #title></template>
<template #cover>
<div :class="height">
<Image :src="item.imgs[0]" />
</div>
</template>
<template class="ant-card-actions" #actions>
<!-- <SettingOutlined key="setting" />-->
<EditOutlined key="edit" />
<Dropdown
:trigger="['hover']"
:dropMenuList="[
{
text: '删除',
event: '1',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, item.id),
},
},
]"
popconfirm
>
<EllipsisOutlined key="ellipsis" />
</Dropdown>
</template>
<CardMeta>
<template #title>
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
</template>
<template #avatar>
<Avatar :src="item.avatar" />
</template>
<template #description>{{ item.time }}</template>
</CardMeta>
</Card>
</ListItem>
</template>
</List>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from 'vue';
import {
EditOutlined,
EllipsisOutlined,
RedoOutlined,
TableOutlined,
} from '@ant-design/icons-vue';
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
import { Dropdown } from '/@/components/Dropdown';
import { BasicForm, useForm } from '/@/components/Form';
import { propTypes } from '/@/utils/propTypes';
import { Button } from '/@/components/Button';
import { isFunction } from '/@/utils/is';
import { useSlider, grid } from './data';
const ListItem = List.Item;
const CardMeta = Card.Meta;
const TypographyText = Typography.Text;
// slider
const sliderProp = computed(() => useSlider(4));
//
const props = defineProps({
// API
params: propTypes.object.def({}),
//api
api: propTypes.func,
});
//
const emit = defineEmits(['getMethod', 'delete']);
//
const data = ref([]);
//
// cover
//pageSize
const height = computed(() => {
return `h-${120 - grid.value * 6}`;
});
//
const [registerForm, { validate }] = useForm({
schemas: [{ field: 'type', component: 'Input', label: '类型' }],
labelWidth: 80,
baseColProps: { span: 6 },
actionColOptions: { span: 24 },
autoSubmitOnEnter: true,
submitFunc: handleSubmit,
});
//
async function handleSubmit() {
const data = await validate();
await fetch(data);
}
function sliderChange(n) {
pageSize.value = n * 4;
fetch();
}
//
onMounted(() => {
fetch();
emit('getMethod', fetch);
});
async function fetch(p = {}) {
const { api, params } = props;
if (api && isFunction(api)) {
const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p });
data.value = res.items;
total.value = res.total;
}
}
//
const page = ref(1);
const pageSize = ref(36);
const total = ref(0);
const paginationProp = ref({
showSizeChanger: false,
showQuickJumper: true,
pageSize,
current: page,
total,
showTotal: (total) => `${total}`,
onChange: pageChange,
onShowSizeChange: pageSizeChange,
});
function pageChange(p, pz) {
page.value = p;
pageSize.value = pz;
fetch();
}
function pageSizeChange(current, size) {
pageSize.value = size;
fetch();
}
async function handleDelete(id) {
emit('delete', id);
}
</script>

View File

@ -0,0 +1,25 @@
import { ref } from 'vue';
//每行个数
export const grid = ref(12);
// slider属性
export const useSlider = (min = 6, max = 12) => {
// 每行显示个数滑动条
const getMarks = () => {
const l = {};
for (let i = min; i < max + 1; i++) {
l[i] = {
style: {
color: '#fff',
},
label: i,
};
}
return l;
};
return {
min,
max,
marks: getMarks(),
step: 1,
};
};

View File

@ -0,0 +1,5 @@
export enum MODE {
JSON = 'application/json',
HTML = 'htmlmixed',
JS = 'javascript',
}

View File

@ -186,7 +186,7 @@
try {
setModalProps({ confirmLoading: true });
const result = await uploadApi({ name: 'file', file: blob, filename });
emit('uploadSuccess', { source: previewSource.value, data: result.data });
emit('uploadSuccess', { source: previewSource.value, data: result.data || result.message });
closeModal();
} finally {
setModalProps({ confirmLoading: false });

View File

@ -91,9 +91,9 @@
}
);
function handleUploadSuccess({ source }) {
function handleUploadSuccess({ source,data }) {
sourceValue.value = source;
emit('change', source);
emit('change', source, data);
createMessage.success(t('component.cropper.uploadSuccess'));
}

View File

@ -1,19 +1,19 @@
<template>
<Dropdown :trigger="trigger" v-bind="$attrs">
<a-dropdown :trigger="trigger" v-bind="$attrs">
<span>
<slot></slot>
</span>
<template #overlay>
<Menu :selectedKeys="selectedKeys">
<a-menu :selectedKeys="selectedKeys">
<template v-for="item in dropMenuList" :key="`${item.event}`">
<MenuItem
v-bind="getAttr(item.event)"
@click="handleClickMenu(item)"
:disabled="item.disabled"
<a-menu-item
v-bind="getAttr(item.event)"
@click="handleClickMenu(item)"
:disabled="item.disabled"
>
<Popconfirm
v-if="popconfirm && item.popConfirm"
v-bind="getPopConfirmAttrs(item.popConfirm)"
<a-popconfirm
v-if="popconfirm && item.popConfirm"
v-bind="getPopConfirmAttrs(item.popConfirm)"
>
<template #icon v-if="item.popConfirm.icon">
<Icon :icon="item.popConfirm.icon" />
@ -22,86 +22,75 @@
<Icon :icon="item.icon" v-if="item.icon" />
<span class="ml-1">{{ item.text }}</span>
</div>
</Popconfirm>
</a-popconfirm>
<template v-else>
<Icon :icon="item.icon" v-if="item.icon" />
<span class="ml-1">{{ item.text }}</span>
</template>
</MenuItem>
<MenuDivider v-if="item.divider" :key="`d-${item.event}`" />
</a-menu-item>
<a-menu-divider v-if="item.divider" :key="`d-${item.event}`" />
</template>
</Menu>
</a-menu>
</template>
</Dropdown>
</a-dropdown>
</template>
<script lang="ts">
<script lang="ts" setup>
import { computed, PropType } from 'vue';
import type { DropMenu } from './typing';
import { defineComponent } from 'vue';
import { Dropdown, Menu, Popconfirm } from 'ant-design-vue';
import { Icon } from '/@/components/Icon';
import { omit } from 'lodash-es';
import { isFunction } from '/@/utils/is';
export default defineComponent({
name: 'BasicDropdown',
components: {
Dropdown,
Menu,
MenuItem: Menu.Item,
MenuDivider: Menu.Divider,
Icon,
Popconfirm,
},
props: {
popconfirm: Boolean,
/**
* the trigger mode which executes the drop-down action
* @default ['hover']
* @type string[]
*/
trigger: {
type: [Array] as PropType<('contextmenu' | 'click' | 'hover')[]>,
default: () => {
return ['contextmenu'];
},
},
dropMenuList: {
type: Array as PropType<(DropMenu & Recordable)[]>,
default: () => [],
},
selectedKeys: {
type: Array as PropType<string[]>,
default: () => [],
const ADropdown = Dropdown;
const AMenu = Menu;
const AMenuItem = Menu.Item;
const AMenuDivider = Menu.Divider;
const APopconfirm = Popconfirm;
const props = defineProps({
popconfirm: Boolean,
/**
* the trigger mode which executes the drop-down action
* @default ['hover']
* @type string[]
*/
trigger: {
type: [Array] as PropType<('contextmenu' | 'click' | 'hover')[]>,
default: () => {
return ['contextmenu'];
},
},
emits: ['menuEvent'],
setup(props, { emit }) {
function handleClickMenu(item: DropMenu) {
const { event } = item;
const menu = props.dropMenuList.find((item) => `${item.event}` === `${event}`);
emit('menuEvent', menu);
item.onClick?.();
}
const getPopConfirmAttrs = computed(() => {
return (attrs) => {
const originAttrs = omit(attrs, ['confirm', 'cancel', 'icon']);
if (!attrs.onConfirm && attrs.confirm && isFunction(attrs.confirm))
originAttrs['onConfirm'] = attrs.confirm;
if (!attrs.onCancel && attrs.cancel && isFunction(attrs.cancel))
originAttrs['onCancel'] = attrs.cancel;
return originAttrs;
};
});
return {
handleClickMenu,
getPopConfirmAttrs,
getAttr: (key: string | number) => ({ key }),
};
dropMenuList: {
type: Array as PropType<(DropMenu & Recordable)[]>,
default: () => [],
},
selectedKeys: {
type: Array as PropType<string[]>,
default: () => [],
},
});
const emit = defineEmits(['menuEvent']);
function handleClickMenu(item: DropMenu) {
const { event } = item;
const menu = props.dropMenuList.find((item) => `${item.event}` === `${event}`);
emit('menuEvent', menu);
item.onClick?.();
}
const getPopConfirmAttrs = computed(() => {
return (attrs) => {
const originAttrs = omit(attrs, ['confirm', 'cancel', 'icon']);
if (!attrs.onConfirm && attrs.confirm && isFunction(attrs.confirm))
originAttrs['onConfirm'] = attrs.confirm;
if (!attrs.onCancel && attrs.cancel && isFunction(attrs.cancel))
originAttrs['onCancel'] = attrs.cancel;
return originAttrs;
};
});
const getAttr = (key: string | number) => ({ key });
</script>

View File

@ -1,11 +1,11 @@
<template>
<div>
<input
ref="inputRef"
type="file"
v-show="false"
accept=".xlsx, .xls"
@change="handleInputClick"
ref="inputRef"
type="file"
v-show="false"
accept=".xlsx, .xls"
@change="handleInputClick"
/>
<div @click="handleUpload">
<slot></slot>
@ -15,12 +15,25 @@
<script lang="ts">
import { defineComponent, ref, unref } from 'vue';
import XLSX from 'xlsx';
import { dateUtil } from '/@/utils/dateUtil';
import type { ExcelData } from './typing';
export default defineComponent({
name: 'ImportExcel',
props: {
// Date
dateFormat: {
type: String,
},
// +08:00
// https://github.com/SheetJS/sheetjs/issues/1470#issuecomment-501108554
timeZone: {
type: Number,
default: 8,
},
},
emits: ['success', 'error'],
setup(_, { emit }) {
setup(props, { emit }) {
const inputRef = ref<HTMLInputElement | null>(null);
const loadingRef = ref<Boolean>(false);
@ -51,10 +64,28 @@
*/
function getExcelData(workbook: XLSX.WorkBook) {
const excelData: ExcelData[] = [];
const { dateFormat, timeZone } = props;
for (const sheetName of workbook.SheetNames) {
const worksheet = workbook.Sheets[sheetName];
const header: string[] = getHeaderRow(worksheet);
const results = XLSX.utils.sheet_to_json(worksheet);
let results = XLSX.utils.sheet_to_json(worksheet, {
raw: true,
dateNF: dateFormat, //Not worked
}) as object[];
results = results.map((row: object) => {
for (let field in row) {
if (row[field] instanceof Date) {
if (timeZone === 8) {
row[field].setSeconds(row[field].getSeconds() + 43);
}
if (dateFormat) {
row[field] = dateUtil(row[field]).format(dateFormat);
}
}
}
return row;
});
excelData.push({
header,
results,
@ -76,7 +107,7 @@
reader.onload = async (e) => {
try {
const data = e.target && e.target.result;
const workbook = XLSX.read(data, { type: 'array' });
const workbook = XLSX.read(data, { type: 'array', cellDates: true });
// console.log(workbook);
/* DO SOMETHING WITH workbook HERE */
const excelData = getExcelData(workbook);

View File

@ -1,4 +0,0 @@
import { withInstall } from '/@/utils';
import flowChart from './src/FlowChart.vue';
export const FlowChart = withInstall(flowChart);

View File

@ -1,158 +0,0 @@
<template>
<div class="h-full" :class="prefixCls">
<FlowChartToolbar :prefixCls="prefixCls" v-if="toolbar" @view-data="handlePreview" />
<div ref="lfElRef" class="h-full"></div>
<BasicModal @register="register" title="流程数据" width="50%">
<JsonPreview :data="graphData" />
</BasicModal>
</div>
</template>
<script lang="ts">
import type { Ref } from 'vue';
import type { Definition } from '@logicflow/core';
import { defineComponent, ref, onMounted, unref, nextTick, computed, watch } from 'vue';
import FlowChartToolbar from './FlowChartToolbar.vue';
import LogicFlow from '@logicflow/core';
import { Snapshot, BpmnElement, Menu, DndPanel, SelectionSelect } from '@logicflow/extension';
import { useDesign } from '/@/hooks/web/useDesign';
import { useAppStore } from '/@/store/modules/app';
import { createFlowChartContext } from './useFlowContext';
import { toLogicFlowData } from './adpterForTurbo';
import { useModal, BasicModal } from '/@/components/Modal';
import { JsonPreview } from '/@/components/CodeEditor';
import { configDefaultDndPanel } from './config';
import '@logicflow/core/dist/style/index.css';
import '@logicflow/extension/lib/style/index.css';
export default defineComponent({
name: 'FlowChart',
components: { BasicModal, FlowChartToolbar, JsonPreview },
props: {
flowOptions: {
type: Object as PropType<Definition>,
default: () => ({}),
},
data: {
type: Object as PropType<any>,
default: () => ({}),
},
toolbar: {
type: Boolean,
default: true,
},
patternItems: {
type: Array,
},
},
setup(props) {
const lfElRef = ref(null);
const graphData = ref({});
const lfInstance = ref(null) as Ref<LogicFlow | null>;
const { prefixCls } = useDesign('flow-chart');
const appStore = useAppStore();
const [register, { openModal }] = useModal();
createFlowChartContext({
logicFlow: lfInstance as unknown as LogicFlow,
});
const getFlowOptions = computed(() => {
const { flowOptions } = props;
const defaultOptions: Partial<Definition> = {
grid: true,
background: {
color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515',
},
keyboard: {
enabled: true,
},
...flowOptions,
};
return defaultOptions as Definition;
});
watch(
() => props.data,
() => {
onRender();
}
);
// TODO
// watch(
// () => appStore.getDarkMode,
// () => {
// init();
// }
// );
watch(
() => unref(getFlowOptions),
(options) => {
unref(lfInstance)?.updateEditConfig(options);
}
);
// init logicFlow
async function init() {
await nextTick();
const lfEl = unref(lfElRef);
if (!lfEl) {
return;
}
LogicFlow.use(DndPanel);
// Canvas configuration
LogicFlow.use(Snapshot);
// Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo
LogicFlow.use(BpmnElement);
// Start the right-click menu
LogicFlow.use(Menu);
LogicFlow.use(SelectionSelect);
lfInstance.value = new LogicFlow({
...unref(getFlowOptions),
container: lfEl,
});
const lf = unref(lfInstance)!;
lf?.setDefaultEdgeType('line');
onRender();
lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf));
}
async function onRender() {
await nextTick();
const lf = unref(lfInstance);
if (!lf) {
return;
}
const lFData = toLogicFlowData(props.data);
lf.render(lFData);
}
function handlePreview() {
const lf = unref(lfInstance);
if (!lf) {
return;
}
graphData.value = unref(lf).getGraphData();
openModal();
}
onMounted(init);
return {
register,
prefixCls,
lfElRef,
handlePreview,
graphData,
};
},
});
</script>

View File

@ -1,162 +0,0 @@
<template>
<div :class="`${prefixCls}-toolbar`" class="flex items-center px-2 py-1">
<template v-for="item in toolbarItemList" :key="item.type">
<Tooltip placement="bottom" v-bind="item.disabled ? { visible: false } : {}">
<template #title>{{ item.tooltip }}</template>
<span :class="`${prefixCls}-toolbar__icon`" v-if="item.icon" @click="onControl(item)">
<Icon
:icon="item.icon"
:class="item.disabled ? 'cursor-not-allowed disabeld' : 'cursor-pointer'"
/>
</span>
</Tooltip>
<Divider v-if="item.separate" type="vertical" />
</template>
</div>
</template>
<script lang="ts">
import type { ToolbarConfig } from './types';
import { defineComponent, ref, onUnmounted, unref, nextTick, watchEffect } from 'vue';
import { Divider, Tooltip } from 'ant-design-vue';
import { Icon } from '/@/components/Icon';
import { useFlowChartContext } from './useFlowContext';
import { ToolbarTypeEnum } from './enum';
export default defineComponent({
name: 'FlowChartToolbar',
components: { Icon, Divider, Tooltip },
props: {
prefixCls: String,
},
emits: ['view-data'],
setup(_, { emit }) {
const toolbarItemList = ref<ToolbarConfig[]>([
{
type: ToolbarTypeEnum.ZOOM_IN,
icon: 'codicon:zoom-out',
tooltip: '缩小',
},
{
type: ToolbarTypeEnum.ZOOM_OUT,
icon: 'codicon:zoom-in',
tooltip: '放大',
},
{
type: ToolbarTypeEnum.RESET_ZOOM,
icon: 'codicon:screen-normal',
tooltip: '重置比例',
},
{ separate: true },
{
type: ToolbarTypeEnum.UNDO,
icon: 'ion:arrow-undo-outline',
tooltip: '后退',
disabled: true,
},
{
type: ToolbarTypeEnum.REDO,
icon: 'ion:arrow-redo-outline',
tooltip: '前进',
disabled: true,
},
{ separate: true },
{
type: ToolbarTypeEnum.SNAPSHOT,
icon: 'ion:download-outline',
tooltip: '下载',
},
{
type: ToolbarTypeEnum.VIEW_DATA,
icon: 'carbon:document-view',
tooltip: '查看数据',
},
]);
const { logicFlow } = useFlowChartContext();
function onHistoryChange({ data: { undoAble, redoAble } }) {
const itemsList = unref(toolbarItemList);
const undoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.UNDO);
const redoIndex = itemsList.findIndex((item) => item.type === ToolbarTypeEnum.REDO);
if (undoIndex !== -1) {
unref(toolbarItemList)[undoIndex].disabled = !undoAble;
}
if (redoIndex !== -1) {
unref(toolbarItemList)[redoIndex].disabled = !redoAble;
}
}
const onControl = (item) => {
const lf = unref(logicFlow);
if (!lf) {
return;
}
switch (item.type) {
case ToolbarTypeEnum.ZOOM_IN:
lf.zoom();
break;
case ToolbarTypeEnum.ZOOM_OUT:
lf.zoom(true);
break;
case ToolbarTypeEnum.RESET_ZOOM:
lf.resetZoom();
break;
case ToolbarTypeEnum.UNDO:
lf.undo();
break;
case ToolbarTypeEnum.REDO:
lf.redo();
break;
case ToolbarTypeEnum.SNAPSHOT:
lf.getSnapshot();
break;
case ToolbarTypeEnum.VIEW_DATA:
emit('view-data');
break;
}
};
watchEffect(async () => {
if (unref(logicFlow)) {
await nextTick();
unref(logicFlow)?.on('history:change', onHistoryChange);
}
});
onUnmounted(() => {
unref(logicFlow)?.off('history:change', onHistoryChange);
});
return { toolbarItemList, onControl };
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-flow-chart-toolbar';
html[data-theme='dark'] {
.lf-dnd {
background: #080808;
}
}
.@{prefix-cls} {
height: 36px;
background-color: @app-content-background;
border-bottom: 1px solid @border-color-base;
.disabeld {
color: @disabled-color;
}
&__icon {
display: inline-block;
padding: 2px 4px;
margin-right: 10px;
&:hover {
color: @primary-color;
}
}
}
</style>

View File

@ -1,75 +0,0 @@
const TurboType = {
SEQUENCE_FLOW: 1,
START_EVENT: 2,
END_EVENT: 3,
USER_TASK: 4,
SERVICE_TASK: 5,
EXCLUSIVE_GATEWAY: 6,
};
function convertFlowElementToEdge(element) {
const { incoming, outgoing, properties, key } = element;
const { text, startPoint, endPoint, pointsList, logicFlowType } = properties;
const edge = {
id: key,
type: logicFlowType,
sourceNodeId: incoming[0],
targetNodeId: outgoing[0],
text,
startPoint,
endPoint,
pointsList,
properties: {},
};
const excludeProperties = ['startPoint', 'endPoint', 'pointsList', 'text', 'logicFlowType'];
Object.keys(element.properties).forEach((property) => {
if (excludeProperties.indexOf(property) === -1) {
edge.properties[property] = element.properties[property];
}
});
return edge;
}
function convertFlowElementToNode(element) {
const { properties, key } = element;
const { x, y, text, logicFlowType } = properties;
const node = {
id: key,
type: logicFlowType,
x,
y,
text,
properties: {},
};
const excludeProperties = ['x', 'y', 'text', 'logicFlowType'];
Object.keys(element.properties).forEach((property) => {
if (excludeProperties.indexOf(property) === -1) {
node.properties[property] = element.properties[property];
}
});
return node;
}
export function toLogicFlowData(data) {
const lfData: {
// TODO type
nodes: any[];
edges: any[];
} = {
nodes: [],
edges: [],
};
const list = data.flowElementList;
list &&
list.length > 0 &&
list.forEach((element) => {
if (element.type === TurboType.SEQUENCE_FLOW) {
const edge = convertFlowElementToEdge(element);
lfData.edges.push(edge);
} else {
const node = convertFlowElementToNode(element);
lfData.nodes.push(node);
}
});
return lfData;
}

View File

@ -1,96 +0,0 @@
export const nodeList = [
{
text: '开始',
type: 'start',
class: 'node-start',
},
{
text: '矩形',
type: 'rect',
class: 'node-rect',
},
{
type: 'user',
text: '用户',
class: 'node-user',
},
{
type: 'push',
text: '推送',
class: 'node-push',
},
{
type: 'download',
text: '位置',
class: 'node-download',
},
{
type: 'end',
text: '结束',
class: 'node-end',
},
];
export const BpmnNode = [
{
type: 'bpmn:startEvent',
text: '开始',
class: 'bpmn-start',
},
{
type: 'bpmn:endEvent',
text: '结束',
class: 'bpmn-end',
},
{
type: 'bpmn:exclusiveGateway',
text: '网关',
class: 'bpmn-exclusiveGateway',
},
{
type: 'bpmn:userTask',
text: '用户',
class: 'bpmn-user',
},
];
export function configDefaultDndPanel(lf) {
return [
{
text: '选区',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
callback: () => {
lf.updateEditConfig({
stopMoveGraph: true,
});
},
},
{
type: 'circle',
text: '开始',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg==',
},
{
type: 'rect',
text: '用户任务',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==',
cls: 'important-node',
},
{
type: 'rect',
text: '系统任务',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==',
cls: 'import_icon',
},
{
type: 'diamond',
text: '条件判断',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAAHeEJUAAAAABGdBTUEAALGPC/xhBQAAAvVJREFUOBGNVEFrE0EU/mY3bQoiFlOkaUJrQUQoWMGePLX24EH0IIoHKQiCV0G8iE1covgLiqA/QTzVm1JPogc9tIJYFaQtlhQxqYjSpunu+L7JvmUTU3AgmTfvffPNN++9WSA1DO182f6xwILzD5btfAoQmwL5KJEwiQyVbSVZ0IgRyV6PTpIJ81E5ZvqfHQR0HUOBHW4L5Et2kQ6Zf7iAOhTFAA8s0pEP7AXO1uAA52SbqGk6h/6J45LaLhO64ByfcUzM39V7ZiAdS2yCePPEIQYvTUHqM/n7dgQNfBKWPjpF4ISk8q3J4nB11qw6X8l+FsF3EhlkEMfrjIer3wJTLwS2aCNcj4DbGxXTw00JmAuO+Ni6bBxVUCvS5d9aa04+so4pHW5jLTywuXAL7jJ+D06sl82Sgl2JuVBQn498zkc2bGKxULHjCnSMadBKYDYYHAtsby1EQ5lNGrQd4Y3v4Zo0XdGEmDno46yCM9Tk+RiJmUYHS/aXHPNTcjxcbTFna000PFJHIVZ5lFRqRpJWk9/+QtlOUYJj9HG5pVFEU7zqIYDVsw2s+AJaD8wTd2umgSCCyUxgGsS1Y6TBwXQQTFuZaHcd8gAGioE90hlsY+wMcs30RduYtxanjMGal8H5dMW67dmT1JFtYUEe8LiQLRsPZ6IIc7A4J5tqco3T0pnv/4u0kyzrYUq7gASuEyI8VXKvB9Odytv6jS/PNaZBln0nioJG/AVQRZvApOdhjj3Jt8QC8Im09SafwdBdvIpztpxWxpeKCC+EsFdS8DCyuCn2munFpL7ctHKp+Xc5cMybeIyMAN33SPL3ZR9QV1XVwLyzHm6Iv0/yeUuUb7PPlZC4D4HZkeu6dpF4v9j9MreGtMbxMMRLIcjJic9yHi7WQ3yVKzZVWUr5UrViJvn1FfUlwe/KYVfYyWRLSGNu16hR01U9IacajXPei0wx/5BqgInvJN+MMNtNme7ReU9SBbgntovn0kKHpFg7UogZvaZiOue/q1SBo9ktHzQAAAAASUVORK5CYII=',
},
{
type: 'circle',
text: '结束',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC',
},
];
}

View File

@ -1,11 +0,0 @@
export enum ToolbarTypeEnum {
ZOOM_IN = 'zoomIn',
ZOOM_OUT = 'zoomOut',
RESET_ZOOM = 'resetZoom',
UNDO = 'undo',
REDO = 'redo',
SNAPSHOT = 'snapshot',
VIEW_DATA = 'viewData',
}

View File

@ -1,14 +0,0 @@
import { NodeConfig } from '@logicflow/core';
import { ToolbarTypeEnum } from './enum';
export interface NodeItem extends NodeConfig {
icon: string;
}
export interface ToolbarConfig {
type?: string | ToolbarTypeEnum;
tooltip?: string | boolean;
icon?: string;
disabled?: boolean;
separate?: boolean;
}

View File

@ -1,17 +0,0 @@
import type LogicFlow from '@logicflow/core';
import { provide, inject } from 'vue';
const key = Symbol('flow-chart');
type Instance = {
logicFlow: LogicFlow;
};
export function createFlowChartContext(instance: Instance) {
provide(key, instance);
}
export function useFlowChartContext(): Instance {
return inject(key) as Instance;
}

View File

@ -7,8 +7,29 @@ export { useComponentRegister } from './src/hooks/useComponentRegister';
export { useForm } from './src/hooks/useForm';
export { default as ApiSelect } from './src/components/ApiSelect.vue';
export { default as JAreaLinkage } from './src/components/JAreaLinkage.vue';
export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
//Jeecg自定义组件
export { default as JAreaLinkage } from './src/jeecg/components/JAreaLinkage.vue';
export { default as JSelectUser } from './src/jeecg/components/JSelectUser.vue';
export { default as JSelectDept } from './src/jeecg/components/JSelectDept.vue';
export { default as JCodeEditor } from './src/jeecg/components/JCodeEditor.vue';
export { default as JCategorySelect } from './src/jeecg/components/JCategorySelect.vue';
export { default as JSelectMultiple } from './src/jeecg/components/JSelectMultiple.vue';
export { default as JPopup } from './src/jeecg/components/JPopup.vue';
export { default as JAreaSelect } from './src/jeecg/components/JAreaSelect.vue';
export { JEasyCron, JEasyCronInner, JEasyCronModal } from '/@/components/Form/src/jeecg/components/JEasyCron'
export { default as JCheckbox } from './src/jeecg/components/JCheckbox.vue';
export { default as JInput } from './src/jeecg/components/JInput.vue';
export { default as JEllipsis } from './src/jeecg/components/JEllipsis.vue';
export { default as JDictSelectTag } from './src/jeecg/components/JDictSelectTag.vue';
export { default as JTreeSelect } from './src/jeecg/components/JTreeSelect.vue';
export { default as JSearchSelect } from './src/jeecg/components/JSearchSelect.vue';
export { default as JSelectUserByDept } from './src/jeecg/components/JSelectUserByDept.vue';
export { default as JEditor } from './src/jeecg/components/JEditor.vue';
export { default as JImageUpload } from './src/jeecg/components/JImageUpload.vue';
// Jeecg自定义校验
export { JCronValidator } from '/@/components/Form/src/jeecg/components/JEasyCron'
export { BasicForm };

View File

@ -1,23 +1,9 @@
<template>
<Form
v-bind="getBindValue"
:class="getFormClass"
ref="formElRef"
:model="formModel"
@keypress.enter="handleEnterPress"
>
<Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel" @keypress.enter="handleEnterPress">
<Row v-bind="getRow">
<slot name="formHeader"></slot>
<template v-for="schema in getSchema" :key="schema.field">
<FormItem
:tableAction="tableAction"
:formActionType="formActionType"
:schema="schema"
:formProps="getProps"
:allDefaultValues="defaultValueRef"
:formModel="formModel"
:setFormModel="setFormModel"
>
<FormItem :tableAction="tableAction" :formActionType="formActionType" :schema="schema" :formProps="getProps" :allDefaultValues="defaultValueRef" :formModel="formModel" :setFormModel="setFormModel">
<template #[item]="data" v-for="item in Object.keys($slots)">
<slot :name="item" v-bind="data || {}"></slot>
</template>
@ -25,10 +11,7 @@
</template>
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
<template
#[item]="data"
v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']"
>
<template #[item]="data" v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</FormAction>
@ -72,8 +55,9 @@
const modalFn = useModalContext();
const advanceState = reactive<AdvanceState>({
isAdvanced: true,
hideAdvanceBtn: false,
//
isAdvanced: false,
hideAdvanceBtn: true,
isLoad: false,
actionSpan: 6,
});

View File

@ -20,15 +20,42 @@ import {
Rate,
Divider,
} from 'ant-design-vue';
import ApiRadioGroup from './components/ApiRadioGroup.vue';
import RadioButtonGroup from './components/RadioButtonGroup.vue';
import ApiSelect from './components/ApiSelect.vue';
import JAreaLinkage from './components/JAreaLinkage.vue';
import ApiTreeSelect from './components/ApiTreeSelect.vue';
import { BasicUpload } from '/@/components/Upload';
import { StrengthMeter } from '/@/components/StrengthMeter';
import { IconPicker } from '/@/components/Icon';
import { CountdownInput } from '/@/components/CountDown';
//自定义组件
import JAreaLinkage from './jeecg/components/JAreaLinkage.vue';
import JSelectUser from './jeecg/components/JSelectUser.vue';
import JSelectPosition from './jeecg/components/JSelectPosition.vue';
import JSelectRole from './jeecg/components/JSelectRole.vue';
import JImageUpload from './jeecg/components/JImageUpload.vue';
import JDictSelectTag from './jeecg/components/JDictSelectTag.vue';
import JSelectDept from './jeecg/components/JSelectDept.vue';
import JAreaSelect from './jeecg/components/JAreaSelect.vue';
import JEditor from './jeecg/components/JEditor.vue';
import JMarkdownEditor from './jeecg/components/JMarkdownEditor.vue';
import JSelectInput from './jeecg/components/JSelectInput.vue';
import JCodeEditor from './jeecg/components/JCodeEditor.vue';
import JCategorySelect from './jeecg/components/JCategorySelect.vue';
import JSelectMultiple from './jeecg/components/JSelectMultiple.vue';
import JPopup from './jeecg/components/JPopup.vue';
import JSwitch from './jeecg/components/JSwitch.vue';
import JTreeDict from './jeecg/components/JTreeDict.vue';
import JInputPop from './jeecg/components/JInputPop.vue';
import { JEasyCron } from './jeecg/components/JEasyCron'
import JCheckbox from './jeecg/components/JCheckbox.vue';
import JInput from './jeecg/components/JInput.vue';
import JTreeSelect from './jeecg/components/JTreeSelect.vue';
import JEllipsis from './jeecg/components/JEllipsis.vue';
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
import JUpload from './jeecg/components/JUpload/JUpload.vue'
import JSearchSelect from './jeecg/components/JSearchSelect.vue'
import JAddInput from './jeecg/components/JAddInput.vue'
const componentMap = new Map<ComponentType, Component>();
@ -42,9 +69,9 @@ componentMap.set('AutoComplete', AutoComplete);
componentMap.set('Select', Select);
componentMap.set('ApiSelect', ApiSelect);
componentMap.set('JAreaLinkage', JAreaLinkage);
componentMap.set('TreeSelect', TreeSelect);
componentMap.set('ApiTreeSelect', ApiTreeSelect);
componentMap.set('ApiRadioGroup', ApiRadioGroup);
componentMap.set('Switch', Switch);
componentMap.set('RadioButtonGroup', RadioButtonGroup);
componentMap.set('RadioGroup', Radio.Group);
@ -66,6 +93,35 @@ componentMap.set('InputCountDown', CountdownInput);
componentMap.set('Upload', BasicUpload);
componentMap.set('Divider', Divider);
//注册自定义组件
componentMap.set('JAreaLinkage', JAreaLinkage);
componentMap.set('JSelectPosition', JSelectPosition);
componentMap.set('JSelectUser', JSelectUser);
componentMap.set('JSelectRole', JSelectRole);
componentMap.set('JImageUpload', JImageUpload);
componentMap.set('JDictSelectTag', JDictSelectTag);
componentMap.set('JSelectDept', JSelectDept);
componentMap.set('JAreaSelect', JAreaSelect);
componentMap.set('JEditor', JEditor);
componentMap.set('JMarkdownEditor', JMarkdownEditor);
componentMap.set('JSelectInput', JSelectInput);
componentMap.set('JCodeEditor', JCodeEditor);
componentMap.set('JCategorySelect', JCategorySelect);
componentMap.set('JSelectMultiple', JSelectMultiple);
componentMap.set('JPopup', JPopup);
componentMap.set('JSwitch', JSwitch);
componentMap.set('JTreeDict', JTreeDict);
componentMap.set('JInputPop', JInputPop);
componentMap.set('JEasyCron', JEasyCron);
componentMap.set('JCheckbox', JCheckbox);
componentMap.set('JInput', JInput);
componentMap.set('JTreeSelect', JTreeSelect);
componentMap.set('JEllipsis', JEllipsis);
componentMap.set('JSelectUserByDept', JSelectUserByDept);
componentMap.set('JUpload', JUpload);
componentMap.set('JSearchSelect', JSearchSelect);
componentMap.set('JAddInput', JAddInput);
export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component);
}

View File

@ -0,0 +1,130 @@
<!--
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<template>
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid" @change="handleChange">
<template v-for="item in getOptions" :key="`${item.value}`">
<RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled">
{{ item.label }}
</RadioButton>
<Radio v-else :value="item.value" :disabled="item.disabled">
{{ item.label }}
</Radio>
</template>
</RadioGroup>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue';
import { Radio } from 'ant-design-vue';
import { isFunction } from '/@/utils/is';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { propTypes } from '/@/utils/propTypes';
import { get, omit } from 'lodash-es';
import { useI18n } from '/@/hooks/web/useI18n';
type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean };
export default defineComponent({
name: 'ApiRadioGroup',
components: {
RadioGroup: Radio.Group,
RadioButton: Radio.Button,
Radio,
},
props: {
api: {
type: Function as PropType<(arg?: Recordable | string) => Promise<OptionsItem[]>>,
default: null,
},
params: {
type: [Object, String] as PropType<Recordable | string>,
default: () => ({}),
},
value: {
type: [String, Number, Boolean] as PropType<string | number | boolean>,
},
isBtn: {
type: [Boolean] as PropType<boolean>,
default: false,
},
numberToString: propTypes.bool,
resultField: propTypes.string.def(''),
labelField: propTypes.string.def('label'),
valueField: propTypes.string.def('value'),
immediate: propTypes.bool.def(true),
},
emits: ['options-change', 'change'],
setup(props, { emit }) {
const options = ref<OptionsItem[]>([]);
const loading = ref(false);
const isFirstLoad = ref(true);
const emitData = ref<any[]>([]);
const attrs = useAttrs();
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props);
// Processing options value
const getOptions = computed(() => {
const { labelField, valueField, numberToString } = props;
return unref(options).reduce((prev, next: Recordable) => {
if (next) {
const value = next[valueField];
prev.push({
label: next[labelField],
value: numberToString ? `${value}` : value,
...omit(next, [labelField, valueField]),
});
}
return prev;
}, [] as OptionsItem[]);
});
watchEffect(() => {
props.immediate && fetch();
});
watch(
() => props.params,
() => {
!unref(isFirstLoad) && fetch();
},
{ deep: true },
);
async function fetch() {
const api = props.api;
if (!api || !isFunction(api)) return;
options.value = [];
try {
loading.value = true;
const res = await api(props.params);
if (Array.isArray(res)) {
options.value = res;
emitChange();
return;
}
if (props.resultField) {
options.value = get(res, props.resultField) || [];
}
emitChange();
} catch (error) {
console.warn(error);
} finally {
loading.value = false;
}
}
function emitChange() {
emit('options-change', unref(getOptions));
}
function handleChange(_, ...args) {
emitData.value = args;
}
return { state, getOptions, attrs, loading, t, handleChange, props };
},
});
</script>

View File

@ -1,7 +1,7 @@
<template>
<Select
@dropdownVisibleChange="handleFetch"
v-bind="attrs"
v-bind="$attrs"
@change="handleChange"
:options="getOptions"
v-model:value="state"
@ -41,12 +41,7 @@
},
inheritAttrs: false,
props: {
value: propTypes.oneOfType([
propTypes.object,
propTypes.number,
propTypes.string,
propTypes.array,
]),
value: [Array, Object, String, Number],
numberToString: propTypes.bool,
api: {
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
@ -73,18 +68,17 @@
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData);
const getOptions = computed(() => {
const { labelField, valueField, numberToString } = props;
return unref(options).reduce((prev, next: Recordable) => {
if (next) {
const value = next[valueField];
prev.push({
label: next[labelField],
value: numberToString ? `${value}` : value,
...omit(next, [labelField, valueField]),
...omit(next, [labelField, valueField]),
label: next[labelField],
value: numberToString ? `${value}` : value,
});
}
return prev;
@ -123,6 +117,9 @@
console.warn(error);
} finally {
loading.value = false;
//--@updateBy-begin----author:liusq---date:20210914------for:multiplevalue------
unref(attrs).mode == 'multiple' && !Array.isArray(unref(state)) && setState([])
//--@updateBy-end----author:liusq---date:20210914------for:multiplevalue------
}
}

View File

@ -44,7 +44,7 @@
watch(
() => props.params,
() => {
isFirstLoaded.value && fetch();
!unref(isFirstLoaded) && fetch();
},
{ deep: true }
);

View File

@ -2,16 +2,20 @@
<a-col v-bind="actionColOpt" v-if="showActionButtonGroup">
<div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
<FormItem>
<slot name="resetBefore"></slot>
<Button type="default" class="mr-2" v-bind="getResetBtnOptions" @click="resetAction" v-if="showResetButton">
{{ getResetBtnOptions.text }}
</Button>
<slot name="submitBefore"></slot>
<!-- update-begin-author:zyf Date:20211213 for调换按钮前后位置-->
<slot name="submitBefore"></slot>
<Button type="primary" class="mr-2" v-bind="getSubmitBtnOptions" @click="submitAction" v-if="showSubmitButton">
<Icon icon="ant-design:search-outlined"></Icon>
{{ getSubmitBtnOptions.text }}
</Button>
<slot name="resetBefore"></slot>
<Button type="default" class="mr-2" v-bind="getResetBtnOptions" @click="resetAction" v-if="showResetButton">
<Icon icon="ic:baseline-restart-alt"></Icon>
{{ getResetBtnOptions.text }}
</Button>
<!-- update-end-author:zyf Date:20211213 for调换按钮前后位置-->
<slot name="advanceBefore"></slot>
<Button type="link" size="small" @click="toggleAdvanced" v-if="showAdvancedButton && !hideAdvanceBtn">
{{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}

View File

@ -1,19 +1,19 @@
<script lang="tsx">
import type { PropType, Ref } from 'vue';
import type { FormActionType, FormProps } from '../types/form';
import type { FormSchema } from '../types/form';
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
import type { TableActionType } from '/@/components/Table';
import { defineComponent, computed, unref, toRefs } from 'vue';
import { Form, Col, Divider } from 'ant-design-vue';
import { componentMap } from '../componentMap';
import { BasicHelp } from '/@/components/Basic';
import { isBoolean, isFunction, isNull } from '/@/utils/is';
import { getSlot } from '/@/utils/helper/tsxHelper';
import { createPlaceholderMessage, setComponentRuleType } from '../helper';
import { upperFirst, cloneDeep } from 'lodash-es';
import { useItemLabelWidth } from '../hooks/useLabelWidth';
import { useI18n } from '/@/hooks/web/useI18n';
import type {PropType, Ref} from 'vue';
import type {FormActionType, FormProps} from '../types/form';
import type {FormSchema} from '../types/form';
import type {ValidationRule} from 'ant-design-vue/lib/form/Form';
import type {TableActionType} from '/@/components/Table';
import {defineComponent, computed, unref, toRefs} from 'vue';
import {Form, Col, Divider} from 'ant-design-vue';
import {componentMap} from '../componentMap';
import {BasicHelp} from '/@/components/Basic';
import {isBoolean, isFunction, isNull} from '/@/utils/is';
import {getSlot} from '/@/utils/helper/tsxHelper';
import {createPlaceholderMessage, setComponentRuleType} from '../helper';
import {upperFirst, cloneDeep} from 'lodash-es';
import {useItemLabelWidth} from '../hooks/useLabelWidth';
import {useI18n} from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'BasicFormItem',
@ -46,10 +46,10 @@
type: Object as PropType<FormActionType>,
},
},
setup(props, { slots }) {
const { t } = useI18n();
setup(props, {slots}) {
const {t} = useI18n();
const { schema, formProps } = toRefs(props) as {
const {schema, formProps} = toRefs(props) as {
schema: Ref<FormSchema>;
formProps: Ref<FormProps>;
};
@ -57,8 +57,8 @@
const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
const getValues = computed(() => {
const { allDefaultValues, formModel, schema } = props;
const { mergeDynamicData } = props.formProps;
const {allDefaultValues, formModel, schema} = props;
const {mergeDynamicData} = props.formProps;
return {
field: schema.field,
model: formModel,
@ -72,13 +72,13 @@
});
const getComponentsProps = computed(() => {
const { schema, tableAction, formModel, formActionType } = props;
let { componentProps = {} } = schema;
const {schema, tableAction, formModel, formActionType} = props;
let {componentProps = {}} = schema;
if (isFunction(componentProps)) {
componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
componentProps = componentProps({schema, tableAction, formModel, formActionType}) ?? {};
}
if (schema.component === 'Divider') {
componentProps = Object.assign({ type: 'horizontal' }, componentProps, {
componentProps = Object.assign({type: 'horizontal'}, componentProps, {
orientation: 'left',
plain: true,
});
@ -87,9 +87,9 @@
});
const getDisable = computed(() => {
const { disabled: globDisabled } = props.formProps;
const { dynamicDisabled } = props.schema;
const { disabled: itemDisabled = false } = unref(getComponentsProps);
const {disabled: globDisabled} = props.formProps;
const {dynamicDisabled} = props.schema;
const {disabled: itemDisabled = false} = unref(getComponentsProps);
let disabled = !!globDisabled || itemDisabled;
if (isBoolean(dynamicDisabled)) {
disabled = dynamicDisabled;
@ -101,8 +101,8 @@
});
function getShow(): { isShow: boolean; isIfShow: boolean } {
const { show, ifShow } = props.schema;
const { showAdvancedButton } = props.formProps;
const {show, ifShow} = props.schema;
const {showAdvancedButton} = props.formProps;
const itemIsAdvanced = showAdvancedButton
? isBoolean(props.schema.isAdvanced)
? props.schema.isAdvanced
@ -125,7 +125,7 @@
isIfShow = ifShow(unref(getValues));
}
isShow = isShow && itemIsAdvanced;
return { isShow, isIfShow };
return {isShow, isIfShow};
}
function handleRules(): ValidationRule[] {
@ -143,7 +143,7 @@
}
let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps;
const {rulesMessageJoinLabel: globalRulesMessageJoinLabel} = props.formProps;
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
? rulesMessageJoinLabel
@ -179,7 +179,7 @@
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
if ((!rules || rules.length === 0) && getRequired) {
rules = [{ required: getRequired, validator }];
rules = [{required: getRequired, validator}];
}
const requiredRuleIndex: number = rules.findIndex(
@ -188,7 +188,7 @@
if (requiredRuleIndex !== -1) {
const rule = rules[requiredRuleIndex];
const { isShow } = getShow();
const {isShow} = getShow();
if (!isShow) {
rule.required = false;
}
@ -243,7 +243,7 @@
};
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
const { autoSetPlaceHolder, size } = props.formProps;
const {autoSetPlaceHolder, size} = props.formProps;
const propsData: Recordable = {
allowClear: true,
getPopupContainer: (trigger: Element) => trigger.parentNode,
@ -252,14 +252,16 @@
disabled: unref(getDisable),
};
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
// RangePicker place is an array
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
propsData.placeholder =
unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component);
}
propsData.codeField = field;
propsData.formValues = unref(getValues);
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
// RangePicker place
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
//placeholder
propsData.placeholder =
unref(getComponentsProps)?.placeholder ||
createPlaceholderMessage(component) + props.schema.label;
}
propsData.codeField = field;
propsData.formValues = unref(getValues);
const bindValue: Recordable = {
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
@ -275,15 +277,19 @@
return <Comp {...compAttr} />;
}
const compSlot = isFunction(renderComponentContent)
? { ...renderComponentContent(unref(getValues)) }
? {...renderComponentContent(unref(getValues))}
: {
default: () => renderComponentContent,
};
return <Comp {...compAttr}>{compSlot}</Comp>;
}
/**
*渲染Label
* @updateBy:zyf
*/
function renderLabelHelpMessage() {
const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
const {label, helpMessage, helpComponentProps, subLabel} = props.schema;
const renderLabel = subLabel ? (
<span>
{label} <span class="text-secondary">{subLabel}</span>
@ -306,9 +312,9 @@
}
function renderItem() {
const { itemProps, slot, render, field, suffix, component } = props.schema;
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
const { colon } = props.formProps;
const {itemProps, slot, render, field, suffix, component} = props.schema;
const {labelCol, wrapperCol} = unref(itemLabelWidthProp);
const {colon} = props.formProps;
if (component === 'Divider') {
return (
@ -332,7 +338,7 @@
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
class={{'suffix-item': showSuffix}}
{...(itemProps as Recordable)}
label={renderLabelHelpMessage()}
rules={handleRules()}
@ -340,7 +346,7 @@
wrapperCol={wrapperCol}
>
<div style="display:flex">
<div style="flex:1">{getContent()}</div>
<div style="flex:1;">{getContent()}</div>
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>
</Form.Item>
@ -349,14 +355,14 @@
}
return () => {
const { colProps = {}, colSlot, renderColContent, component } = props.schema;
const {colProps = {}, colSlot, renderColContent, component} = props.schema;
if (!componentMap.has(component)) {
return null;
}
const { baseColProps = {} } = props.formProps;
const realColProps = { ...baseColProps, ...colProps };
const { isIfShow, isShow } = getShow();
const {baseColProps = {}} = props.formProps;
const realColProps = {...baseColProps, ...colProps};
const {isIfShow, isShow} = getShow();
const values = unref(getValues);
const getContent = () => {

View File

@ -61,7 +61,7 @@ export default function ({
{ immediate: true }
);
function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) {
function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false, index = 0) {
const width = unref(realWidthRef);
const mdWidth =
@ -84,27 +84,41 @@ export default function ({
itemColSum += xxlWidth;
}
let autoAdvancedCol = (unref(getProps).autoAdvancedCol ?? 3)
if (isLastAction) {
advanceState.hideAdvanceBtn = false;
if (itemColSum <= BASIC_COL_LEN * 2) {
// When less than or equal to 2 lines, the collapse and expand buttons are not displayed
advanceState.hideAdvanceBtn = unref(getSchema).length <= autoAdvancedCol;
// update-begin--author:sunjianlei---date:20211108---for: 注释掉该逻辑使小于等于2行时也显示展开收起按钮
/* if (itemColSum <= BASIC_COL_LEN * 2) {
// 小于等于2行时不显示折叠和展开按钮
advanceState.hideAdvanceBtn = true;
advanceState.isAdvanced = true;
} else if (
} else */
// update-end--author:sunjianlei---date:20211108---for: 注释掉该逻辑使小于等于2行时也显示展开收起按钮
if (
itemColSum > BASIC_COL_LEN * 2 &&
itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)
) {
advanceState.hideAdvanceBtn = false;
// More than 3 lines collapsed by default
// 默认超过 3 行折叠
} else if (!advanceState.isLoad) {
advanceState.isLoad = true;
advanceState.isAdvanced = !advanceState.isAdvanced;
// update-begin--author:sunjianlei---date:20211108---for: 如果总列数大于 autoAdvancedCol就默认折叠
if (unref(getSchema).length > autoAdvancedCol) {
advanceState.hideAdvanceBtn = false
advanceState.isAdvanced = false
}
// update-end--author:sunjianlei---date:20211108---for: 如果总列数大于 autoAdvancedCol就默认折叠
}
return { isAdvanced: advanceState.isAdvanced, itemColSum };
}
if (itemColSum > BASIC_COL_LEN * (unref(getProps).alwaysShowLines || 1)) {
return { isAdvanced: advanceState.isAdvanced, itemColSum };
} else if (!advanceState.isAdvanced && (index + 1) > autoAdvancedCol) {
// 如果当前是收起状态,并且当前列下标 > autoAdvancedCol就隐藏
return { isAdvanced: false, itemColSum }
} else {
// The first line is always displayed
return { isAdvanced: true, itemColSum };
@ -116,7 +130,9 @@ export default function ({
let realItemColSum = 0;
const { baseColProps = {} } = unref(getProps);
for (const schema of unref(getSchema)) {
const schemas = unref(getSchema)
for (let i = 0; i < schemas.length; i++) {
const schema = schemas[i]
const { show, colProps } = schema;
let isShow = true;
@ -139,7 +155,7 @@ export default function ({
if (isShow && (colProps || baseColProps)) {
const { itemColSum: sum, isAdvanced } = getAdvanced(
{ ...baseColProps, ...colProps },
itemColSum
itemColSum, false, i,
);
itemColSum = sum || 0;

View File

@ -1,117 +1,136 @@
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface';
import type { DynamicProps } from '/#/utils';
import { handleRangeValue } from '../utils/formUtils';
import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
import { isProdMode } from '/@/utils/env';
import { error } from '/@/utils/log';
import { getDynamicProps } from '/@/utils';
import { getDynamicProps, getValueType } from '/@/utils';
export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
type Props = Partial<DynamicProps<FormProps>>;
export function useForm(props?: Props): UseFormReturnType {
const formRef = ref<Nullable<FormActionType>>(null);
const loadedRef = ref<Nullable<boolean>>(false);
const formRef = ref<Nullable<FormActionType>>(null);
const loadedRef = ref<Nullable<boolean>>(false);
async function getForm() {
const form = unref(formRef);
if (!form) {
error(
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!'
);
async function getForm() {
const form = unref(formRef);
if (!form) {
error(
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!'
);
}
await nextTick();
return form as FormActionType;
}
await nextTick();
return form as FormActionType;
}
function register(instance: FormActionType) {
isProdMode() &&
onUnmounted(() => {
formRef.value = null;
loadedRef.value = null;
});
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
function register(instance: FormActionType) {
isProdMode() &&
onUnmounted(() => {
formRef.value = null;
loadedRef.value = null;
});
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
formRef.value = instance;
loadedRef.value = true;
formRef.value = instance;
loadedRef.value = true;
watch(
() => props,
() => {
props && instance.setProps(getDynamicProps(props));
},
{
immediate: true,
deep: true,
}
);
}
watch(
() => props,
() => {
props && instance.setProps(getDynamicProps(props));
},
{
immediate: true,
deep: true,
}
);
}
const methods: FormActionType = {
scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
const form = await getForm();
form.scrollToField(name, options);
},
setProps: async (formProps: Partial<FormProps>) => {
const form = await getForm();
form.setProps(formProps);
},
const methods: FormActionType = {
scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
const form = await getForm();
form.scrollToField(name, options);
},
setProps: async (formProps: Partial<FormProps>) => {
const form = await getForm();
form.setProps(formProps);
},
updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm();
form.updateSchema(data);
},
updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm();
form.updateSchema(data);
},
resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm();
form.resetSchema(data);
},
resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm();
form.resetSchema(data);
},
clearValidate: async (name?: string | string[]) => {
const form = await getForm();
form.clearValidate(name);
},
clearValidate: async (name?: string | string[]) => {
const form = await getForm();
form.clearValidate(name);
},
resetFields: async () => {
getForm().then(async (form) => {
await form.resetFields();
});
},
resetFields: async () => {
getForm().then(async (form) => {
await form.resetFields();
});
},
removeSchemaByFiled: async (field: string | string[]) => {
unref(formRef)?.removeSchemaByFiled(field);
},
removeSchemaByFiled: async (field: string | string[]) => {
unref(formRef)?.removeSchemaByFiled(field);
},
// TODO promisify
getFieldsValue: <T>() => {
return unref(formRef)?.getFieldsValue() as T;
},
// TODO promisify
getFieldsValue: <T>() => {
return unref(formRef)?.getFieldsValue() as T;
},
setFieldsValue: async <T>(values: T) => {
const form = await getForm();
form.setFieldsValue<T>(values);
},
setFieldsValue: async <T>(values: T) => {
const form = await getForm();
form.setFieldsValue<T>(values);
},
appendSchemaByField: async (
schema: FormSchema,
prefixField: string | undefined,
first: boolean
) => {
const form = await getForm();
form.appendSchemaByField(schema, prefixField, first);
},
appendSchemaByField: async (
schema: FormSchema,
prefixField: string | undefined,
first: boolean
) => {
const form = await getForm();
form.appendSchemaByField(schema, prefixField, first);
},
submit: async (): Promise<any> => {
const form = await getForm();
return form.submit();
},
submit: async (): Promise<any> => {
const form = await getForm();
return form.submit();
},
/**
*
* @update:
* @updateBy:zyf
* @updateDate:2021-09-02
*/
validate: async (nameList?: NamePath[]): Promise<Recordable> => {
const form = await getForm();
return form.validate(nameList);
let values = form.validate(nameList).then((values) => {
for (let key in values) {
if (values[key] instanceof Array) {
let valueType = getValueType(props, key);
if (valueType === 'string') {
values[key] = values[key].join(',');
}
}
}
//--@updateBy-begin----author:liusq---date:20210916------for:处理区域事件字典信息------
return handleRangeValue(props,values);
//--@updateBy-end----author:liusq---date:20210916------for:处理区域事件字典信息------
});
return values;
},
validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
const form = await getForm();
return form.validateFields(nameList);

View File

@ -3,7 +3,7 @@ import type { FormProps, FormSchema, FormActionType } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw } from 'vue';
import { isArray, isFunction, isObject, isString } from '/@/utils/is';
import { deepMerge } from '/@/utils';
import { deepMerge, getValueType } from '/@/utils';
import { dateItemType, handleInputNumberValue } from '../helper';
import { dateUtil } from '/@/utils/dateUtil';
import { cloneDeep, uniqBy } from 'lodash-es';
@ -240,6 +240,17 @@ export function useFormEvents({
if (!formEl) return;
try {
const values = await validate();
//update-begin---author:zhangdaihao Date:20140212 for[bug号]树机构调整------------
//--updateBy-begin----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
for (let key in values) {
if (values[key] instanceof Array) {
let valueType = getValueType(getProps, key);
if (valueType === 'string') {
values[key] = values[key].join(',');
}
}
}
//--updateBy-end----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
const res = handleFormValues(values);
emit('submit', res);
} catch (error) {

View File

@ -4,6 +4,7 @@ import { unref } from 'vue';
import type { Ref, ComputedRef } from 'vue';
import type { FormProps, FormSchema } from '../types/form';
import { set } from 'lodash-es';
import { handleRangeValue } from '/@/components/Form/src/utils/formUtils';
interface UseFormValuesContext {
defaultValueRef: Ref<any>;
@ -42,33 +43,9 @@ export function useFormValues({
}
set(res, key, value);
}
return handleRangeTimeValue(res);
return handleRangeValue(getProps,res);
}
/**
* @description: Processing time interval parameters
*/
function handleRangeTimeValue(values: Recordable) {
const fieldMapToTime = unref(getProps).fieldMapToTime;
if (!fieldMapToTime || !Array.isArray(fieldMapToTime)) {
return values;
}
for (const [field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD'] of fieldMapToTime) {
if (!field || !startTimeKey || !endTimeKey || !values[field]) {
continue;
}
const [startTime, endTime]: string[] = values[field];
values[startTimeKey] = dateUtil(startTime).format(format);
values[endTimeKey] = dateUtil(endTime).format(format);
Reflect.deleteProperty(values, field);
}
return values;
}
function initDefault() {
const schemas = unref(getSchema);

View File

@ -16,8 +16,14 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
wrapperCol: globWrapperCol,
} = unref(propsRef);
// update-begin--author:sunjianlei---date:20211104---for: 禁用全局 labelWidth不自动设置 textAlign --------
if (disabledLabelWidth) {
return { labelCol, wrapperCol }
}
// update-begin--author:sunjianlei---date:20211104---for: 禁用全局 labelWidth不自动设置 textAlign --------
// If labelWidth is set globally, all items setting
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
if ((!globalLabelWidth && !labelWidth && !globalLabelCol)) {
labelCol.style = {
textAlign: 'left',
};

View File

@ -0,0 +1,119 @@
<template>
<div v-for="(param, index) in dynamicInput.params" :key="index" style="display: flex">
<a-input placeholder="请输入参数key" v-model:value="param.label" style="width: 30%;margin-bottom: 5px" @input="emitChange"/>
<a-input placeholder="请输入参数value" v-model:value="param.value" style="width: 30%;margin: 0 0 5px 5px" @input="emitChange"/>
<MinusCircleOutlined
v-if="dynamicInput.params.length > 1"
class="dynamic-delete-button"
@click="remove(param)"
style="width: 50px"
></MinusCircleOutlined>
</div>
<div>
<a-button type="dashed" style="width: 60%" @click="add">
<PlusOutlined/>
新增
</a-button>
</div>
</template>
<script lang="ts">
import {MinusCircleOutlined, PlusOutlined} from '@ant-design/icons-vue';
import {defineComponent, reactive, ref, UnwrapRef, watchEffect} from 'vue';
import {propTypes} from '/@/utils/propTypes';
import { isEmpty } from '/@/utils/is'
import { tryOnMounted, tryOnUnmounted } from '@vueuse/core';
interface Params {
label: string;
value: string;
}
export default defineComponent({
name: 'JAddInput',
props: {
value: propTypes.string.def('')
},
emits: ['change', 'update:value'],
setup(props, {emit}) {
//input
const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({params: []});
//Input
const remove = (item: Params) => {
let index = dynamicInput.params.indexOf(item);
if (index !== -1) {
dynamicInput.params.splice(index, 1);
}
emitChange()
};
//Input
const add = () => {
dynamicInput.params.push({
label: '',
value: '',
});
emitChange()
};
//value
watchEffect(() => {
initVal();
});
/**
* 初始化数值
*/
function initVal() {
console.log("props.value",props.value)
dynamicInput.params = [];
if(props.value && props.value.indexOf("{")==0){
let jsonObj = JSON.parse(props.value);
Object.keys(jsonObj).forEach((key) => {
dynamicInput.params.push({label: key, value: jsonObj[key]});
});
}
}
/**
* 数值改变
*/
function emitChange() {
let obj = {};
if (dynamicInput.params.length > 0) {
dynamicInput.params.forEach(item => {
obj[item['label']] = item['value']
})
}
emit("change", isEmpty(obj)?'': JSON.stringify(obj));
emit("update:value",isEmpty(obj)?'': JSON.stringify(obj))
}
return {
dynamicInput,
emitChange,
remove,
add,
};
},
components: {
MinusCircleOutlined,
PlusOutlined,
},
});
</script>
<style scoped>
.dynamic-delete-button {
cursor: pointer;
position: relative;
top: 4px;
font-size: 24px;
color: #999;
transition: all 0.3s;
}
.dynamic-delete-button:hover {
color: #777;
}
.dynamic-delete-button[disabled] {
cursor: not-allowed;
opacity: 0.5;
}
</style>

View File

@ -4,7 +4,7 @@
<script lang="ts">
import {defineComponent, PropType, ref,reactive, watchEffect, computed, unref, watch, onMounted} from 'vue';
import {Cascader} from 'ant-design-vue';
import {provinceAndCityData, regionData, provinceAndCityDataPlus, regionDataPlus, CodeToText, TextToCode} from "../utils/areaDataUtil";
import {provinceAndCityData, regionData, provinceAndCityDataPlus, regionDataPlus, CodeToText, TextToCode} from "../../utils/areaDataUtil";
import {useRuleFormItem} from "/@/hooks/component/useFormItem";
import {propTypes} from "/@/utils/propTypes";
import {useAttrs} from "/@/hooks/core/useAttrs";

View File

@ -0,0 +1,153 @@
<template>
<div class="area-select">
<!--省份-->
<a-select v-model:value="province" @change="proChange" allowClear>
<template v-for="item in provinceOptions" :key="`${item.value}`">
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
</template>
</a-select>
<!--城市-->
<a-select v-if="level>=2" v-model:value="city" @change="cityChange">
<template v-for="item in cityOptions" :key="`${item.value}`">
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
</template>
</a-select>
<!--地区-->
<a-select v-if="level>=3" v-model:value="area" @change="areaChange">
<template v-for="item in areaOptions" :key="`${item.value}`">
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
</template>
</a-select>
</div>
</template>
<script lang="ts">
import {defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted, onUnmounted, toRefs} from 'vue';
import {propTypes} from "/@/utils/propTypes";
import {useRuleFormItem} from '/@/hooks/component/useFormItem';
import {provinceOptions, getDataByCode, getRealCode} from "../../utils/areaDataUtil";
export default defineComponent({
name: 'JAreaSelect',
props: {
value: [Array, String],
province: [String],
city: [String],
area: [String],
level: propTypes.number.def(3),
},
emits: ['change','update:value'],
setup(props, {emit, refs}) {
const emitData = ref<any[]>([]);
//
const pca = reactive({
province: '',
city: '',
area: '',
});
//
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
//
const cityOptions = computed(() => {
return pca.province ? getDataByCode(pca.province) : [];
});
//
const areaOptions = computed(() => {
return pca.city ? getDataByCode(pca.city) : [];
});
/**
* 监听props值
*/
watchEffect(() => {
props && initValue();
});
/**
* 监听组件值变化
*/
watch(pca, (newVal) => {
if(!props.value){
emit("update:province",pca.province);
emit("update:city",pca.city);
emit("update:area",pca.area);
}
});
/**
* 数据初始化
*/
function initValue() {
if (props.value) {
//
if (Array.isArray(props.value)) {
pca.province = props.value[0];
pca.city = props.value[1] ? props.value[1] : '';
pca.area = props.value[2] ? props.value[2] : '';
} else {
//
let valueArr = getRealCode(props.value, props.level);
if (valueArr) {
pca.province = valueArr[0];
pca.city = props.level >= 2 && valueArr[1] ? valueArr[1] : '';
pca.area = props.level >= 3 && valueArr[2] ? valueArr[2] : '';
}
}
}else{
//
pca.province = props.province?props.province:'';
pca.city = props.city?props.city:'';
pca.area = props.area?props.area:'';
}
}
/**
* 省份change事件
*/
function proChange(val) {
pca.city = (val && getDataByCode(val)[0]?.value);
pca.area = (pca.city && getDataByCode(pca.city)[0]?.value);
state.value = props.level <= 1 ? val : (props.level <= 2 ? pca.city : pca.area);
emit("update:value",unref(state));
}
/**
* 城市change事件
*/
function cityChange(val) {
pca.area = (val && getDataByCode(val)[0]?.value);
state.value = props.level <= 2 ? val : pca.area;
emit("update:value",unref(state));
}
/**
* 区域change事件
*/
function areaChange(val) {
state.value = val;
emit("update:value",unref(state));
}
return {
...toRefs(pca),
provinceOptions,
cityOptions,
areaOptions,
proChange,
cityChange,
areaChange
};
},
});
</script>
<style lang="less" scoped>
.area-select {
width: 100%;
display: flex;
.ant-select{
width: 33.3%;
}
.ant-select:not(:first-child) {
margin-left: 10px;
}
}
</style>

View File

@ -0,0 +1,256 @@
<!--下拉树-->
<template>
<a-tree-select
allowClear
labelInValue
style="width: 100%"
:disabled="disabled"
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
:placeholder="placeholder"
:loadData="asyncLoadTreeData"
:value="treeValue"
:treeData="treeData"
:multiple="multiple"
@change="onChange">
</a-tree-select>
</template>
<script lang="ts">
import { defineComponent, ref, unref, watch } from 'vue';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { loadDictItem, loadTreeData } from '/@/api/common/api';
import { useMessage } from '/@/hooks/web/useMessage';
const { createMessage, createErrorModal } = useMessage();
export default defineComponent({
name: 'JCategorySelect',
components: {},
inheritAttrs: false,
props: {
value: propTypes.oneOfType([
propTypes.string,
propTypes.array,
]),
placeholder: {
type: String,
default: '请选择',
required: false,
},
disabled: {
type: Boolean,
default: false,
required: false,
},
condition: {
type: String,
default: '',
required: false,
},
//
multiple: {
type: [Boolean,String],
default: false,
},
loadTriggleChange: {
type: Boolean,
default: false,
required: false,
},
pid: {
type: String,
default: '',
required: false,
},
pcode: {
type: String,
default: '',
required: false,
},
back: {
type: String,
default: '',
required: false,
},
},
emits: ['options-change', 'change'],
setup(props, { emit, refs }) {
console.info(props);
const emitData = ref<any[]>([]);
const treeData = ref<any[]>([]);
const treeValue = ref('');
const attrs = useAttrs();
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
watch(
() => props.value,
() => {
loadItemByCode();
},
{ deep: true },
);
watch(
() => props.pcode,
() => {
loadRoot();
},
{ deep: true, immediate: true },
);
function loadRoot() {
let param = {
pid: props.pid,
pcode: !props.pcode ? '0' : props.pcode,
condition: props.condition,
};
console.info(param);
loadTreeData(param).then(res => {
for (let i of res) {
i.value = i.key;
if (i.leaf == false) {
i.isLeaf = false;
} else if (i.leaf == true) {
i.isLeaf = true;
}
}
treeData.value = res;
});
}
function loadItemByCode() {
if (!props.value || props.value == '0') {
treeValue.value = [];
} else {
loadDictItem({ ids: props.value }).then(res => {
let values = props.value.split(',');
treeValue.value = res.map((item, index) => ({
key: values[index],
value: values[index],
label: item,
}));
onLoadTriggleChange(res[0]);
});
}
}
function onLoadTriggleChange(text) {
//
if (!props.multiple && props.loadTriggleChange) {
backValue(props.value, text);
}
}
function backValue(value, label) {
let obj = {};
if (props.back) {
obj[props.back] = label;
}
emit('change', value, obj);
}
function asyncLoadTreeData(treeNode) {
let dataRef = treeNode.dataRef;
return new Promise((resolve) => {
if (treeNode.children.length > 0) {
resolve();
return;
}
let pid = dataRef.key;
console.info(treeNode);
let param = {
pid: pid,
condition: props.condition,
};
loadTreeData(param).then(res => {
if (res) {
for (let i of res) {
i.value = i.key;
if (i.leaf == false) {
i.isLeaf = false;
} else if (i.leaf == true) {
i.isLeaf = true;
}
}
addChildren(pid, res, treeData.value);
resolve();
}
});
});
}
function addChildren(pid, children, treeArray) {
console.info('treeArray', treeArray);
if (treeArray && treeArray.length > 0) {
for (let item of treeArray) {
if (item.key == pid) {
if (!children || children.length == 0) {
item.isLeaf = true;
} else {
item.children = children;
}
break;
} else {
addChildren(pid, children, item.children);
}
}
}
}
function onChange(value) {
if (!value) {
emit('change', '');
treeValue.value = '';
} else if (Array.isArray(value)) {
let labels = [];
let values = value.map(item => {
labels.push(item.label);
return item.value;
});
backValue(values.join(','), labels.join(','));
treeValue.value = value;
} else {
backValue(value.value, value.label);
treeValue.value = value;
}
}
function getCurrTreeData() {
return treeData;
}
function validateProp() {
let mycondition = props.condition;
return new Promise((resolve, reject) => {
if (!mycondition) {
resolve();
} else {
try {
let test = JSON.parse(mycondition);
if (typeof test == 'object' && test) {
resolve();
} else {
createMessage.error('组件JTreeSelect-condition传值有误需要一个json字符串!');
reject();
}
} catch (e) {
createMessage.error('组件JTreeSelect-condition传值有误需要一个json字符串!');
reject();
}
}
});
}
return {
state,
attrs,
onChange,
treeData,
treeValue,
asyncLoadTreeData,
};
},
})
;
</script>

View File

@ -0,0 +1,78 @@
<template>
<a-checkbox-group v-bind="attrs" v-model:value="checkboxArray" :options="checkOptions" @change="handleChange"></a-checkbox-group>
</template>
<script lang="ts">
import {defineComponent, computed, watch, watchEffect, ref, unref} from 'vue';
import {propTypes} from "/@/utils/propTypes";
import {useAttrs} from '/@/hooks/core/useAttrs';
import {initDictOptions} from "/@/utils/dict/index"
export default defineComponent({
name: 'JCheckbox',
props: {
value: propTypes.string,
dictCode: propTypes.string,
options: {
type: Array,
default: () => [],
},
},
emits: ['change', 'update:value'],
setup(props, {emit}) {
const attrs = useAttrs();
//checkbox
const checkOptions = ref<any[]>([]);
//checkbox
const checkboxArray = ref<any[]>([]);
/**
* 监听value
*/
watchEffect(() => {
props.value && (checkboxArray.value = props.value ? props.value.split(",") : []);
});
/**
* 监听字典code
*/
watchEffect(() => {
props && initOptions();
});
/**
* 初始化选项
*/
async function initOptions() {
//options,
if (props.options && props.options.length > 0) {
checkOptions.value = props.options;
return;
}
//Code,
if(props.dictCode){
const dictData = await initDictOptions(props.dictCode);
checkOptions.value = dictData.reduce((prev, next) => {
if (next) {
const value = next['value'];
prev.push({
label: next['text'],
value: value,
});
}
return prev;
}, []);
}
}
/**
* change事件
* @param $event
*/
function handleChange($event) {
emit('update:value', $event.join(','));
emit('change', $event.join(','));
}
return {checkboxArray, checkOptions, attrs, handleChange};
},
});
</script>

View File

@ -0,0 +1,246 @@
<template>
<div v-bind="boxBindProps">
<!-- 全屏按钮 -->
<a-icon v-if="fullScreen" class="full-screen-icon" :type="fullScreenIcon" @click="onToggleFullScreen"/>
<textarea ref="textarea" v-bind="getBindValue"></textarea>
</div>
</template>
<script lang="ts">
import {defineComponent, onMounted, reactive, ref, watch, unref, computed} from 'vue';
import { propTypes } from '/@/utils/propTypes';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
//
import _CodeMirror, { EditorFromTextArea } from 'codemirror'
//
import 'codemirror/lib/codemirror.css';
// options
import 'codemirror/theme/cobalt.css';
//
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/mode/css/css.js';
import 'codemirror/mode/xml/xml.js';
import 'codemirror/mode/clike/clike.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/python/python.js';
import 'codemirror/mode/r/r.js';
import 'codemirror/mode/shell/shell.js';
import 'codemirror/mode/sql/sql.js';
import 'codemirror/mode/swift/swift.js';
import 'codemirror/mode/vue/vue.js';
// :
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/comment-fold.js";
import "codemirror/addon/fold/indent-fold.js";
import "codemirror/addon/fold/foldgutter.js";
// :
//styleActiveLinetrue
import "codemirror/addon/selection/active-line.js";
//
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/anyword-hint.js";
import { useAttrs } from '/@/hooks/core/useAttrs';
import {useDesign} from '/@/hooks/web/useDesign'
export default defineComponent({
name: 'JCodeEditor',
// attrs html
inheritAttrs: false,
components: {},
props: {
value: propTypes.string.def(''),
height:propTypes.string.def('auto'),
disabled: propTypes.bool.def(false),
//
fullScreen: propTypes.bool.def(false),
// z-index
zIndex: propTypes.any.def(999),
},
emits: ['change', 'update:value'],
setup(props, { emit }) {
const { prefixCls } = useDesign('code-editer');
const CodeMirror = window.CodeMirror || _CodeMirror;
const emitData = ref<object>();
//
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
const textarea = ref<HTMLTextAreaElement>();
let coder: Nullable<EditorFromTextArea> = null
const attrs = useAttrs();
const height =ref(props.height);
const options = reactive({
//
tabSize: 2,
// JS
theme: 'cobalt',
smartIndent: true, //
//
lineNumbers: true,
line: true,
// :
foldGutter: true,
lineWrapping: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
// :
//
styleActiveLine: true,
});
let innerValue = ''
//
const isFullScreen = ref(false)
const fullScreenIcon = computed(() => isFullScreen.value ? 'fullscreen-exit' : 'fullscreen')
//
const boxBindProps = computed(() => {
let _props = {
class: [
prefixCls, 'full-screen-parent', 'auto-height',
{
'full-screen': isFullScreen.value,
},
],
style: {},
}
if (isFullScreen.value) {
_props.style['z-index'] = props.zIndex
}
return _props
})
/**
* 监听组件值
*/
watch(() => props.value, () => {
if (innerValue != props.value) {
setValue(props.value, false);
}
});
onMounted(() => {
initialize();
});
/**
* 组件赋值
* @param value
* @param trigger 是否触发 change 事件
*/
function setValue(value: string, trigger = true) {
coder?.setValue(value ?? '')
innerValue = value
trigger && emitChange(innerValue)
}
//
function onChange(obj) {
innerValue = obj.getValue() ?? '';
if (props.value != innerValue) {
emitChange(innerValue)
}
}
function emitChange(value) {
emit('change', value);
emit('update:value', value);
}
//
function initialize() {
coder = CodeMirror.fromTextArea(textarea.value!, options);
//
coder.on('change', onChange);
//
setValue(innerValue, false)
}
//
function onToggleFullScreen() {
isFullScreen.value = !isFullScreen.value
}
const getBindValue = Object.assign({}, unref(props), unref(attrs));
return {
state,
textarea,
boxBindProps,
getBindValue,
setValue,
isFullScreen,
fullScreenIcon,
onToggleFullScreen,
};
},
});
</script>
<style lang="less">
//noinspection LessUnresolvedVariable
@prefix-cls: ~'@{namespace}-code-editer';
.@{prefix-cls} {
&.auto-height {
.CodeMirror {
height: v-bind(height) !important;
min-height: 100px;
}
}
/* 全屏样式 */
&.full-screen-parent {
position: relative;
.full-screen-icon {
opacity: 0;
color: black;
width: 20px;
height: 20px;
line-height: 24px;
background-color: white;
position: absolute;
top: 2px;
right: 2px;
z-index: 9;
cursor: pointer;
transition: opacity 0.3s;
padding: 2px 0 0 1.5px;
}
&:hover {
.full-screen-icon {
opacity: 1;
&:hover {
background-color: rgba(255, 255, 255, 0.88);
}
}
}
&.full-screen {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 8px;
background-color: #f5f5f5;
.full-screen-icon {
top: 12px;
right: 12px;
}
.full-screen-child,
.CodeMirror {
height: 100%;
max-height: 100%;
min-height: 100%;
}
}
.full-screen-child {
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<a-radio-group v-if="compType===CompTypeEnum.Radio" v-bind="attrs" v-model:value="state" @change="handleChange">
<template v-for="item in dictOptions" :key="`${item.value}`">
<a-radio :value="item.value">
{{ item.label }}
</a-radio>
</template>
</a-radio-group>
<a-radio-group v-else-if="compType===CompTypeEnum.RadioButton" v-bind="attrs" v-model:value="state" buttonStyle="solid" @change="handleChange">
<template v-for="item in dictOptions" :key="`${item.value}`">
<a-radio-button :value="item.value">
{{ item.label }}
</a-radio-button>
</template>
</a-radio-group>
<a-select v-else-if="compType===CompTypeEnum.Select" :placeholder="placeholder" v-bind="attrs" v-model:value="state" @change="handleChange">
<a-select-option v-if="showChooseOption" :value="undefined"></a-select-option>
<template v-for="item in dictOptions" :key="`${item.value}`">
<a-select-option :value="item.value">
<span style="display: inline-block;width: 100%" :title=" item.label ">
{{ item.label }}
</span>
</a-select-option>
</template>
</a-select>
</template>
<script lang="ts">
import {defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted} from 'vue';
import {propTypes} from "/@/utils/propTypes";
import {useAttrs} from "/@/hooks/core/useAttrs";
import {initDictOptions} from "/@/utils/dict/index"
import {get, omit} from 'lodash-es';
import {useRuleFormItem} from '/@/hooks/component/useFormItem';
import {CompTypeEnum} from '/@/enums/CompTypeEnum.ts';
export default defineComponent({
name: 'JDictSelectTag',
inheritAttrs: false,
props: {
value: propTypes.oneOfType([
propTypes.string,
propTypes.number,
propTypes.array,
]),
dictCode: propTypes.string,
type: propTypes.string,
placeholder: propTypes.string,
stringToNumber: propTypes.bool,
getPopupContainer: {
type: Function,
default: (node) => node.parentNode
},
//
showChooseOption: propTypes.bool.def(true),
},
emits: ['options-change', 'change'],
setup(props, {emit, refs}) {
const emitData = ref<any[]>([]);
const dictOptions = ref<any[]>([]);
const attrs = useAttrs();
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
const getBindValue = Object.assign({}, unref(props), unref(attrs));
//
const compType = computed(() => {
return (!props.type || props.type === "list") ? 'select' : props.type;
});
/**
* 监听字典code
*/
watchEffect(() => {
props.dictCode && initDictData();
});
async function initDictData() {
let {dictCode, stringToNumber} = props;
//Code,
const dictData = await initDictOptions(dictCode);
dictOptions.value = dictData.reduce((prev, next) => {
if (next) {
const value = next['value'];
prev.push({
label: next['text'] || next['label'],
value: stringToNumber ? +value : value,
...omit(next, ['text', 'value']),
});
}
return prev;
}, []);
}
function handleChange(e) {
emitData.value = [e?.target?.value || e];
}
return {
state,
compType,
attrs,
getBindValue,
dictOptions,
CompTypeEnum,
handleChange
};
},
});
</script>

View File

@ -0,0 +1,305 @@
<template>
<div :class="`${prefixCls}`">
<div class="content">
<a-tabs :size="`small`" v-model:activeKey="activeKey">
<a-tab-pane tab="秒" key="second" v-if="!hideSecond">
<SecondUI v-model:value="second" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="分" key="minute">
<MinuteUI v-model:value="minute" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="时" key="hour">
<HourUI v-model:value="hour" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="日" key="day">
<DayUI v-model:value="day" :week="week" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="月" key="month">
<MonthUI v-model:value="month" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="周" key="week">
<WeekUI v-model:value="week" :day="day" :disabled="disabled"/>
</a-tab-pane>
<a-tab-pane tab="年" key="year" v-if="!hideYear && !hideSecond">
<YearUI v-model:value="year" :disabled="disabled"/>
</a-tab-pane>
</a-tabs>
<a-divider/>
<!-- 执行时间预览 -->
<a-row :gutter="8">
<a-col :span="18" style="margin-top: 22px;">
<a-row :gutter="8">
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.second" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='second'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.minute" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='minute'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.hour" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='hour'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.day" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='day'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.month" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='month'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8" style="margin-bottom: 12px;">
<a-input v-model:value="inputValues.week" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='week'"></span>
</template>
</a-input>
</a-col>
<a-col :span="8">
<a-input v-model:value="inputValues.year" @blur="onInputBlur">
<template #addonBefore>
<span class="allow-click" @click="activeKey='year'"></span>
</template>
</a-input>
</a-col>
<a-col :span="16">
<a-input v-model:value="inputValues.cron" @blur="onInputCronBlur">
<template #addonBefore>
<a-tooltip title="Cron表达式"></a-tooltip>
</template>
</a-input>
</a-col>
</a-row>
</a-col>
<a-col :span="6">
<div>近十次执行时间不含年</div>
<a-textarea type="textarea" :value="preTimeList" :rows="5"/>
</a-col>
</a-row>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, reactive, ref, watch, provide } from 'vue'
import { useDesign } from '/@/hooks/web/useDesign'
import CronParser from 'cron-parser'
import SecondUI from './tabs/SecondUI.vue'
import MinuteUI from './tabs/MinuteUI.vue'
import HourUI from './tabs/HourUI.vue'
import DayUI from './tabs/DayUI.vue'
import MonthUI from './tabs/MonthUI.vue'
import WeekUI from './tabs/WeekUI.vue'
import YearUI from './tabs/YearUI.vue'
import { cronEmits, cronProps } from './easy.cron.data'
import { dateFormat, simpleDebounce } from '/@/utils/common/compUtils'
const { prefixCls } = useDesign('easy-cron-inner')
provide('prefixCls', prefixCls)
const emit = defineEmits([...cronEmits])
const props = defineProps({ ...cronProps })
const activeKey = ref(props.hideSecond ? 'minute' : 'second')
const second = ref('*')
const minute = ref('*')
const hour = ref('*')
const day = ref('*')
const month = ref('*')
const week = ref('?')
const year = ref('*')
const inputValues = reactive({ second: '', minute: '', hour: '', day: '', month: '', week: '', year: '', cron: '' })
const preTimeList = ref('执行预览,会忽略年份参数。')
// cron
const cronValueInner = computed(() => {
let result: string[] = []
if (!props.hideSecond) {
result.push(second.value ? second.value : '*')
}
result.push(minute.value ? minute.value : '*')
result.push(hour.value ? hour.value : '*')
result.push(day.value ? day.value : '*')
result.push(month.value ? month.value : '*')
result.push(week.value ? week.value : '?')
if (!props.hideYear && !props.hideSecond) result.push(year.value ? year.value : '*')
return result.join(' ')
})
//
const cronValueNoYear = computed(() => {
const v = cronValueInner.value
if (props.hideYear || props.hideSecond) return v
const vs = v.split(' ')
if (vs.length >= 6) {
// Quartz
vs[5] = convertWeekToQuartz(vs[5])
}
return vs.slice(0, vs.length - 1).join(' ')
})
const calTriggerList = simpleDebounce(calTriggerListInner, 500)
watch(() => props.value, (newVal) => {
if (newVal === cronValueInner.value) {
return
}
formatValue()
})
watch(cronValueInner, (newValue) => {
calTriggerList()
emitValue(newValue)
assignInput()
})
// watch(minute, () => {
// if (second.value === '*') {
// second.value = '0'
// }
// })
// watch(hour, () => {
// if (minute.value === '*') {
// minute.value = '0'
// }
// })
// watch(day, () => {
// if (day.value !== '?' && hour.value === '*') {
// hour.value = '0'
// }
// })
// watch(week, () => {
// if (week.value !== '?' && hour.value === '*') {
// hour.value = '0'
// }
// })
// watch(month, () => {
// if (day.value === '?' && week.value === '*') {
// week.value = '1'
// } else if (week.value === '?' && day.value === '*') {
// day.value = '1'
// }
// })
// watch(year, () => {
// if (month.value === '*') {
// month.value = '1'
// }
// })
assignInput()
formatValue()
calTriggerListInner()
function assignInput() {
inputValues.second = second.value
inputValues.minute = minute.value
inputValues.hour = hour.value
inputValues.day = day.value
inputValues.month = month.value
inputValues.week = week.value
inputValues.year = year.value
inputValues.cron = cronValueInner.value
}
function formatValue() {
if (!props.value) return
const values = props.value.split(' ').filter(item => !!item)
if (!values || values.length <= 0) return
let i = 0
if (!props.hideSecond) second.value = values[i++]
if (values.length > i) minute.value = values[i++]
if (values.length > i) hour.value = values[i++]
if (values.length > i) day.value = values[i++]
if (values.length > i) month.value = values[i++]
if (values.length > i) week.value = values[i++]
if (values.length > i) year.value = values[i]
assignInput()
}
// Quartz
// 1 = 2 = 3 = 4 = 5 = 6 = 7 =
function convertWeekToQuartz(week: string) {
let convert = (v: string) => {
if (v === '0') {
return '1'
}
if (v === '1') {
return '0'
}
return (Number.parseInt(v) - 1).toString()
}
// 1-7 or 1/7
let patten1 = /^([0-7])([-/])([0-7])$/
// 1,4,7
let patten2 = /^([0-7])(,[0-7])+$/
if (/^[0-7]$/.test(week)) {
return convert(week)
} else if (patten1.test(week)) {
return week.replace(patten1, ($0, before, separator, after) => {
if (separator === '/') {
return convert(before) + separator + after
} else {
return convert(before) + separator + convert(after)
}
})
} else if (patten2.test(week)) {
return week.split(',').map(v => convert(v)).join(',')
}
return week
}
function calTriggerListInner() {
//
if (props.remote) {
props.remote(cronValueInner.value, +new Date(), v => {
preTimeList.value = v
})
return
}
const format = 'yyyy-MM-dd hh:mm:ss'
const options = {
currentDate: dateFormat(new Date(), format),
}
const iter = CronParser.parseExpression(cronValueNoYear.value, options)
const result: string[] = []
for (let i = 1; i <= 10; i++) {
result.push(dateFormat(new Date(iter.next() as any), format))
}
preTimeList.value = result.length > 0 ? result.join('\n') : '无执行时间'
}
function onInputBlur() {
second.value = inputValues.second
minute.value = inputValues.minute
hour.value = inputValues.hour
day.value = inputValues.day
month.value = inputValues.month
week.value = inputValues.week
year.value = inputValues.year
}
function onInputCronBlur(event) {
emitValue(event.target.value)
}
function emitValue(value) {
emit('change', value)
emit('update:value', value)
}
</script>
<style lang="less">
@import "easy.cron.inner";
</style>

View File

@ -0,0 +1,63 @@
<template>
<div :class="`${prefixCls}`">
<a-input :placeholder="placeholder" v-model:value="editCronValue" :disabled="disabled">
<template #addonAfter>
<a class="open-btn" :disabled="disabled?'disabled':null" @click="showConfigModal">
<Icon icon="ant-design:setting-outlined"/>
<span>选择</span>
</a>
</template>
</a-input>
<EasyCronModal
@register="registerModal"
v-model:value="editCronValue"
:exeStartTime="exeStartTime"
:hideYear="hideYear"
:remote="remote"
:hideSecond="hideSecond"/>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { useDesign } from '/@/hooks/web/useDesign'
import { useModal } from '/@/components/Modal'
import { propTypes } from '/@/utils/propTypes'
import Icon from '/@/components/Icon/src/Icon.vue'
import EasyCronModal from './EasyCronModal.vue'
import { cronEmits, cronProps } from './easy.cron.data'
const { prefixCls } = useDesign('easy-cron-input')
const emit = defineEmits([...cronEmits])
const props = defineProps({
...cronProps,
placeholder: propTypes.string.def('请输入cron表达式'),
exeStartTime: propTypes.oneOfType([
propTypes.number,
propTypes.string,
propTypes.object,
]).def(0),
})
const [registerModal, { openModal }] = useModal()
const editCronValue = ref(props.value)
watch(() => props.value, (newVal) => {
if (newVal !== editCronValue.value) {
editCronValue.value = newVal
}
})
watch(editCronValue, (newVal) => {
emit('change', newVal)
emit('update:value', newVal)
})
function showConfigModal() {
if (!props.disabled) {
openModal()
}
}
</script>
<style lang="less">
@import "easy.cron.input";
</style>

Some files were not shown because too many files have changed in this diff Show More