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 # port
VITE_PORT = 3100 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 # 是否打开mock
VITE_USE_MOCK = false VITE_USE_MOCK = true
# 公共路径 # 发布路径
VITE_PUBLIC_PATH = / VITE_PUBLIC_PATH = /
# 跨域代理,您可以配置多个 ,请注意,没有换行符 # 跨域代理,您可以配置多个 ,请注意,没有换行符
VITE_PROXY = [["/jeecg-boot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]] VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
# VITE_PROXY=[["/api","https://vvbin.cn/test"]]
# 控制台不输出 # 控制台不输出
VITE_DROP_CONSOLE = false 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= 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 # 是否启用mock
VITE_USE_MOCK = true VITE_USE_MOCK = true
# 公共路径 # 发布路径
VITE_PUBLIC_PATH = / VITE_PUBLIC_PATH = /
# 控制台不输出 # 控制台不输出
@ -10,19 +10,18 @@ VITE_DROP_CONSOLE = true
# 是否启用gzip或brotli压缩 # 是否启用gzip或brotli压缩
# 选项值: gzip | brotli | none # 选项值: gzip | brotli | none
# 如果需要多个可以使用“,”分隔 # 如果需要多个可以使用“,”分隔
VITE_BUILD_COMPRESS = 'none' VITE_BUILD_COMPRESS = 'gzip'
# 使用压缩时是否删除原始文件默认为false # 使用压缩时是否删除原始文件默认为false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# 接口父路径 #后台接口父地址(必填)
VITE_GLOB_API_URL=/basic-api VITE_GLOB_API_URL=/jeecgboot
# 文件上次地址(可选) #后台接口全路径地址(必填)
# 它可以由nginx转发也可以直接写入实际地址 VITE_GLOB_DOMAIN_URL=http://api3.boot.jeecg.com
VITE_GLOB_UPLOAD_URL=/upload
# 接口父路径 # 接口父路径前缀
VITE_GLOB_API_URL_PREFIX= VITE_GLOB_API_URL_PREFIX=
# 是否启用图像压缩 # 是否启用图像压缩

View File

@ -1,36 +1,31 @@
NODE_ENV=production # 是否启用mock
# Whether to open mock
VITE_USE_MOCK = true VITE_USE_MOCK = true
# public path # 发布路径
VITE_PUBLIC_PATH = / VITE_PUBLIC_PATH = /
# Delete console # 控制台不输出
VITE_DROP_CONSOLE = true VITE_DROP_CONSOLE = true
# Whether to enable gzip or brotli compression # 是否启用gzip或brotli压缩
# Optional: gzip | brotli | none # 选项值: gzip | brotli | none
# If you need multiple forms, you can use `,` to separate # 如果需要多个可以使用“,”分隔
VITE_BUILD_COMPRESS = 'none' VITE_BUILD_COMPRESS = 'gzip'
# Whether to delete origin files when using compress, default false # 使用压缩时是否删除原始文件,默认为false
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = 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= VITE_GLOB_API_URL_PREFIX=
# Whether to enable image compression # 是否启用图像压缩
VITE_USE_IMAGEMIN= true VITE_USE_IMAGEMIN= true
# use pwa # 使用pwa
VITE_USE_PWA = false VITE_USE_PWA = false
# Is it compatible with older browsers # 是否兼容旧浏览器
VITE_LEGACY = false VITE_LEGACY = false

View File

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

View File

@ -1,6 +1,6 @@
import { generate } from '@ant-design/colors'; import { generate } from '@ant-design/colors';
export const primaryColor = '#0960bd'; export const primaryColor = '#1890FF';
export const darkMode = 'light'; 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 fs, { writeFileSync } from 'fs-extra';
import chalk from 'chalk'; import chalk from 'chalk';
import { getRootPath, getEnvConfig } from '../utils'; import { getEnvConfig, getRootPath } from '../utils';
import { getConfigFileName } from '../getConfigFileName'; import { getConfigFileName } from '../getConfigFileName';
import pkg from '../../package.json'; import pkg from '../../package.json';
function createConfig( interface CreateConfigParams {
{ configName: string;
configName, config: any;
config, configFileName?: string;
configFileName = GLOB_CONFIG_FILE_NAME, }
}: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} }
) { function createConfig(params: CreateConfigParams) {
const { configName, config, configFileName } = params;
try { try {
const windowConf = `window.${configName}`; const windowConf = `window.${configName}`;
// Ensure that the variable will not be modified // Ensure that the variable will not be modified
@ -40,5 +41,5 @@ function createConfig(
export function runBuildConfig() { export function runBuildConfig() {
const config = getEnvConfig(); const config = getEnvConfig();
const configFileName = getConfigFileName(config); 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') { if (envName === 'VITE_PORT') {
realName = Number(realName); realName = Number(realName);
} }
if (envName === 'VITE_PROXY') { if (envName === 'VITE_PROXY' && realName) {
try { try {
realName = JSON.parse(realName); realName = JSON.parse(realName.replace(/'/g, '"'));
} catch (error) { } catch (error) {
realName = ''; realName = '';
} }
} }
ret[envName] = realName; ret[envName] = realName;
if (typeof realName === 'string') { if (typeof realName === 'string') {
@ -50,7 +50,7 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
*/ */
function getConfFiles() { function getConfFiles() {
const script = process.env.npm_lifecycle_script; 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; const result = reg.exec(script as string) as any;
if (result) { if (result) {
const mode = result[1] as string; 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 legacy from '@vitejs/plugin-legacy';
import purgeIcons from 'vite-plugin-purge-icons'; import purgeIcons from 'vite-plugin-purge-icons';
import windiCSS from 'vite-plugin-windicss'; import windiCSS from 'vite-plugin-windicss';
import vueSetupExtend from 'vite-plugin-vue-setup-extend';
import { configHtmlPlugin } from './html'; import { configHtmlPlugin } from './html';
import { configPwaConfig } from './pwa'; import { configPwaConfig } from './pwa';
import { configMockPlugin } from './mock'; import { configMockPlugin } from './mock';
@ -29,7 +30,10 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vue(), vue(),
// have to // have to
vueJsx(), vueJsx(),
// support name
vueSetupExtend(),
]; ];
// vite-plugin-windicss // vite-plugin-windicss
vitePlugins.push(windiCSS()); vitePlugins.push(windiCSS());
@ -67,7 +71,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// rollup-plugin-gzip // rollup-plugin-gzip
vitePlugins.push( 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 // vite-plugin-pwa

View File

@ -14,7 +14,52 @@ export function configStyleImportPlugin(isBuild: boolean) {
libraryName: 'ant-design-vue', libraryName: 'ant-design-vue',
esModule: true, esModule: true,
resolveStyle: (name) => { 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-base': '#303030',
// 'border-color-split': '#30363d', // 'border-color-split': '#30363d',
'item-active-bg': '#111b26', 'item-active-bg': '#111b26',
'app-content-background': 'rgb(255 255 255 / 4%)', 'app-content-background': '#1e1e1e',
'tree-node-selected-bg': '#11263c', 'tree-node-selected-bg': '#11263c',
'alert-success-border-color': '#274916', 'alert-success-border-color': '#274916',

View File

@ -7,7 +7,7 @@ type ProxyItem = [string, string];
type ProxyList = ProxyItem[]; type ProxyList = ProxyItem[];
type ProxyTargetList = Record<string, ProxyOptions & { rewrite: (path: string) => string }>; type ProxyTargetList = Record<string, ProxyOptions>;
const httpsRE = /^https:\/\//; 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> <!DOCTYPE html>
<html lang="en" id="htmlRoot"> <html lang="zh_CN" id="htmlRoot">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
@ -10,7 +10,11 @@
/> />
<title><%= title %></title> <title><%= title %></title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/logo.png" />
<!-- 全局配置 -->
<script>
window._CONFIG = {};
</script>
</head> </head>
<body> <body>
<script> <script>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import { MockMethod } from 'vite-plugin-mock'; import { MockMethod } from 'vite-plugin-mock';
import { resultSuccess } from '../_util'; import { resultSuccess, baseUrl } from '../_util';
const demoTreeList = (keyword) => { const demoTreeList = (keyword) => {
const result = { const result = {
@ -26,7 +26,7 @@ const demoTreeList = (keyword) => {
export default [ export default [
{ {
url: '/jeecg-boot/tree/getDemoOptions', url: `${baseUrl}/tree/getDemoOptions`,
timeout: 1000, timeout: 1000,
method: 'get', method: 'get',
response: ({ query }) => { 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 { MockMethod } from 'vite-plugin-mock';
import { createFakeUserList } from './user'; import { createFakeUserList } from './user';
@ -17,7 +17,7 @@ const dashboardRoute = {
{ {
path: 'analysis', path: 'analysis',
name: 'Analysis', name: 'Analysis',
component: '/dashboard/analysis/index', component: '/dashboard/Analysis/index',
meta: { meta: {
hideMenu: true, hideMenu: true,
hideBreadcrumb: true, hideBreadcrumb: true,
@ -237,7 +237,7 @@ const linkRoute = {
export default [ export default [
{ {
url: '/jeecg-boot/sys/permission/getUserPermissionByToken', url: `${baseUrl}/sys/permission/getUserPermissionByToken`,
timeout: 1000, timeout: 1000,
method: 'get', method: 'get',
response: (request: requestParams) => { response: (request: requestParams) => {

View File

@ -1,11 +1,10 @@
import { MockMethod } from 'vite-plugin-mock'; import { MockMethod } from 'vite-plugin-mock';
import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util'; import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util';
export function createFakeUserList() { export function createFakeUserList() {
return [ return [
{ {
userId: '1', userId: '1',
username: 'jeecg', username: 'admin',
realname: '管理员', realname: '管理员',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640', avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640',
desc: 'manager', desc: 'manager',
@ -21,7 +20,7 @@ export function createFakeUserList() {
}, },
{ {
userId: '2', userId: '2',
username: 'test', username: 'jeecg',
password: '123456', password: '123456',
realname: '测试用户', realname: '测试用户',
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640', avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
@ -47,7 +46,7 @@ const fakeCodeList: any = {
export default [ export default [
// mock user login // mock user login
{ {
url: '/jeecg-boot/sys/login', url: `${baseUrl}/sys/login`,
timeout: 200, timeout: 200,
method: 'post', method: 'post',
response: ({ body }) => { response: ({ body }) => {
@ -58,19 +57,19 @@ export default [
if (!checkUser) { if (!checkUser) {
return resultError('Incorrect account or password'); 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({ return resultSuccess({
roles, roles,
userId, userId,
username: _username, username: _username,
token, token,
realName, realname,
desc, desc,
}); });
}, },
}, },
{ {
url: '/jeecg-boot/sys/user/getUserInfo', url: `${baseUrl}/sys/user/getUserInfo`,
method: 'get', method: 'get',
response: (request: requestParams) => { response: (request: requestParams) => {
const token = getRequestToken(request); const token = getRequestToken(request);
@ -83,7 +82,7 @@ export default [
}, },
}, },
{ {
url: '/jeecg-boot/sys/permission/getPermCode', url: `${baseUrl}/sys/permission/getPermCode`,
timeout: 200, timeout: 200,
method: 'get', method: 'get',
response: (request: requestParams) => { response: (request: requestParams) => {
@ -99,7 +98,7 @@ export default [
}, },
}, },
{ {
url: '/jeecg-boot/sys/logout', url: `${baseUrl}/sys/logout`,
timeout: 200, timeout: 200,
method: 'get', method: 'get',
response: (request: requestParams) => { response: (request: requestParams) => {
@ -113,11 +112,12 @@ export default [
}, },
}, },
{ {
url: `/jeecg-boot/sys/randomImage/1629428467008`, url: `${baseUrl}/sys/randomImage/1629428467008`,
timeout: 200, timeout: 200,
method: 'get', method: 'get',
response: (request: requestParams) => { 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); return resultSuccess(result);
}, },
}, },

View File

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

View File

@ -8,7 +8,6 @@ module.exports = {
quoteProps: 'as-needed', quoteProps: 'as-needed',
bracketSpacing: true, bracketSpacing: true,
trailingComma: 'es5', trailingComma: 'es5',
jsxBracketSameLine: false,
jsxSingleQuote: false, jsxSingleQuote: false,
arrowParens: 'always', arrowParens: 'always',
insertPragma: false, 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'; import { GetAccountInfoModel } from './model/accountModel';
enum Api { enum Api {
ACCOUNT_INFO = '/account/getAccountInfo', ACCOUNT_INFO = '/mock/account/getAccountInfo',
SESSION_TIMEOUT = '/user/sessionTimeout', SESSION_TIMEOUT = '/mock/user/sessionTimeout',
TOKEN_EXPIRED = '/mock/user/tokenExpired',
} }
// Get personal center-basic settings // Get personal center-basic settings
@ -11,3 +12,5 @@ enum Api {
export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO }); export const accountInfoApi = () => defHttp.get<GetAccountInfoModel>({ url: Api.ACCOUNT_INFO });
export const sessionTimeoutApi = () => defHttp.post<void>({ url: Api.SESSION_TIMEOUT }); 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 { defHttp } from '/@/utils/http/axios';
import { DemoOptionsItem, selectParams } from './model/optionsModel'; import { DemoOptionsItem, selectParams } from './model/optionsModel';
enum Api { enum Api {
OPTIONS_LIST = '/select/getDemoOptions', OPTIONS_LIST = '/mock/select/getDemoOptions',
} }
/** /**

View File

@ -4,28 +4,26 @@ import {
MenuParams, MenuParams,
RoleParams, RoleParams,
TestPageParams, TestPageParams,
UserPageParams,
RolePageParams, RolePageParams,
MenuListGetResultModel, MenuListGetResultModel,
DeptListGetResultModel, DeptListGetResultModel,
AccountListGetResultModel, AccountListGetResultModel,
RolePageListGetResultModel, RolePageListGetResultModel,
RoleListGetResultModel, RoleListGetResultModel,
TestListGetResultModel, TestListGetResultModel
UserListGetResultModel,
} from './model/systemModel'; } from './model/systemModel';
import {defHttp} from '/@/utils/http/axios'; import {defHttp} from '/@/utils/http/axios';
enum Api { enum Api {
AccountList = '/system/getAccountList', AccountList = '/mock/system/getAccountList',
IsAccountExist = '/system/accountExist', IsAccountExist = '/mock/system/accountExist',
DeptList = '/system/getDeptList', DeptList = '/mock/system/getDeptList',
setRoleStatus = '/system/setRoleStatus', setRoleStatus = '/mock/system/setRoleStatus',
MenuList = '/system/getMenuList', MenuList = '/mock/system/getMenuList',
RolePageList = '/system/getRoleListByPage', RolePageList = '/mock/system/getRoleListByPage',
DemoTableList = '/system/getDemoTableListByPage', DemoTableList = '/mock/system/getDemoTableListByPage',
TestPageList = '/system/getTestListByPage', TestPageList = '/mock/system/getTestListByPage',
GetAllRoleList = '/system/getAllRoleList', GetAllRoleList = '/mock/system/getAllRoleList',
} }
export const getAccountList = (params: AccountParams) => export const getAccountList = (params: AccountParams) =>
@ -54,29 +52,3 @@ export const getDemoTableListByPage = (params) =>
export const isAccountExist = (account: string) => export const isAccountExist = (account: string) =>
defHttp.post({url: Api.IsAccountExist, params: {account}}, {errorMessageMode: 'none'}); 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'; import { DemoParams, DemoListGetResultModel } from './model/tableModel';
enum Api { enum Api {
DEMO_LIST = '/table/getDemoList', DEMO_LIST = '/mock/table/getDemoList',
} }
/** /**

View File

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

View File

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

View File

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

View File

@ -20,3 +20,18 @@ export function uploadApi(
params 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', phoneLogin = '/sys/phoneLogin',
Logout = '/sys/logout', Logout = '/sys/logout',
GetUserInfo = '/sys/user/getUserInfo', GetUserInfo = '/sys/user/getUserInfo',
// 获取系统权限
// 1、查询用户拥有的按钮/表单访问权限
// 2、所有权限
// 3、系统安全模式
GetPermCode = '/sys/permission/getPermCode', GetPermCode = '/sys/permission/getPermCode',
//新加的获取图形验证码的接口 //新加的获取图形验证码的接口
getInputCode = '/sys/randomImage', getInputCode = '/sys/randomImage',
@ -20,10 +24,20 @@ enum Api {
registerApi = '/sys/user/register', registerApi = '/sys/user/register',
//校验用户接口 //校验用户接口
checkOnlyUser = '/sys/user/checkOnlyUser', checkOnlyUser = '/sys/user/checkOnlyUser',
//SSO登录校验
validateCasLogin = '/sys/cas/client/validateLogin',
//校验手机号 //校验手机号
phoneVerify = '/sys/user/phoneVerification', phoneVerify = '/sys/user/phoneVerification',
//修改密码 //修改密码
passwordChange = '/sys/user/passwordChange', 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 * @description: getUserInfo
*/ */
export function getUserInfo() { export function getUserInfo() {
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }); return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' });
} }
export function getPermCode() { export function getPermCode() {
return defHttp.get<string[]>({ url: Api.GetPermCode }); return defHttp.get({ url: Api.GetPermCode });
} }
export function doLogout() { export function doLogout() {
@ -80,7 +94,7 @@ export function getCodeInfo(currdatetime) {
*/ */
export function getCaptcha(params) { export function getCaptcha(params) {
return new Promise((resolve, reject) => { 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) console.log(res)
if(res.success){ if(res.success){
resolve(true) resolve(true)
@ -117,3 +131,56 @@ export const phoneVerify = (params) =>
*/ */
export const passwordChange = (params) => export const passwordChange = (params) =>
defHttp.get({url: Api.passwordChange, params},{isTransformResponse:false}); 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-size: 16px;
font-weight: 700; font-weight: 700;
transition: all 0.5s; transition: all 0.5s;
line-height: normal;
} }
} }
</style> </style>

View File

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

View File

@ -21,7 +21,6 @@
import Icon from '/@/components/Icon/src/Icon.vue'; import Icon from '/@/components/Icon/src/Icon.vue';
import { buttonProps } from './props'; import { buttonProps } from './props';
import { useAttrs } from '/@/hooks/core/useAttrs'; import { useAttrs } from '/@/hooks/core/useAttrs';
const props = defineProps(buttonProps); const props = defineProps(buttonProps);
// get component class // get component class
const attrs = useAttrs({ excludeDefaultKeys: false }); 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. * Text after icon.
*/ */
postIcon: { type: String }, postIcon: { type: String },
type: { type: String },
/** /**
* preIcon and postIcon icon size. * preIcon and postIcon icon size.
* @default: 14 * @default: 14
*/ */
iconSize: { type: Number, default: 14 }, iconSize: { type: Number, default: 14 },
isUpload:{type:Boolean,default:false},
onClick: { type: Function as PropType<(...args) => any>, default: null }, 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 { try {
setModalProps({ confirmLoading: true }); setModalProps({ confirmLoading: true });
const result = await uploadApi({ name: 'file', file: blob, filename }); 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(); closeModal();
} finally { } finally {
setModalProps({ confirmLoading: false }); setModalProps({ confirmLoading: false });

View File

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

View File

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

View File

@ -1,11 +1,11 @@
<template> <template>
<div> <div>
<input <input
ref="inputRef" ref="inputRef"
type="file" type="file"
v-show="false" v-show="false"
accept=".xlsx, .xls" accept=".xlsx, .xls"
@change="handleInputClick" @change="handleInputClick"
/> />
<div @click="handleUpload"> <div @click="handleUpload">
<slot></slot> <slot></slot>
@ -15,12 +15,25 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, unref } from 'vue'; import { defineComponent, ref, unref } from 'vue';
import XLSX from 'xlsx'; import XLSX from 'xlsx';
import { dateUtil } from '/@/utils/dateUtil';
import type { ExcelData } from './typing'; import type { ExcelData } from './typing';
export default defineComponent({ export default defineComponent({
name: 'ImportExcel', 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'], emits: ['success', 'error'],
setup(_, { emit }) { setup(props, { emit }) {
const inputRef = ref<HTMLInputElement | null>(null); const inputRef = ref<HTMLInputElement | null>(null);
const loadingRef = ref<Boolean>(false); const loadingRef = ref<Boolean>(false);
@ -51,10 +64,28 @@
*/ */
function getExcelData(workbook: XLSX.WorkBook) { function getExcelData(workbook: XLSX.WorkBook) {
const excelData: ExcelData[] = []; const excelData: ExcelData[] = [];
const { dateFormat, timeZone } = props;
for (const sheetName of workbook.SheetNames) { for (const sheetName of workbook.SheetNames) {
const worksheet = workbook.Sheets[sheetName]; const worksheet = workbook.Sheets[sheetName];
const header: string[] = getHeaderRow(worksheet); 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({ excelData.push({
header, header,
results, results,
@ -76,7 +107,7 @@
reader.onload = async (e) => { reader.onload = async (e) => {
try { try {
const data = e.target && e.target.result; 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); // console.log(workbook);
/* DO SOMETHING WITH workbook HERE */ /* DO SOMETHING WITH workbook HERE */
const excelData = getExcelData(workbook); 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 { useForm } from './src/hooks/useForm';
export { default as ApiSelect } from './src/components/ApiSelect.vue'; 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 RadioButtonGroup } from './src/components/RadioButtonGroup.vue';
export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.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 }; export { BasicForm };

View File

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

View File

@ -20,15 +20,42 @@ import {
Rate, Rate,
Divider, Divider,
} from 'ant-design-vue'; } from 'ant-design-vue';
import ApiRadioGroup from './components/ApiRadioGroup.vue';
import RadioButtonGroup from './components/RadioButtonGroup.vue'; import RadioButtonGroup from './components/RadioButtonGroup.vue';
import ApiSelect from './components/ApiSelect.vue'; import ApiSelect from './components/ApiSelect.vue';
import JAreaLinkage from './components/JAreaLinkage.vue';
import ApiTreeSelect from './components/ApiTreeSelect.vue'; import ApiTreeSelect from './components/ApiTreeSelect.vue';
import { BasicUpload } from '/@/components/Upload'; import { BasicUpload } from '/@/components/Upload';
import { StrengthMeter } from '/@/components/StrengthMeter'; import { StrengthMeter } from '/@/components/StrengthMeter';
import { IconPicker } from '/@/components/Icon'; import { IconPicker } from '/@/components/Icon';
import { CountdownInput } from '/@/components/CountDown'; 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>(); const componentMap = new Map<ComponentType, Component>();
@ -42,9 +69,9 @@ componentMap.set('AutoComplete', AutoComplete);
componentMap.set('Select', Select); componentMap.set('Select', Select);
componentMap.set('ApiSelect', ApiSelect); componentMap.set('ApiSelect', ApiSelect);
componentMap.set('JAreaLinkage', JAreaLinkage);
componentMap.set('TreeSelect', TreeSelect); componentMap.set('TreeSelect', TreeSelect);
componentMap.set('ApiTreeSelect', ApiTreeSelect); componentMap.set('ApiTreeSelect', ApiTreeSelect);
componentMap.set('ApiRadioGroup', ApiRadioGroup);
componentMap.set('Switch', Switch); componentMap.set('Switch', Switch);
componentMap.set('RadioButtonGroup', RadioButtonGroup); componentMap.set('RadioButtonGroup', RadioButtonGroup);
componentMap.set('RadioGroup', Radio.Group); componentMap.set('RadioGroup', Radio.Group);
@ -66,6 +93,35 @@ componentMap.set('InputCountDown', CountdownInput);
componentMap.set('Upload', BasicUpload); componentMap.set('Upload', BasicUpload);
componentMap.set('Divider', Divider); 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) { export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, 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> <template>
<Select <Select
@dropdownVisibleChange="handleFetch" @dropdownVisibleChange="handleFetch"
v-bind="attrs" v-bind="$attrs"
@change="handleChange" @change="handleChange"
:options="getOptions" :options="getOptions"
v-model:value="state" v-model:value="state"
@ -41,12 +41,7 @@
}, },
inheritAttrs: false, inheritAttrs: false,
props: { props: {
value: propTypes.oneOfType([ value: [Array, Object, String, Number],
propTypes.object,
propTypes.number,
propTypes.string,
propTypes.array,
]),
numberToString: propTypes.bool, numberToString: propTypes.bool,
api: { api: {
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>, type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
@ -73,18 +68,17 @@
const { t } = useI18n(); const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification // 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 getOptions = computed(() => {
const { labelField, valueField, numberToString } = props; const { labelField, valueField, numberToString } = props;
return unref(options).reduce((prev, next: Recordable) => { return unref(options).reduce((prev, next: Recordable) => {
if (next) { if (next) {
const value = next[valueField]; const value = next[valueField];
prev.push({ prev.push({
label: next[labelField], ...omit(next, [labelField, valueField]),
value: numberToString ? `${value}` : value, label: next[labelField],
...omit(next, [labelField, valueField]), value: numberToString ? `${value}` : value,
}); });
} }
return prev; return prev;
@ -123,6 +117,9 @@
console.warn(error); console.warn(error);
} finally { } finally {
loading.value = false; 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( watch(
() => props.params, () => props.params,
() => { () => {
isFirstLoaded.value && fetch(); !unref(isFirstLoaded) && fetch();
}, },
{ deep: true } { deep: true }
); );

View File

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

View File

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

View File

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

View File

@ -1,117 +1,136 @@
import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form'; import type { FormProps, FormActionType, UseFormReturnType, FormSchema } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface'; import type { NamePath } from 'ant-design-vue/lib/form/interface';
import type { DynamicProps } from '/#/utils'; import type { DynamicProps } from '/#/utils';
import { handleRangeValue } from '../utils/formUtils';
import { ref, onUnmounted, unref, nextTick, watch } from 'vue'; import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
import { isProdMode } from '/@/utils/env'; import { isProdMode } from '/@/utils/env';
import { error } from '/@/utils/log'; import { error } from '/@/utils/log';
import { getDynamicProps } from '/@/utils'; import { getDynamicProps, getValueType } from '/@/utils';
export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>; export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordable>;
type Props = Partial<DynamicProps<FormProps>>; type Props = Partial<DynamicProps<FormProps>>;
export function useForm(props?: Props): UseFormReturnType { export function useForm(props?: Props): UseFormReturnType {
const formRef = ref<Nullable<FormActionType>>(null); const formRef = ref<Nullable<FormActionType>>(null);
const loadedRef = ref<Nullable<boolean>>(false); const loadedRef = ref<Nullable<boolean>>(false);
async function getForm() { async function getForm() {
const form = unref(formRef); const form = unref(formRef);
if (!form) { if (!form) {
error( error(
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!' '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) { function register(instance: FormActionType) {
isProdMode() && isProdMode() &&
onUnmounted(() => { onUnmounted(() => {
formRef.value = null; formRef.value = null;
loadedRef.value = null; loadedRef.value = null;
}); });
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return; if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
formRef.value = instance; formRef.value = instance;
loadedRef.value = true; loadedRef.value = true;
watch( watch(
() => props, () => props,
() => { () => {
props && instance.setProps(getDynamicProps(props)); props && instance.setProps(getDynamicProps(props));
}, },
{ {
immediate: true, immediate: true,
deep: true, deep: true,
} }
); );
} }
const methods: FormActionType = { const methods: FormActionType = {
scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => { scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
const form = await getForm(); const form = await getForm();
form.scrollToField(name, options); form.scrollToField(name, options);
}, },
setProps: async (formProps: Partial<FormProps>) => { setProps: async (formProps: Partial<FormProps>) => {
const form = await getForm(); const form = await getForm();
form.setProps(formProps); form.setProps(formProps);
}, },
updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => { updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm(); const form = await getForm();
form.updateSchema(data); form.updateSchema(data);
}, },
resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => { resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
const form = await getForm(); const form = await getForm();
form.resetSchema(data); form.resetSchema(data);
}, },
clearValidate: async (name?: string | string[]) => { clearValidate: async (name?: string | string[]) => {
const form = await getForm(); const form = await getForm();
form.clearValidate(name); form.clearValidate(name);
}, },
resetFields: async () => { resetFields: async () => {
getForm().then(async (form) => { getForm().then(async (form) => {
await form.resetFields(); await form.resetFields();
}); });
}, },
removeSchemaByFiled: async (field: string | string[]) => { removeSchemaByFiled: async (field: string | string[]) => {
unref(formRef)?.removeSchemaByFiled(field); unref(formRef)?.removeSchemaByFiled(field);
}, },
// TODO promisify // TODO promisify
getFieldsValue: <T>() => { getFieldsValue: <T>() => {
return unref(formRef)?.getFieldsValue() as T; return unref(formRef)?.getFieldsValue() as T;
}, },
setFieldsValue: async <T>(values: T) => { setFieldsValue: async <T>(values: T) => {
const form = await getForm(); const form = await getForm();
form.setFieldsValue<T>(values); form.setFieldsValue<T>(values);
}, },
appendSchemaByField: async ( appendSchemaByField: async (
schema: FormSchema, schema: FormSchema,
prefixField: string | undefined, prefixField: string | undefined,
first: boolean first: boolean
) => { ) => {
const form = await getForm(); const form = await getForm();
form.appendSchemaByField(schema, prefixField, first); form.appendSchemaByField(schema, prefixField, first);
}, },
submit: async (): Promise<any> => { submit: async (): Promise<any> => {
const form = await getForm(); const form = await getForm();
return form.submit(); return form.submit();
}, },
/**
*
* @update:
* @updateBy:zyf
* @updateDate:2021-09-02
*/
validate: async (nameList?: NamePath[]): Promise<Recordable> => { validate: async (nameList?: NamePath[]): Promise<Recordable> => {
const form = await getForm(); 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> => { validateFields: async (nameList?: NamePath[]): Promise<Recordable> => {
const form = await getForm(); const form = await getForm();
return form.validateFields(nameList); 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 type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw } from 'vue'; import { unref, toRaw } from 'vue';
import { isArray, isFunction, isObject, isString } from '/@/utils/is'; import { isArray, isFunction, isObject, isString } from '/@/utils/is';
import { deepMerge } from '/@/utils'; import { deepMerge, getValueType } from '/@/utils';
import { dateItemType, handleInputNumberValue } from '../helper'; import { dateItemType, handleInputNumberValue } from '../helper';
import { dateUtil } from '/@/utils/dateUtil'; import { dateUtil } from '/@/utils/dateUtil';
import { cloneDeep, uniqBy } from 'lodash-es'; import { cloneDeep, uniqBy } from 'lodash-es';
@ -240,6 +240,17 @@ export function useFormEvents({
if (!formEl) return; if (!formEl) return;
try { try {
const values = await validate(); 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); const res = handleFormValues(values);
emit('submit', res); emit('submit', res);
} catch (error) { } catch (error) {

View File

@ -4,6 +4,7 @@ import { unref } from 'vue';
import type { Ref, ComputedRef } from 'vue'; import type { Ref, ComputedRef } from 'vue';
import type { FormProps, FormSchema } from '../types/form'; import type { FormProps, FormSchema } from '../types/form';
import { set } from 'lodash-es'; import { set } from 'lodash-es';
import { handleRangeValue } from '/@/components/Form/src/utils/formUtils';
interface UseFormValuesContext { interface UseFormValuesContext {
defaultValueRef: Ref<any>; defaultValueRef: Ref<any>;
@ -42,33 +43,9 @@ export function useFormValues({
} }
set(res, key, value); 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() { function initDefault() {
const schemas = unref(getSchema); const schemas = unref(getSchema);

View File

@ -16,8 +16,14 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
wrapperCol: globWrapperCol, wrapperCol: globWrapperCol,
} = unref(propsRef); } = 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 labelWidth is set globally, all items setting
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { if ((!globalLabelWidth && !labelWidth && !globalLabelCol)) {
labelCol.style = { labelCol.style = {
textAlign: 'left', 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"> <script lang="ts">
import {defineComponent, PropType, ref,reactive, watchEffect, computed, unref, watch, onMounted} from 'vue'; import {defineComponent, PropType, ref,reactive, watchEffect, computed, unref, watch, onMounted} from 'vue';
import {Cascader} from 'ant-design-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 {useRuleFormItem} from "/@/hooks/component/useFormItem";
import {propTypes} from "/@/utils/propTypes"; import {propTypes} from "/@/utils/propTypes";
import {useAttrs} from "/@/hooks/core/useAttrs"; 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