提交 46e08753 作者: vben

chore: add some notes

上级 815250ed
...@@ -138,6 +138,7 @@ ...@@ -138,6 +138,7 @@
// "vetur.format.defaultFormatter.html": "prettyhtml", // "vetur.format.defaultFormatter.html": "prettyhtml",
"vetur.format.defaultFormatter.ts": "prettier-tslint", "vetur.format.defaultFormatter.ts": "prettier-tslint",
"vetur.format.defaultFormatter.js": "prettier", "vetur.format.defaultFormatter.js": "prettier",
"vetur.languageFeatures.codeActions": false,
// "vetur.useWorkspaceDependencies": true, // "vetur.useWorkspaceDependencies": true,
"vetur.format.defaultFormatterOptions": { "vetur.format.defaultFormatterOptions": {
"js-beautify-html": { "js-beautify-html": {
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
### 🎫 Chores ### 🎫 Chores
- 更新 antdv 到`2.0.0-rc.1` - 更新 antdv 到`2.0.0-rc.1`(暂时还原到 beta15,rc1 菜单卡顿太严重.)
- 添加部分注释
### 🐛 Bug Fixes ### 🐛 Bug Fixes
......
// 修改自 // Modified from
// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts // https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
// TODO 目前还不能监听文件新增及删除 内容已经改变,缓存问题? // TODO Currently, it is not possible to monitor file addition and deletion. The content has been changed, the cache problem?
import { join } from 'path'; import { join } from 'path';
import { lstatSync } from 'fs'; import { lstatSync } from 'fs';
import glob from 'glob'; import glob from 'glob';
......
...@@ -4,11 +4,11 @@ import { resultSuccess } from '../_util'; ...@@ -4,11 +4,11 @@ import { resultSuccess } from '../_util';
const userInfo = { const userInfo = {
name: 'Vben', name: 'Vben',
userid: '00000001', userid: '00000001',
email: 'antdesign@alipay.com', email: 'test@gmail.com',
signature: '海纳百川,有容乃大', signature: '海纳百川,有容乃大',
introduction: '微笑着,努力着,欣赏着', introduction: '微笑着,努力着,欣赏着',
title: '交互专家', title: '交互专家',
group: '蚂蚁集团11-某某某事业群-某某平台部-某某技术部-UED', group: '某某某事业群-某某平台部-某某技术部-UED',
tags: [ tags: [
{ {
key: '0', key: '0',
...@@ -38,7 +38,7 @@ const userInfo = { ...@@ -38,7 +38,7 @@ const userInfo = {
notifyCount: 12, notifyCount: 12,
unreadCount: 11, unreadCount: 11,
country: 'China', country: 'China',
address: '厦门市 77 号', address: 'Xiamen City 77',
phone: '0592-268888888', phone: '0592-268888888',
}; };
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
}, },
"dependencies": { "dependencies": {
"@iconify/iconify": "^2.0.0-rc.2", "@iconify/iconify": "^2.0.0-rc.2",
"@vueuse/core": "^4.0.0-beta.41", "@vueuse/core": "4.0.0-beta.41",
"ant-design-vue": "^2.0.0-rc.1", "ant-design-vue": "2.0.0-beta.15",
"apexcharts": "3.22.0", "apexcharts": "3.22.0",
"axios": "^0.21.0", "axios": "^0.21.0",
"echarts": "^4.9.0", "echarts": "^4.9.0",
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"vditor": "^3.6.2", "vditor": "^3.6.2",
"vue": "^3.0.2", "vue": "^3.0.2",
"vue-i18n": "^9.0.0-beta.6", "vue-i18n": "^9.0.0-beta.7",
"vue-router": "^4.0.0-rc.3", "vue-router": "^4.0.0-rc.3",
"vuex": "^4.0.0-rc.1", "vuex": "^4.0.0-rc.1",
"vuex-module-decorators": "^1.0.1", "vuex-module-decorators": "^1.0.1",
...@@ -45,10 +45,10 @@ ...@@ -45,10 +45,10 @@
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^11.0.0", "@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0", "@commitlint/config-conventional": "^11.0.0",
"@iconify/json": "^1.1.258", "@iconify/json": "^1.1.260",
"@ls-lint/ls-lint": "^1.9.2", "@ls-lint/ls-lint": "^1.9.2",
"@purge-icons/generated": "^0.4.1", "@purge-icons/generated": "^0.4.1",
"@types/echarts": "^4.9.0", "@types/echarts": "^4.9.1",
"@types/fs-extra": "^9.0.4", "@types/fs-extra": "^9.0.4",
"@types/koa-static": "^4.0.1", "@types/koa-static": "^4.0.1",
"@types/lodash-es": "^4.17.3", "@types/lodash-es": "^4.17.3",
...@@ -56,10 +56,10 @@ ...@@ -56,10 +56,10 @@
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/qrcode": "^1.3.5", "@types/qrcode": "^1.3.5",
"@types/rollup-plugin-visualizer": "^2.6.0", "@types/rollup-plugin-visualizer": "^2.6.0",
"@types/yargs": "^15.0.9", "@types/yargs": "^15.0.10",
"@types/zxcvbn": "^4.4.0", "@types/zxcvbn": "^4.4.0",
"@typescript-eslint/eslint-plugin": "^4.6.1", "@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.6.1", "@typescript-eslint/parser": "^4.8.1",
"@vue/compiler-sfc": "^3.0.2", "@vue/compiler-sfc": "^3.0.2",
"@vuedx/typecheck": "^0.2.4-0", "@vuedx/typecheck": "^0.2.4-0",
"@vuedx/typescript-plugin-vue": "^0.2.4-0", "@vuedx/typescript-plugin-vue": "^0.2.4-0",
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
"prettier": "^2.1.2", "prettier": "^2.1.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^4.1.2", "rollup-plugin-visualizer": "^4.1.2",
"stylelint": "^13.7.2", "stylelint": "^13.8.0",
"stylelint-config-prettier": "^8.0.2", "stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^20.0.0", "stylelint-config-standard": "^20.0.0",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
......
/*
* @Author: Vben
* @Description:
*/
module.exports = { module.exports = {
printWidth: 100, printWidth: 100,
tabWidth: 2, tabWidth: 2,
......
...@@ -33,20 +33,17 @@ ...@@ -33,20 +33,17 @@
</style> </style>
<circle cx="97" cy="97" r="81" stroke-width="16" stroke="#327fd8" fill="none"></circle> <circle cx="97" cy="97" r="81" stroke-width="16" stroke="#327fd8" fill="none"></circle>
<g class="load"> <g class="load">
<!--右半圆环-->
<linearGradient id="left-linear" gradientUnits="userSpaceOnUse" x1="50" y1="0" x2="100" y2="180"> <linearGradient id="left-linear" gradientUnits="userSpaceOnUse" x1="50" y1="0" x2="100" y2="180">
<stop offset="0" style="stop-color: #64acff;" /> <stop offset="0" style="stop-color: #64acff;" />
<stop offset="1" style="stop-color: #9DBFE4;" /> <stop offset="1" style="stop-color: #9DBFE4;" />
</linearGradient> </linearGradient>
<path class="left-linear" d="M20,100c0-44.1,35.9-80,80-80V0C44.8,0,0,44.8,0,100s44.8,100,100,100v-20C55.9,180,20,144.1,20,100z" /> <path class="left-linear" d="M20,100c0-44.1,35.9-80,80-80V0C44.8,0,0,44.8,0,100s44.8,100,100,100v-20C55.9,180,20,144.1,20,100z" />
<!--左半圆环-->
<circle class="bottom" cx="100" cy="190" r="10" /> <circle class="bottom" cx="100" cy="190" r="10" />
<linearGradient id="right-linear" gradientUnits="userSpaceOnUse" x1="100" y1="120" x2="100" y2="180"> <linearGradient id="right-linear" gradientUnits="userSpaceOnUse" x1="100" y1="120" x2="100" y2="180">
<stop offset="0" style="stop-color: transparent;" /> <stop offset="0" style="stop-color: transparent;" />
<stop offset="1" style="stop-color: transparent;" /> <stop offset="1" style="stop-color: transparent;" />
</linearGradient> </linearGradient>
<path class="right-linear" d="M100,0v20c44.1,0,80,35.9,80,80c0,44.1-35.9,80-80,80v20c55.2,0,100-44.8,100-100S155.2,0,100,0z" /> <path class="right-linear" d="M100,0v20c44.1,0,80,35.9,80,80c0,44.1-35.9,80-80,80v20c55.2,0,100-44.8,100-100S155.2,0,100,0z" />
<!--左半圆环-->
<circle class="top" cx="100" cy="10" r="10" /> <circle class="top" cx="100" cy="10" r="10" />
</g> </g>
</svg> </svg>
<template> <template>
<ConfigProvider :locale="zhCN" :transform-cell-text="transformCellText" v-bind="lockOn"> <ConfigProvider v-bind="lockEvent" :locale="zhCN" :transform-cell-text="transformCellText">
<router-view /> <router-view />
</ConfigProvider> </ConfigProvider>
</template> </template>
...@@ -13,9 +13,8 @@ ...@@ -13,9 +13,8 @@
import moment from 'moment'; import moment from 'moment';
import 'moment/dist/locale/zh-cn'; import 'moment/dist/locale/zh-cn';
import { useConfigProvider, useInitAppConfigStore } from './useApp'; import { getConfigProvider, initAppConfigStore } from '/@/setup/Application';
import { useLockPage } from '/@/hooks/web/useLockPage'; import { useLockPage } from '/@/hooks/web/useLockPage';
import { useSetting } from '/@/hooks/core/useSetting';
moment.locale('zh-cn'); moment.locale('zh-cn');
...@@ -23,26 +22,22 @@ ...@@ -23,26 +22,22 @@
name: 'App', name: 'App',
components: { ConfigProvider }, components: { ConfigProvider },
setup() { setup() {
// Initialize application settings // Initialize vuex internal system configuration
useInitAppConfigStore(); initAppConfigStore();
// Initialize breakpoint monitoring
// Create a global breakpoint monitor
createBreakpointListen(); createBreakpointListen();
// Get system configuration
const { projectSetting } = useSetting();
// Get ConfigProvider configuration // Get ConfigProvider configuration
const { transformCellText } = useConfigProvider(); const { transformCellText } = getConfigProvider();
let lockOn = {}; // Create a lock screen monitor
if (projectSetting.lockTime) { const lockEvent = useLockPage();
// Monitor the mouse or keyboard time, used to recalculate the lock screen time
const { on } = useLockPage();
lockOn = on;
}
return { return {
transformCellText, transformCellText,
zhCN, zhCN,
lockOn, lockEvent,
}; };
}, },
}); });
......
...@@ -5,7 +5,7 @@ enum Api { ...@@ -5,7 +5,7 @@ enum Api {
ACCOUNT_INFO = '/account/getAccountInfo', ACCOUNT_INFO = '/account/getAccountInfo',
} }
// 获取个人中心--基础设置内容 // Get personal center-basic settings
export function accountInfoApi() { export function accountInfoApi() {
return defHttp.request<GetAccountInfoModel>({ return defHttp.request<GetAccountInfoModel>({
url: Api.ACCOUNT_INFO, url: Api.ACCOUNT_INFO,
......
...@@ -7,7 +7,7 @@ enum Api { ...@@ -7,7 +7,7 @@ enum Api {
} }
/** /**
* @description: 根据id获取用户菜单 * @description: Get user menu based on id
*/ */
export function getMenuListById(params: getMenuListByIdParams) { export function getMenuListById(params: getMenuListByIdParams) {
return defHttp.request<getMenuListByIdParamsResultModel>({ return defHttp.request<getMenuListByIdParamsResultModel>({
......
...@@ -11,13 +11,13 @@ export interface RouteItem { ...@@ -11,13 +11,13 @@ export interface RouteItem {
} }
/** /**
* @description: 获取菜单接口 * @description: Get menu interface
*/ */
export interface getMenuListByIdParams { export interface getMenuListByIdParams {
id: number | string; id: number | string;
} }
/** /**
* @description: 获取菜单返回值 * @description: Get menu return value
*/ */
export type getMenuListByIdParamsResultModel = RouteItem[]; export type getMenuListByIdParamsResultModel = RouteItem[];
...@@ -7,7 +7,7 @@ enum Api { ...@@ -7,7 +7,7 @@ enum Api {
} }
/** /**
* @description: 上传接口 * @description: Upload interface
*/ */
export function uploadApi( export function uploadApi(
params: UploadFileParams, params: UploadFileParams,
......
import type { App } from 'vue';
import Authority from './src/index.vue'; import Authority from './src/index.vue';
export default Authority;
export default (app: App): void => {
app.component(Authority.name, Authority);
};
export { Authority };
<!--
* @Author: Vben
* @Description:Access control component for fine-grained access control.
-->
<script lang="ts"> <script lang="ts">
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { defineComponent, computed, unref } from 'vue'; import { defineComponent, computed, unref } from 'vue';
import { PermissionModeEnum } from '/@/enums/appEnum'; import { PermissionModeEnum } from '/@/enums/appEnum';
import { RoleEnum } from '/@/enums/roleEnum'; import { RoleEnum } from '/@/enums/roleEnum';
import { usePermission } from '/@/hooks/web/usePermission'; import { usePermission } from '/@/hooks/web/usePermission';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { getSlot } from '/@/utils/helper/tsxHelper'; import { getSlot } from '/@/utils/helper/tsxHelper';
export default defineComponent({ export default defineComponent({
name: 'Authority', name: 'Authority',
props: { props: {
// 指定角色可见 /**
* Specified role is visible
* When the permission mode is the role mode, the value value can pass the role value.
* When the permission mode is background, the value value can pass the code permission value
* @default ''
*/
value: { value: {
type: [Number, Array, String] as PropType<RoleEnum | RoleEnum[] | string | string[]>, type: [Number, Array, String] as PropType<RoleEnum | RoleEnum[] | string | string[]>,
default: '', default: '',
...@@ -23,7 +34,7 @@ ...@@ -23,7 +34,7 @@
}); });
/** /**
* 渲染角色按钮 * Render role button
*/ */
function renderRoleAuth() { function renderRoleAuth() {
const { value } = props; const { value } = props;
...@@ -34,10 +45,8 @@ ...@@ -34,10 +45,8 @@
return hasPermission(value) ? getSlot(slots) : null; return hasPermission(value) ? getSlot(slots) : null;
} }
/** // Render coding button
* 渲染编码按钮 // Here only judge whether it is included, the specific implementation can be written according to the project logic
* 这里只判断是否包含,具体实现可以根据项目自行写逻辑
*/
function renderCodeAuth() { function renderCodeAuth() {
const { value } = props; const { value } = props;
if (!value) { if (!value) {
...@@ -49,12 +58,12 @@ ...@@ -49,12 +58,12 @@
return () => { return () => {
const mode = unref(getModeRef); const mode = unref(getModeRef);
// 基于角色渲染 // Role-based value control
if (mode === PermissionModeEnum.ROLE) { if (mode === PermissionModeEnum.ROLE) {
return renderRoleAuth(); return renderRoleAuth();
} }
// 基于后台编码渲染 // Based on background role permission control
if (mode === PermissionModeEnum.BACK) { if (mode === PermissionModeEnum.BACK) {
return renderCodeAuth(); return renderCodeAuth();
} }
......
<!--
* @Author: Vben
* @Description: Arrow component with animation
-->
<template> <template>
<span :class="getClass"> <span :class="getClass">
<RightOutlined /> <RightOutlined />
......
...@@ -71,9 +71,6 @@ ...@@ -71,9 +71,6 @@
return props.absolute ? props.position : {}; return props.absolute ? props.position : {};
}); });
/**
* @description: 渲染内容
*/
const renderTitle = () => { const renderTitle = () => {
const list = props.text; const list = props.text;
if (isString(list)) { if (isString(list)) {
...@@ -89,6 +86,7 @@ ...@@ -89,6 +86,7 @@
return () => { return () => {
return h( return h(
// @ts-ignores
Tooltip, Tooltip,
{ {
title: h( title: h(
......
...@@ -12,33 +12,19 @@ ...@@ -12,33 +12,19 @@
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue';
import { Button } from 'ant-design-vue'; import { Button } from 'ant-design-vue';
// import { extendSlots } from '/@/utils/helper/tsxHelper';
// import { useThrottle } from '/@/hooks/core/useThrottle';
// import { isFunction } from '/@/utils/is';
import Icon from '/@/components/Icon'; import Icon from '/@/components/Icon';
export default defineComponent({ export default defineComponent({
name: 'AButton', name: 'AButton',
inheritAttrs: false, inheritAttrs: false,
components: { Button, Icon }, components: { Button, Icon },
props: { props: {
// 按钮类型
type: { type: {
type: String as PropType<'primary' | 'default' | 'danger' | 'dashed' | 'link'>, type: String as PropType<'primary' | 'default' | 'danger' | 'dashed' | 'link'>,
default: 'default', default: 'default',
}, },
// 节流防抖类型 throttle debounce
// throttle: {
// type: String as PropType<'throttle' | 'debounce'>,
// default: 'throttle',
// },
color: { color: {
type: String as PropType<'error' | 'warning' | 'success' | ''>, type: String as PropType<'error' | 'warning' | 'success' | ''>,
}, },
// // 防抖节流时间
// throttleTime: {
// type: Number as PropType<number>,
// default: 50,
// },
loading: { loading: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: false, default: false,
...@@ -58,42 +44,15 @@ ...@@ -58,42 +44,15 @@
const getIsCircleBtn = computed(() => { const getIsCircleBtn = computed(() => {
return attrs.shape === 'circle'; return attrs.shape === 'circle';
}); });
// const getListeners = computed(() => {
// const { throttle, throttleTime = 0 } = props;
// // 是否开启节流防抖
// const throttleType = throttle!.toLowerCase();
// const isDebounce = throttleType === 'debounce';
// const openThrottle = ['throttle', 'debounce'].includes(throttleType) && throttleTime > 0;
// if (!openThrottle) {
// return {
// ...attrs,
// };
// }
// const on: {
// onClick?: Fn;
// } = {};
// if (attrs.onClick && isFunction(attrs.onClick) && openThrottle) {
// const [handler] = useThrottle(attrs.onClick as any, throttleTime!, {
// debounce: isDebounce,
// immediate: false,
// });
// on.onClick = handler;
// }
// return {
// ...attrs,
// ...on,
// };
// });
const getColor = computed(() => { const getColor = computed(() => {
const res: string[] = [];
const { color, disabled } = props; const { color, disabled } = props;
color && res.push(`ant-btn-${color}`); return [
disabled && res.push('is-disabled'); {
return res; [`ant-btn-${color}`]: !!color,
[`is-disabled`]: disabled,
},
];
}); });
const getBindValue = computed((): any => { const getBindValue = computed((): any => {
......
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue'; import { defineComponent, reactive, onMounted, ref, toRef, toRefs } from 'vue';
import { Skeleton } from 'ant-design-vue'; import { Skeleton } from 'ant-design-vue';
import { useTimeoutFn, useIntersectionObserver } from '@vueuse/core'; import { useTimeoutFn } from '@vueuse/core';
import { useIntersectionObserver } from '/@/hooks/event/useIntersectionObserver';
interface State { interface State {
isInit: boolean; isInit: boolean;
loading: boolean; loading: boolean;
......
...@@ -43,23 +43,22 @@ ...@@ -43,23 +43,22 @@
}, },
name: 'CollapseContainer', name: 'CollapseContainer',
props: { props: {
// 标题
title: { title: {
type: String as PropType<string>, type: String as PropType<string>,
default: '', default: '',
}, },
// 是否可以展开 // Can it be expanded
canExpan: { canExpan: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: true, default: true,
}, },
// 标题右侧温馨提醒 // Warm reminder on the right side of the title
helpMessage: { helpMessage: {
type: [Array, String] as PropType<string[] | string>, type: [Array, String] as PropType<string[] | string>,
default: '', default: '',
}, },
// 展开收缩的时候是否触发window.resize, // Whether to trigger window.resize when expanding and contracting,
// 可以适应表格和表单,当表单收缩起来,表格触发resize 自适应高度 // Can adapt to tables and forms, when the form shrinks, the form triggers resize to adapt to the height
triggerWindowResize: { triggerWindowResize: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: false, default: false,
...@@ -68,12 +67,12 @@ ...@@ -68,12 +67,12 @@
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: false, default: false,
}, },
// 延时加载 // Delayed loading
lazy: { lazy: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: false, default: false,
}, },
// 延时加载时间 // Delayed loading time
lazyTime: { lazyTime: {
type: Number as PropType<number>, type: Number as PropType<number>,
default: 0, default: 0,
...@@ -82,14 +81,14 @@ ...@@ -82,14 +81,14 @@
setup(props) { setup(props) {
const showRef = ref(true); const showRef = ref(true);
/** /**
* @description: 处理开展事件 * @description: Handling development events
*/ */
function handleExpand() { function handleExpand() {
const hasShow = !unref(showRef); const hasShow = !unref(showRef);
showRef.value = hasShow; showRef.value = hasShow;
if (props.triggerWindowResize) { if (props.triggerWindowResize) {
// 这里200毫秒是因为展开有动画, // 200 milliseconds here is because the expansion has animation,
useTimeoutFn(triggerWindowResize, 200); useTimeoutFn(triggerWindowResize, 200);
} }
} }
......
...@@ -9,25 +9,23 @@ export const props = { ...@@ -9,25 +9,23 @@ export const props = {
type: Object as PropType<Event>, type: Object as PropType<Event>,
default: null, default: null,
}, },
// 样式
styles: { styles: {
type: Object as PropType<any>, type: Object as PropType<any>,
default: null, default: null,
}, },
showIcon: { showIcon: {
// 是否显示icon
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
default: true, default: true,
}, },
axis: { axis: {
// 鼠标右键点击的位置 // The position of the right mouse button click
type: Object as PropType<Axis>, type: Object as PropType<Axis>,
default() { default() {
return { x: 0, y: 0 }; return { x: 0, y: 0 };
}, },
}, },
items: { items: {
// 最重要的列表,没有的话直接不显示 // The most important list, if not, will not be displayed
type: Array as PropType<ContextMenuItem[]>, type: Array as PropType<ContextMenuItem[]>,
default() { default() {
return []; return [];
......
// 对vue-count-to进行改造成支持vue3版本 // Transform vue-count-to to support vue3 version
export { default as CountTo } from './src/index.vue'; export { default as CountTo } from './src/index.vue';
...@@ -14,9 +14,8 @@ export default defineComponent({ ...@@ -14,9 +14,8 @@ export default defineComponent({
props: descProps, props: descProps,
emits: ['register'], emits: ['register'],
setup(props, { attrs, slots, emit }) { setup(props, { attrs, slots, emit }) {
// props来自设置
const propsRef = ref<Partial<DescOptions> | null>(null); const propsRef = ref<Partial<DescOptions> | null>(null);
// 自定义title组件:获得title // Custom title component: get title
const getMergeProps = computed(() => { const getMergeProps = computed(() => {
return { return {
...props, ...props,
...@@ -34,19 +33,19 @@ export default defineComponent({ ...@@ -34,19 +33,19 @@ export default defineComponent({
}); });
/** /**
* @description: 是否使用标题 * @description: Whether to use title
*/ */
const useWrapper = computed(() => { const useWrapper = computed(() => {
return !!unref(getMergeProps).title; return !!unref(getMergeProps).title;
}); });
/** /**
* @description: 获取配置Collapse * @description: Get configuration Collapse
*/ */
const getCollapseOptions = computed( const getCollapseOptions = computed(
(): CollapseContainerOptions => { (): CollapseContainerOptions => {
return { return {
// 默认不能展开 // Cannot be expanded by default
canExpand: false, canExpand: false,
...unref(getProps).collapseOptions, ...unref(getProps).collapseOptions,
}; };
...@@ -57,7 +56,7 @@ export default defineComponent({ ...@@ -57,7 +56,7 @@ export default defineComponent({
* @description:设置desc * @description:设置desc
*/ */
function setDescProps(descProps: Partial<DescOptions>): void { function setDescProps(descProps: Partial<DescOptions>): void {
// 保留上一次的setDrawerProps // Keep the last setDrawerProps
const mergeProps = deepMerge(unref(propsRef) || {}, descProps); const mergeProps = deepMerge(unref(propsRef) || {}, descProps);
propsRef.value = cloneDeep(mergeProps); propsRef.value = cloneDeep(mergeProps);
} }
...@@ -68,7 +67,7 @@ export default defineComponent({ ...@@ -68,7 +67,7 @@ export default defineComponent({
emit('register', methods); emit('register', methods);
// 防止换行 // Prevent line breaks
function renderLabel({ label, labelMinWidth, labelStyle }: DescItem) { function renderLabel({ label, labelMinWidth, labelStyle }: DescItem) {
if (!labelStyle && !labelMinWidth) { if (!labelStyle && !labelMinWidth) {
return label; return label;
...@@ -101,7 +100,6 @@ export default defineComponent({ ...@@ -101,7 +100,6 @@ export default defineComponent({
const width = contentMinWidth; const width = contentMinWidth;
return ( return (
// @ts-ignore
<Descriptions.Item label={renderLabel(item)} key={field} span={span}> <Descriptions.Item label={renderLabel(item)} key={field} span={span}>
{() => {() =>
contentMinWidth ? ( contentMinWidth ? (
...@@ -131,7 +129,7 @@ export default defineComponent({ ...@@ -131,7 +129,7 @@ export default defineComponent({
const renderContainer = () => { const renderContainer = () => {
const content = props.useCollapse ? renderDesc() : <div>{renderDesc()}</div>; const content = props.useCollapse ? renderDesc() : <div>{renderDesc()}</div>;
// 减少dom层级 // Reduce the dom level
return props.useCollapse ? ( return props.useCollapse ? (
<CollapseContainer <CollapseContainer
title={unref(getMergeProps).title} title={unref(getMergeProps).title}
......
...@@ -2,7 +2,6 @@ import type { VNode } from 'vue'; ...@@ -2,7 +2,6 @@ import type { VNode } from 'vue';
import type { CollapseContainerOptions } from '/@/components/Container/index'; import type { CollapseContainerOptions } from '/@/components/Container/index';
export interface DescItem { export interface DescItem {
// 最小宽度
labelMinWidth?: number; labelMinWidth?: number;
contentMinWidth?: number; contentMinWidth?: number;
...@@ -11,7 +10,7 @@ export interface DescItem { ...@@ -11,7 +10,7 @@ export interface DescItem {
field: string; field: string;
label: any; label: any;
// 和并列 // Merge column
span?: number; span?: number;
show?: (...arg: any) => boolean; show?: (...arg: any) => boolean;
// render // render
...@@ -19,10 +18,10 @@ export interface DescItem { ...@@ -19,10 +18,10 @@ export interface DescItem {
} }
export interface DescOptions { export interface DescOptions {
// 是否包含collapse组件 // Whether to include the collapse component
useCollapse?: boolean; useCollapse?: boolean;
/** /**
* item配置 * item configuration
* @type DescItem * @type DescItem
*/ */
schema: DescItem[]; schema: DescItem[];
...@@ -32,7 +31,7 @@ export interface DescOptions { ...@@ -32,7 +31,7 @@ export interface DescOptions {
*/ */
data: any; data: any;
/** /**
* 内置的CollapseContainer组件配置 * Built-in CollapseContainer component configuration
* @type CollapseContainerOptions * @type CollapseContainerOptions
*/ */
collapseOptions?: CollapseContainerOptions; collapseOptions?: CollapseContainerOptions;
......
...@@ -71,7 +71,7 @@ export default defineComponent({ ...@@ -71,7 +71,7 @@ export default defineComponent({
} }
); );
// 底部按钮自定义实现, // Custom implementation of the bottom button,
const getFooterHeight = computed(() => { const getFooterHeight = computed(() => {
const { footerHeight, showFooter }: DrawerProps = unref(getProps); const { footerHeight, showFooter }: DrawerProps = unref(getProps);
if (showFooter && footerHeight) { if (showFooter && footerHeight) {
...@@ -80,7 +80,7 @@ export default defineComponent({ ...@@ -80,7 +80,7 @@ export default defineComponent({
return `0px`; return `0px`;
}); });
// 取消事件 // Cancel event
async function onClose(e: any) { async function onClose(e: any) {
const { closeFunc } = unref(getProps); const { closeFunc } = unref(getProps);
emit('close', e); emit('close', e);
...@@ -93,7 +93,7 @@ export default defineComponent({ ...@@ -93,7 +93,7 @@ export default defineComponent({
} }
function setDrawerProps(props: Partial<DrawerProps>): void { function setDrawerProps(props: Partial<DrawerProps>): void {
// 保留上一次的setDrawerProps // Keep the last setDrawerProps
propsRef.value = deepMerge(unref(propsRef) || {}, props); propsRef.value = deepMerge(unref(propsRef) || {}, props);
if (Reflect.has(props, 'visible')) { if (Reflect.has(props, 'visible')) {
visibleRef.value = !!props.visible; visibleRef.value = !!props.visible;
......
import type { PropType } from 'vue'; import type { PropType } from 'vue';
// import {DrawerProps} from './types'
export const footerProps = { export const footerProps = {
confirmLoading: Boolean as PropType<boolean>, confirmLoading: Boolean as PropType<boolean>,
/** /**
* @description: 显示关闭按钮 * @description: Show close button
*/ */
showCancelBtn: { showCancelBtn: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
...@@ -15,7 +14,7 @@ export const footerProps = { ...@@ -15,7 +14,7 @@ export const footerProps = {
default: '关闭', default: '关闭',
}, },
/** /**
* @description: 显示确认按钮 * @description: Show confirmation button
*/ */
showOkBtn: { showOkBtn: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
......
...@@ -73,7 +73,7 @@ export interface DrawerProps extends DrawerFooterProps { ...@@ -73,7 +73,7 @@ export interface DrawerProps extends DrawerFooterProps {
showDetailBack?: boolean; showDetailBack?: boolean;
visible?: boolean; visible?: boolean;
/** /**
* 内置的ScrollContainer组件配置 * Built-in ScrollContainer component configuration
* @type ScrollContainerOptions * @type ScrollContainerOptions
*/ */
scrollOptions?: ScrollContainerOptions; scrollOptions?: ScrollContainerOptions;
......
...@@ -22,7 +22,7 @@ import { isFunction } from '/@/utils/is'; ...@@ -22,7 +22,7 @@ import { isFunction } from '/@/utils/is';
const dataTransferRef = reactive<any>({}); const dataTransferRef = reactive<any>({});
/** /**
* @description: 适用于将drawer独立出去,外面调用 * @description: Applicable to separate drawer and call outside
*/ */
export function useDrawer(): UseDrawerReturnType { export function useDrawer(): UseDrawerReturnType {
if (!getCurrentInstance()) { if (!getCurrentInstance()) {
......
import type { PropType } from 'vue'; import type { PropType } from 'vue';
/**
* @description: 基础表格参数配置
*/
export const dropdownProps = { export const dropdownProps = {
/** /**
* the trigger mode which executes the drop-down action * the trigger mode which executes the drop-down action
...@@ -14,52 +12,6 @@ export const dropdownProps = { ...@@ -14,52 +12,6 @@ export const dropdownProps = {
return ['contextmenu']; return ['contextmenu'];
}, },
}, },
// /**
// * the dropdown menu
// * @type () => Menu
// */
// overlay: {
// type: null,
// },
// /**
// * Class name of the dropdown root element
// * @type string
// */
// overlayClassName: String,
// /**
// * Style of the dropdown root element
// * @type object
// */
// overlayStyle: Object,
// /**
// * whether the dropdown menu is visible
// * @type boolean
// */
// visible: Boolean,
// /**
// * whether the dropdown menu is disabled
// * @type boolean
// */
// disabled: Boolean,
// /**
// * to set the ontainer of the dropdown menu. The default is to create a div element in body, you can reset it to the scrolling area and make a relative reposition.
// * @default () => document.body
// * @type Function
// */
// getPopupContainer: Function,
// /**
// * placement of pop menu: bottomLeft bottomCenter bottomRight topLeft topCenter topRight
// * @default 'bottomLeft'
// * @type string
// */
// placement: String,
}; };
export const basicDropdownProps = Object.assign({}, dropdownProps, { export const basicDropdownProps = Object.assign({}, dropdownProps, {
dropMenuList: { dropMenuList: {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
<script lang="ts"> <script lang="ts">
import type { FormActionType, FormProps, FormSchema } from './types/form'; import type { FormActionType, FormProps, FormSchema } from './types/form';
import type { AdvanceState } from './types/hooks'; import type { AdvanceState } from './types/hooks';
import type { Ref } from 'vue'; import type { Ref, WatchStopHandle } from 'vue';
import type { ValidateFields } from 'ant-design-vue/lib/form/interface'; import type { ValidateFields } from 'ant-design-vue/lib/form/interface';
import { defineComponent, reactive, ref, computed, unref, toRef, onMounted, watch } from 'vue'; import { defineComponent, reactive, ref, computed, unref, toRef, onMounted, watch } from 'vue';
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
}); });
const defaultValueRef = ref<any>({}); const defaultValueRef = ref<any>({});
const isInitedDefaultRef = ref(false);
const propsRef = ref<Partial<FormProps>>({}); const propsRef = ref<Partial<FormProps>>({});
const schemaRef = ref<Nullable<FormSchema[]>>(null); const schemaRef = ref<Nullable<FormSchema[]>>(null);
const formElRef = ref<Nullable<FormActionType>>(null); const formElRef = ref<Nullable<FormActionType>>(null);
...@@ -164,16 +165,19 @@ ...@@ -164,16 +165,19 @@
} }
); );
watch( const stopWatch: WatchStopHandle = watch(
() => getSchema.value, () => getSchema.value,
() => { (schema) => {
initDefault(); if (unref(isInitedDefaultRef)) {
return stopWatch();
}
if (schema && schema.length) {
initDefault();
isInitedDefaultRef.value = true;
}
} }
); );
/**
* @description:设置表单
*/
function setProps(formProps: Partial<FormProps>): void { function setProps(formProps: Partial<FormProps>): void {
const mergeProps = deepMerge(unref(propsRef) || {}, formProps); const mergeProps = deepMerge(unref(propsRef) || {}, formProps);
propsRef.value = mergeProps; propsRef.value = mergeProps;
......
import { Component } from 'vue'; import { Component } from 'vue';
/** /**
* 组件列表,在这里注册才可以在表单使用 * Component list, register here to use it in the form
*/ */
import { import {
Input, Input,
......
...@@ -114,7 +114,7 @@ export default function ({ ...@@ -114,7 +114,7 @@ export default function ({
) { ) {
advanceState.hideAdvanceBtn = false; advanceState.hideAdvanceBtn = false;
// 大于3行默认收起 // More than 3 lines collapsed by default
} else if (!advanceState.isLoad) { } else if (!advanceState.isLoad) {
advanceState.isLoad = true; advanceState.isLoad = true;
advanceState.isAdvanced = !advanceState.isAdvanced; advanceState.isAdvanced = !advanceState.isAdvanced;
...@@ -124,7 +124,7 @@ export default function ({ ...@@ -124,7 +124,7 @@ export default function ({
if (itemColSum > BASIC_COL_LEN) { if (itemColSum > BASIC_COL_LEN) {
return { isAdvanced: advanceState.isAdvanced, itemColSum }; return { isAdvanced: advanceState.isAdvanced, itemColSum };
} else { } else {
// 第一行始终显示 // The first line is always displayed
return { isAdvanced: true, itemColSum }; return { isAdvanced: true, itemColSum };
} }
} }
......
...@@ -62,7 +62,7 @@ export function useFormAction({ ...@@ -62,7 +62,7 @@ export function useFormAction({
Object.keys(values).forEach((key) => { Object.keys(values).forEach((key) => {
const element = values[key]; const element = values[key];
if (element !== undefined && element !== null && fields.includes(key)) { if (element !== undefined && element !== null && fields.includes(key)) {
// 时间 // time type
if (itemIsDateType(key)) { if (itemIsDateType(key)) {
if (Array.isArray(element)) { if (Array.isArray(element)) {
const arr: any[] = []; const arr: any[] = [];
...@@ -84,7 +84,7 @@ export function useFormAction({ ...@@ -84,7 +84,7 @@ export function useFormAction({
// } // }
} }
/** /**
* @description: 根据字段名删除 * @description: Delete based on field name
*/ */
function removeSchemaByFiled(fields: string | string[]): void { function removeSchemaByFiled(fields: string | string[]): void {
const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
...@@ -102,7 +102,7 @@ export function useFormAction({ ...@@ -102,7 +102,7 @@ export function useFormAction({
} }
/** /**
* @description: 根据字段名删除 * @description: Delete based on field name
*/ */
function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void { function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
if (isString(field)) { if (isString(field)) {
...@@ -114,7 +114,7 @@ export function useFormAction({ ...@@ -114,7 +114,7 @@ export function useFormAction({
} }
/** /**
* @description: 往某个字段后面插入,如果没有插入最后一个 * @description: Insert after a certain field, if not insert the last
*/ */
function appendSchemaByField(schema: FormSchema, prefixField?: string) { function appendSchemaByField(schema: FormSchema, prefixField?: string) {
const schemaList: FormSchema[] = cloneDeep(unref(getSchema)); const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
...@@ -169,7 +169,7 @@ export function useFormAction({ ...@@ -169,7 +169,7 @@ export function useFormAction({
} }
/** /**
* @description: 是否是时间 * @description: Is it time
*/ */
function itemIsDateType(key: string) { function itemIsDateType(key: string) {
return unref(getSchema).some((item) => { return unref(getSchema).some((item) => {
...@@ -193,7 +193,7 @@ export function useFormAction({ ...@@ -193,7 +193,7 @@ export function useFormAction({
} }
/** /**
* @description: 表单提交 * @description: Form submission
*/ */
async function handleSubmit(e?: Event): Promise<void> { async function handleSubmit(e?: Event): Promise<void> {
e && e.preventDefault(); e && e.preventDefault();
......
...@@ -18,7 +18,7 @@ export function useFormValues({ ...@@ -18,7 +18,7 @@ export function useFormValues({
getSchema, getSchema,
formModel, formModel,
}: UseFormValuesContext) { }: UseFormValuesContext) {
// 处理表单值 // Processing form values
function handleFormValues(values: any) { function handleFormValues(values: any) {
if (!isObject(values)) { if (!isObject(values)) {
return {}; return {};
...@@ -37,7 +37,7 @@ export function useFormValues({ ...@@ -37,7 +37,7 @@ export function useFormValues({
if (isArray(value) && value[0]._isAMomentObject && value[1]._isAMomentObject) { if (isArray(value) && value[0]._isAMomentObject && value[1]._isAMomentObject) {
value = value.map((item) => transformDateFunc(item)); value = value.map((item) => transformDateFunc(item));
} }
// 去除空格 // Remove spaces
if (isString(value)) { if (isString(value)) {
value = value.trim(); value = value.trim();
} }
...@@ -47,7 +47,7 @@ export function useFormValues({ ...@@ -47,7 +47,7 @@ export function useFormValues({
} }
/** /**
* @description: 处理时间区间参数 * @description: Processing time interval parameters
*/ */
function handleRangeTimeValue(values: any) { function handleRangeTimeValue(values: any) {
const fieldMapToTime = unref(fieldMapToTimeRef); const fieldMapToTime = unref(fieldMapToTimeRef);
......
...@@ -31,7 +31,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref< ...@@ -31,7 +31,7 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
wrapperCol: globWrapperCol, wrapperCol: globWrapperCol,
} = unref(propsRef) as any; } = unref(propsRef) as any;
// 如果全局有设置labelWidth, 则所有item使用 // If labelWidth is set globally, all items use
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
return { labelCol, wrapperCol }; return { labelCol, wrapperCol };
} }
......
...@@ -42,57 +42,57 @@ export type UseFormReturnType = [RegisterFn, FormActionType]; ...@@ -42,57 +42,57 @@ export type UseFormReturnType = [RegisterFn, FormActionType];
export interface FormProps { export interface FormProps {
// layout?: 'vertical' | 'inline' | 'horizontal'; // layout?: 'vertical' | 'inline' | 'horizontal';
// 表单值 // Form value
model?: any; model?: any;
// 整个表单所有项宽度 // The width of all items in the entire form
labelWidth?: number | string; labelWidth?: number | string;
// 重置时提交 // Submit form on reset
submitOnReset?: boolean; submitOnReset?: boolean;
// 整个表单通用Col配置 // Col configuration for the entire form
labelCol?: Partial<ColEx>; labelCol?: Partial<ColEx>;
// 整个表单通用Col配置 // Col configuration for the entire form
wrapperCol?: Partial<ColEx>; wrapperCol?: Partial<ColEx>;
// 通用col配置 // General col configuration
baseColProps?: Partial<ColEx>; baseColProps?: Partial<ColEx>;
// 表单配置规则 // Form configuration rules
schemas?: FormSchema[]; schemas?: FormSchema[];
// 用于合并到动态控制表单项的 函数values // Function values used to merge into dynamic control form items
mergeDynamicData?: any; mergeDynamicData?: any;
// 紧凑模式,用于搜索表单 // Compact mode for search forms
compact?: boolean; compact?: boolean;
// 空白行span // Blank line span
emptySpan?: number | Partial<ColEx>; emptySpan?: number | Partial<ColEx>;
// 表单内部组件大小 // Internal component size of the form
size?: 'default' | 'small' | 'large'; size?: 'default' | 'small' | 'large';
// 是否禁用 // Whether to disable
disabled?: boolean; disabled?: boolean;
// 时间区间字段映射成多个 // Time interval fields are mapped into multiple
fieldMapToTime?: FieldMapToTime; fieldMapToTime?: FieldMapToTime;
// 自动设置placeholder // Placeholder is set automatically
autoSetPlaceHolder?: boolean; autoSetPlaceHolder?: boolean;
// 校验信息是否加入label // Check whether the information is added to the label
rulesMessageJoinLabel?: boolean; rulesMessageJoinLabel?: boolean;
// 是否显示收起展开按钮 // Whether to show collapse and expand buttons
showAdvancedButton?: boolean; showAdvancedButton?: boolean;
// 超过指定行数自动收起 // Automatically collapse over the specified number of rows
autoAdvancedLine?: number; autoAdvancedLine?: number;
// 是否显示操作按钮 // Whether to show the operation button
showActionButtonGroup?: boolean; showActionButtonGroup?: boolean;
// 重置按钮配置 // Reset button configuration
resetButtonOptions?: Partial<ButtonProps>; resetButtonOptions?: Partial<ButtonProps>;
// 确认按钮配置 // Confirm button configuration
submitButtonOptions?: Partial<ButtonProps>; submitButtonOptions?: Partial<ButtonProps>;
// 操作列配置 // Operation column configuration
actionColOptions?: Partial<ColEx>; actionColOptions?: Partial<ColEx>;
// 显示重置按钮 // Show reset button
showResetButton?: boolean; showResetButton?: boolean;
// 显示确认按钮 // Show confirmation button
showSubmitButton?: boolean; showSubmitButton?: boolean;
resetFunc?: () => Promise<void>; resetFunc?: () => Promise<void>;
...@@ -101,27 +101,27 @@ export interface FormProps { ...@@ -101,27 +101,27 @@ export interface FormProps {
colon?: boolean; colon?: boolean;
} }
export interface FormSchema { export interface FormSchema {
// 字段名 // Field name
field: string; field: string;
// 内部值更改触发的事件名,默认 change // Event name triggered by internal value change, default change
changeEvent?: string; changeEvent?: string;
// v-model绑定的变量名 默认 value // Variable name bound to v-model Default value
valueField?: string; valueField?: string;
// 标签名 // Label name
label: string; label: string;
// 辅助文本 // Auxiliary text
subLabel?: string; subLabel?: string;
// 文本右侧帮助文本 // Help text on the right side of the text
helpMessage?: string | string[]; helpMessage?: string | string[];
// BaseHelp组件props // BaseHelp component props
helpComponentProps?: Partial<HelpComponentProps>; helpComponentProps?: Partial<HelpComponentProps>;
// label宽度,有传的话 itemProps配置的 labelCol 和WrapperCol会失效 // Label width, if it is passed, the labelCol and WrapperCol configured by itemProps will be invalid
labelWidth?: string | number; labelWidth?: string | number;
// 禁用调有formModel全局设置的labelWidth,自己手动设置 labelCol和wrapperCol // Disable the adjustment of labelWidth with global settings of formModel, and manually set labelCol and wrapperCol by yourself
disabledLabelWidth?: boolean; disabledLabelWidth?: boolean;
// 组件 // render component
component: ComponentType; component: ComponentType;
// 组件参数 // Component parameters
componentProps?: componentProps?:
| ((opt: { | ((opt: {
schema: FormSchema; schema: FormSchema;
...@@ -130,35 +130,35 @@ export interface FormSchema { ...@@ -130,35 +130,35 @@ export interface FormSchema {
formModel: any; formModel: any;
}) => any) }) => any)
| object; | object;
// 必填 // Required
required?: boolean; required?: boolean;
// 校验规则 // Validation rules
rules?: Rule[]; rules?: Rule[];
// 校验信息是否加入label // Check whether the information is added to the label
rulesMessageJoinLabel?: boolean; rulesMessageJoinLabel?: boolean;
// 参考formModelItem // Reference formModelItem
itemProps?: Partial<FormItem>; itemProps?: Partial<FormItem>;
// formModelItem外层的col配置 // col configuration outside formModelItem
colProps?: Partial<ColEx>; colProps?: Partial<ColEx>;
// 默认值 // 默认值
defaultValue?: any; defaultValue?: any;
isAdvanced?: boolean; isAdvanced?: boolean;
// 配合详情组件 // Matching details components
span?: number; span?: number;
ifShow?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); ifShow?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
// 渲染form-item标签内的内容 // Render the content in the form-item tag
render?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string; render?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
// 渲染 col内容,需要外层包裹 form-item // Rendering col content requires outer wrapper form-item
renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string; renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
renderComponentContent?: renderComponentContent?:
...@@ -167,10 +167,10 @@ export interface FormSchema { ...@@ -167,10 +167,10 @@ export interface FormSchema {
| VNode[] | VNode[]
| string; | string;
// 自定义slot, 在 from-item内 // Custom slot, in from-item
slot?: string; slot?: string;
// 自定义slot,类似renderColContent // Custom slot, similar to renderColContent
colSlot?: string; colSlot?: string;
dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean); dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
...@@ -179,16 +179,16 @@ export interface FormSchema { ...@@ -179,16 +179,16 @@ export interface FormSchema {
} }
export interface HelpComponentProps { export interface HelpComponentProps {
maxWidth: string; maxWidth: string;
// 是否显示序号 // Whether to display the serial number
showIndex: boolean; showIndex: boolean;
// 文本列表 // Text list
text: any; text: any;
// 颜色 // colour
color: string; color: string;
// 字体大小 // font size
fontSize: string; fontSize: string;
icon: string; icon: string;
absolute: boolean; absolute: boolean;
// 定位 // Positioning
position: any; position: any;
} }
...@@ -6,7 +6,8 @@ import { Menu } from 'ant-design-vue'; ...@@ -6,7 +6,8 @@ import { Menu } from 'ant-design-vue';
import SearchInput from './SearchInput.vue'; import SearchInput from './SearchInput.vue';
import MenuContent from './MenuContent'; import MenuContent from './MenuContent';
import { MenuModeEnum, MenuThemeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { ThemeEnum } from '/@/enums/appEnum';
import { menuStore } from '/@/store/modules/menu'; import { menuStore } from '/@/store/modules/menu';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
...@@ -254,7 +255,7 @@ export default defineComponent({ ...@@ -254,7 +255,7 @@ export default defineComponent({
{getSlot(slots, 'header')} {getSlot(slots, 'header')}
<SearchInput <SearchInput
class={!props.search ? 'hidden' : ''} class={!props.search ? 'hidden' : ''}
theme={props.theme as MenuThemeEnum} theme={props.theme as ThemeEnum}
onChange={handleInputChange} onChange={handleInputChange}
onClick={handleInputClick} onClick={handleInputClick}
collapsed={getCollapsedState} collapsed={getCollapsedState}
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<script lang="ts"> <script lang="ts">
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue';
import { MenuThemeEnum } from '/@/enums/menuEnum'; import { ThemeEnum } from '/@/enums/appEnum';
// hook // hook
import { useDebounce } from '/@/hooks/core/useDebounce'; import { useDebounce } from '/@/hooks/core/useDebounce';
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
default: true, default: true,
}, },
theme: { theme: {
type: String as PropType<MenuThemeEnum>, type: String as PropType<ThemeEnum>,
}, },
}, },
setup(props, { emit }) { setup(props, { emit }) {
......
import type { Menu } from '/@/router/types'; import type { Menu } from '/@/router/types';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { MenuModeEnum, MenuTypeEnum, MenuThemeEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { ThemeEnum } from '/@/enums/appEnum';
export const basicProps = { export const basicProps = {
items: { items: {
type: Array as PropType<Menu[]>, type: Array as PropType<Menu[]>,
...@@ -40,7 +41,7 @@ export const basicProps = { ...@@ -40,7 +41,7 @@ export const basicProps = {
}, },
theme: { theme: {
type: String as PropType<string>, type: String as PropType<string>,
default: MenuThemeEnum.DARK, default: ThemeEnum.DARK,
}, },
showLogo: { showLogo: {
type: Boolean as PropType<boolean>, type: Boolean as PropType<boolean>,
......
import { ThemeEnum } from '/@/enums/appEnum';
export interface MenuState { export interface MenuState {
// 默认选中的列表 // 默认选中的列表
defaultSelectedKeys: string[]; defaultSelectedKeys: string[];
...@@ -6,7 +7,7 @@ export interface MenuState { ...@@ -6,7 +7,7 @@ export interface MenuState {
mode: MenuModeEnum; mode: MenuModeEnum;
// 主题 // 主题
theme: ComputedRef<MenuThemeEnum> | MenuThemeEnum; theme: ComputedRef<ThemeEnum> | ThemeEnum;
// 缩进 // 缩进
inlineIndent?: number; inlineIndent?: number;
......
...@@ -208,8 +208,8 @@ ...@@ -208,8 +208,8 @@
padding: 16px; padding: 16px;
.ant-form { .ant-form {
padding: 12px 12px 4px 12px; padding: 20px 20px 4px 12px;
margin-bottom: 12px; margin-bottom: 18px;
background: #fff; background: #fff;
border-radius: 2px; border-radius: 2px;
} }
......
...@@ -33,7 +33,7 @@ import { ...@@ -33,7 +33,7 @@ import {
Result, Result,
Empty, Empty,
} from 'ant-design-vue'; } from 'ant-design-vue';
import { getApp } from '/@/useApp'; import { getApp } from '/@/setup/Application';
const compList = [Icon, Button, AntButton.Group, AppFooter]; const compList = [Icon, Button, AntButton.Group, AppFooter];
......
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
@page-loading-z-index: 10000; @page-loading-z-index: 10000;
// left-menu // left-menu
@app-menu-item-height: 46px; @app-menu-item-height: 44px;
...@@ -15,6 +15,13 @@ export enum ThemeModeEnum { ...@@ -15,6 +15,13 @@ export enum ThemeModeEnum {
SEMI_DARK = 'semi-dark-mode', SEMI_DARK = 'semi-dark-mode',
} }
// menu theme enum
export enum ThemeEnum {
DARK = 'dark',
LIGHT = 'light',
}
/** /**
* 权限模式 * 权限模式
*/ */
......
export const MENU_DRAG_STATE = 'MENU_DRAG_STATE';
...@@ -10,13 +10,6 @@ export enum MenuTypeEnum { ...@@ -10,13 +10,6 @@ export enum MenuTypeEnum {
TOP_MENU = 'top-menu', TOP_MENU = 'top-menu',
} }
// menu theme enum
export enum MenuThemeEnum {
DARK = 'dark',
LIGHT = 'light',
}
// 折叠触发器位置 // 折叠触发器位置
export enum TriggerEnum { export enum TriggerEnum {
// 不显示 // 不显示
......
export enum PaginationEnum {
// Default number of pages
DEFAULT_PAGE_SIZE = 20,
}
export enum ResultEnum {
SUCCESS = 0,
ERROR = 1,
TIMEOUT = 401,
TYPE = 'success',
}
import { nextTick, onMounted, onActivated } from 'vue';
export function onMountedOrActivated(hook: Fn) {
let mounted: boolean;
onMounted(() => {
hook();
nextTick(() => {
mounted = true;
});
});
onActivated(() => {
if (mounted) {
hook();
}
});
}
import { getCurrentInstance } from 'vue';
// expose public api
export function useExpose(apis: Record<string, any>) {
const instance = getCurrentInstance();
if (instance) {
Object.assign(instance.proxy, apis);
}
}
import { toRef, Ref, reactive, customRef, SetupContext, watch, UnwrapRef } from 'vue';
export type ModelProps<U> = Readonly<
{ [props: string]: any } & {
modelValue?: U;
}
>;
export function useModel<T>(
props: ModelProps<T>,
context: SetupContext,
callback?: (val: T | undefined, internalState: { value: UnwrapRef<T | undefined> }) => any
) {
const outerModel: Ref<T | undefined> = toRef(props, 'modelValue');
const internalState = reactive({
value: props.modelValue,
});
const internalModel = customRef<UnwrapRef<T> | undefined>((track, trigger) => {
return {
get() {
track();
return internalState.value;
},
set(newVal) {
if (internalState.value === newVal) return;
internalState.value = newVal;
context.emit('update:modelValue', newVal);
trigger();
},
};
});
watch(outerModel, (val, oldVal) => {
if (val === oldVal || val === internalState.value) return;
if (callback) {
callback(val, internalState);
return;
}
internalState.value = val as UnwrapRef<T> | undefined;
});
return {
internalState,
internalModel,
};
}
import { ref, onBeforeUpdate } from 'vue';
export function useRefs() {
const refs = ref([] as Element[]);
onBeforeUpdate(() => {
refs.value = [];
});
const setRefs = (index: number) => (el: Element) => {
refs.value[index] = el;
};
return [refs, setRefs];
}
...@@ -27,7 +27,7 @@ export function throttle<T extends unknown[]>( ...@@ -27,7 +27,7 @@ export function throttle<T extends unknown[]>(
} }
let { immediate = false } = options; let { immediate = false } = options;
const { once = false, debounce = false } = options; const { once = false, debounce = false } = options;
let timeoutId: ReturnType<typeof setTimeout> | undefined; let timeoutId: Nullable<TimeoutHandle>;
// Has it been cancelled // Has it been cancelled
let cancelled: boolean | null = false; let cancelled: boolean | null = false;
/** /**
...@@ -36,7 +36,7 @@ export function throttle<T extends unknown[]>( ...@@ -36,7 +36,7 @@ export function throttle<T extends unknown[]>(
function clearTimer() { function clearTimer() {
if (timeoutId) { if (timeoutId) {
window.clearTimeout(timeoutId); window.clearTimeout(timeoutId);
timeoutId = undefined; timeoutId = null;
} }
} }
/** cancel exec */ /** cancel exec */
...@@ -63,7 +63,7 @@ export function throttle<T extends unknown[]>( ...@@ -63,7 +63,7 @@ export function throttle<T extends unknown[]>(
const callNow = !timeoutId; const callNow = !timeoutId;
if (callNow) { if (callNow) {
exec(); exec();
timeoutId = undefined; timeoutId = null;
} }
} else { } else {
debounce && clearTimer(); debounce && clearTimer();
......
import { ref, watch, Ref, SetupContext } from 'vue';
export function useToggle(internalModel: Ref<unknown>, { emit }: SetupContext) {
const isActive = ref(!!internalModel.value);
const isToggled = ref(false);
watch(internalModel, (val) => {
isActive.value = !!val;
});
watch(isActive, (value) => {
!!value !== !!internalModel.value && emit('onUpdate:modelValue', value);
});
function toggleIt() {
isToggled.value = !isToggled.value;
}
return {
isActive,
toggleIt,
isToggled,
};
}
import { Ref, watchEffect, ref } from 'vue';
interface IntersectionObserverProps {
target: Ref<Element | null | undefined>;
root?: Ref<Element | null | undefined>;
onIntersect: IntersectionObserverCallback;
rootMargin?: string;
threshold?: number;
}
export function useIntersectionObserver({
target,
root,
onIntersect,
rootMargin = '0px',
threshold = 0.1,
}: IntersectionObserverProps) {
let cleanup = () => {};
const observer: Ref<Nullable<IntersectionObserver>> = ref(null);
const stopEffect = watchEffect(() => {
cleanup();
observer.value = new IntersectionObserver(onIntersect, {
root: root ? root.value : null,
rootMargin,
threshold,
});
const current = target.value;
current && observer.value.observe(current);
cleanup = () => {
if (observer.value) {
observer.value.disconnect();
target.value && observer.value.unobserve(target.value);
}
};
});
return {
observer,
stop: () => {
cleanup();
stopEffect();
},
};
}
import { ref, Ref, unref } from 'vue'; import { ref, Ref, unref } from 'vue';
import { useEventListener } from '/@/hooks/event/useEventListener'; import { useEventListener } from '/@/hooks/event/useEventListener';
import { isServer } from '/@/utils/is';
export function useClickOutside<T extends HTMLElement>( export function useClickOutside<T extends HTMLElement>(
containerRef: Ref<T>, containerRef: Ref<T>,
onClickOutside: (e: MouseEvent | TouchEvent) => void onClickOutside: (e: MouseEvent | TouchEvent) => void,
eventName = 'click'
) { ) {
if (isServer) return;
const isTouchRef = ref(false); const isTouchRef = ref(false);
useEventListener({ useEventListener({
el: document, el: document,
name: 'touchend', name: 'touchend',
...@@ -13,7 +18,7 @@ export function useClickOutside<T extends HTMLElement>( ...@@ -13,7 +18,7 @@ export function useClickOutside<T extends HTMLElement>(
}); });
useEventListener({ useEventListener({
el: document, el: document,
name: 'click', name: eventName,
listener: handler, listener: handler,
options: true, options: true,
}); });
......
import { Ref, ref, onMounted, nextTick } from 'vue';
import { useRect } from '/@/hooks/web/useRect';
export const useHeight = (element: Element | Ref<Element>) => {
const height = ref();
onMounted(() => {
nextTick(() => {
height.value = useRect(element).height;
});
});
return height;
};
import { onUnmounted, watchEffect } from 'vue'; import { computed, onUnmounted, watchEffect } from 'vue';
import { useThrottle } from '/@/hooks/core/useThrottle'; import { useThrottle } from '/@/hooks/core/useThrottle';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
...@@ -7,10 +7,11 @@ import { userStore } from '/@/store/modules/user'; ...@@ -7,10 +7,11 @@ import { userStore } from '/@/store/modules/user';
export function useLockPage() { export function useLockPage() {
let timeId: ReturnType<typeof setTimeout>; let timeId: ReturnType<typeof setTimeout>;
function clear() { function clear(): void {
window.clearTimeout(timeId); window.clearTimeout(timeId);
} }
function resetCalcLockTimeout() {
function resetCalcLockTimeout(): void {
// not login // not login
if (!userStore.getTokenState) { if (!userStore.getTokenState) {
clear(); clear();
...@@ -28,31 +29,37 @@ export function useLockPage() { ...@@ -28,31 +29,37 @@ export function useLockPage() {
}, lockTime * 60 * 1000); }, lockTime * 60 * 1000);
} }
function lockPage() { function lockPage(): void {
appStore.commitLockInfoState({ appStore.commitLockInfoState({
isLock: true, isLock: true,
pwd: undefined, pwd: undefined,
}); });
} }
watchEffect(() => { watchEffect((onClean) => {
if (userStore.getTokenState) { if (userStore.getTokenState) {
resetCalcLockTimeout(); resetCalcLockTimeout();
} else { } else {
clear(); clear();
} }
onClean(() => {
clear();
});
}); });
onUnmounted(() => { onUnmounted(() => {
clear(); clear();
}); });
const [keyupFn] = useThrottle(resetCalcLockTimeout, 2000); const [keyupFn] = useThrottle(resetCalcLockTimeout, 2000);
return { return computed(() => {
registerGlobOnKeyup: keyupFn, const openLockPage = appStore.getProjectConfig.lockTime;
registerGlobOnMouseMove: keyupFn, if (openLockPage) {
on: { return { onKeyup: keyupFn, onMousemove: keyupFn };
onKeyup: keyupFn, } else {
onMousemove: keyupFn, clear();
}, return {};
}; }
});
} }
import type { RouteRecordRaw } from 'vue-router';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { permissionStore } from '/@/store/modules/permission'; import { permissionStore } from '/@/store/modules/permission';
import { userStore } from '/@/store/modules/user';
import { useTabs } from './useTabs'; import { useTabs } from './useTabs';
import { RoleEnum } from '/@/enums/roleEnum';
import router, { resetRouter } from '/@/router'; import router, { resetRouter } from '/@/router';
import { userStore } from '/@/store/modules/user';
import { isArray } from '/@/utils/is';
import { RootRoute } from '/@/router/routes'; import { RootRoute } from '/@/router/routes';
import type { RouteRecordRaw } from 'vue-router';
import { PermissionModeEnum } from '/@/enums/appEnum'; import { PermissionModeEnum } from '/@/enums/appEnum';
import { RoleEnum } from '/@/enums/roleEnum';
import { intersection } from 'lodash-es'; import { intersection } from 'lodash-es';
import { isArray } from '/@/utils/is';
// User permissions related operations
export function usePermission() { export function usePermission() {
/** /**
* 更换权限模式 * Change permission mode
*/ */
async function togglePermissionMode() { async function togglePermissionMode() {
appStore.commitProjectConfigState({ appStore.commitProjectConfigState({
...@@ -25,6 +31,10 @@ export function usePermission() { ...@@ -25,6 +31,10 @@ export function usePermission() {
// location.reload(); // location.reload();
} }
/**
* Reset and regain authority resource information
* @param id
*/
async function resume(id?: string | number) { async function resume(id?: string | number) {
resetRouter(); resetRouter();
const routes = await permissionStore.buildRoutesAction(id); const routes = await permissionStore.buildRoutesAction(id);
...@@ -41,12 +51,12 @@ export function usePermission() { ...@@ -41,12 +51,12 @@ export function usePermission() {
} }
/** /**
* 角色模式下判断是否显示 * Determine whether there is permission
*/ */
function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean { function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
const permMode = appStore.getProjectConfig.permissionMode; const permMode = appStore.getProjectConfig.permissionMode;
if (PermissionModeEnum.ROLE === permMode) { if (PermissionModeEnum.ROLE === permMode) {
// !不传默认可见 // Visible by default
if (!value) { if (!value) {
return def; return def;
} }
...@@ -56,7 +66,7 @@ export function usePermission() { ...@@ -56,7 +66,7 @@ export function usePermission() {
return (intersection(value, userStore.getRoleListState) as RoleEnum[]).length > 0; return (intersection(value, userStore.getRoleListState) as RoleEnum[]).length > 0;
} }
if (PermissionModeEnum.BACK === permMode) { if (PermissionModeEnum.BACK === permMode) {
// !不传默认可见 // Visible by default
if (!value) { if (!value) {
return def; return def;
} }
...@@ -66,17 +76,18 @@ export function usePermission() { ...@@ -66,17 +76,18 @@ export function usePermission() {
} }
return (intersection(value, allCodeList) as string[]).length > 0; return (intersection(value, allCodeList) as string[]).length > 0;
} }
return true; return true;
} }
/** /**
* 更新角色 * Change roles
* @param roles * @param roles
*/ */
async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> { async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
if (appStore.getProjectConfig.permissionMode !== PermissionModeEnum.ROLE) { if (appStore.getProjectConfig.permissionMode !== PermissionModeEnum.ROLE) {
throw new Error('请在配置中将PermissionModeEnum切换为ROLE模式在进行操作!'); throw new Error(
'Please switch PermissionModeEnum to ROLE mode in the configuration to operate!'
);
} }
if (!isArray(roles)) { if (!isArray(roles)) {
roles = [roles]; roles = [roles];
...@@ -86,10 +97,10 @@ export function usePermission() { ...@@ -86,10 +97,10 @@ export function usePermission() {
} }
/** /**
* * Change menu
*/ */
async function changeMenu(id?: string | number) { async function changeMenu(id?: string | number) {
// 这里传入id是为测试,实际可以不用传,会自动获取登录人的id // TODO The id passed in here is for testing. Actually, you don’t need to pass it. The id of the login person will be automatically obtained.
resume(id); resume(id);
} }
......
import { Ref, unref } from 'vue';
import { isWindow } from '/@/utils/is';
export const useRect = (elementRef: (Element | Window) | Ref<Element | Window | undefined>) => {
const element = unref(elementRef);
if (isWindow(element)) {
const width = element.innerWidth;
const height = element.innerHeight;
return {
top: 0,
left: 0,
right: width,
bottom: height,
width,
height,
};
}
if (element && element.getBoundingClientRect) {
return element.getBoundingClientRect();
}
return {
top: 0,
left: 0,
right: 0,
bottom: 0,
width: 0,
height: 0,
};
};
...@@ -35,7 +35,7 @@ interface SwitchOptions { ...@@ -35,7 +35,7 @@ interface SwitchOptions {
} }
interface SelectConfig { interface SelectConfig {
options?: SelectOptions; options?: LabelValueOptions;
def?: any; def?: any;
disabled?: boolean; disabled?: boolean;
handler?: Fn; handler?: Fn;
......
import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { ContentEnum, RouterTransitionEnum, ThemeEnum } from '/@/enums/appEnum';
import { MenuThemeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum'; import { TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
export enum HandlerEnum { export enum HandlerEnum {
CHANGE_LAYOUT, CHANGE_LAYOUT,
...@@ -40,11 +40,11 @@ export enum HandlerEnum { ...@@ -40,11 +40,11 @@ export enum HandlerEnum {
export const themeOptions = [ export const themeOptions = [
{ {
value: MenuThemeEnum.LIGHT, value: ThemeEnum.LIGHT,
label: '亮色', label: '亮色',
}, },
{ {
value: MenuThemeEnum.DARK, value: ThemeEnum.DARK,
label: '暗色', label: '暗色',
}, },
]; ];
......
...@@ -4,34 +4,40 @@ import router, { setupRouter } from '/@/router'; ...@@ -4,34 +4,40 @@ import router, { setupRouter } from '/@/router';
import { setupStore } from '/@/store'; import { setupStore } from '/@/store';
import { setupAntd } from '/@/setup/ant-design-vue'; import { setupAntd } from '/@/setup/ant-design-vue';
import { setupErrorHandle } from '/@/setup/error-handle'; import { setupErrorHandle } from '/@/setup/error-handle';
import { setupDirectives } from '/@/setup/directives'; import { setupGlobDirectives } from '/@/setup/directives';
import { isDevMode, isProdMode, isUseMock } from '/@/utils/env';
import { setupProdMockServer } from '../mock/_createProductionServer'; import { setupProdMockServer } from '../mock/_createProductionServer';
import { setApp } from './useApp'; import { setApp } from '/@/setup/Application';
import App from './App.vue'; import App from './App.vue';
import { isDevMode, isProdMode, isUseMock } from '/@/utils/env';
import '/@/design/index.less'; import '/@/design/index.less';
const app = createApp(App); const app = createApp(App);
// ui // Configure component library
setupAntd(app); setupAntd(app);
// router
// Configure routing
setupRouter(app); setupRouter(app);
// store
// Configure vuex store
setupStore(app); setupStore(app);
// Directives // Register global directive
setupDirectives(app); setupGlobDirectives(app);
// error-handle // Configure global error handling
setupErrorHandle(app); setupErrorHandle(app);
// Mount when the route is ready
router.isReady().then(() => { router.isReady().then(() => {
app.mount('#app'); app.mount('#app');
}); });
// The development environment takes effect
if (isDevMode()) { if (isDevMode()) {
app.config.performance = true; app.config.performance = true;
window.__APP__ = app; window.__APP__ = app;
......
import type { ProjectConfig } from '/@/types/config'; import type { ProjectConfig } from '/@/types/config';
import { MenuTypeEnum, MenuThemeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import { primaryColor } from '../../build/config/lessModifyVars'; import { primaryColor } from '../../build/config/lessModifyVars';
import { isProdMode } from '/@/utils/env'; import { isProdMode } from '/@/utils/env';
...@@ -39,7 +39,7 @@ const setting: ProjectConfig = { ...@@ -39,7 +39,7 @@ const setting: ProjectConfig = {
// 是否显示顶部 // 是否显示顶部
show: true, show: true,
// theme // theme
theme: MenuThemeEnum.LIGHT, theme: ThemeEnum.LIGHT,
// 开启锁屏功能 // 开启锁屏功能
useLockPage: true, useLockPage: true,
// 显示刷新按钮 // 显示刷新按钮
...@@ -74,7 +74,7 @@ const setting: ProjectConfig = { ...@@ -74,7 +74,7 @@ const setting: ProjectConfig = {
// 菜单类型 // 菜单类型
type: MenuTypeEnum.SIDEBAR, type: MenuTypeEnum.SIDEBAR,
// 菜单主题 // 菜单主题
theme: MenuThemeEnum.DARK, theme: ThemeEnum.DARK,
// 分割菜单 // 分割菜单
split: false, split: false,
// 顶部菜单布局 // 顶部菜单布局
......
// Application related functions /**
* Application configuration
*/
import type { ProjectConfig } from '/@/types/config'; import type { ProjectConfig } from '/@/types/config';
import type { App } from 'vue'; import type { App } from 'vue';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
...@@ -18,7 +21,9 @@ import { ...@@ -18,7 +21,9 @@ import {
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
// Used to share global app instances
let app: App; let app: App;
export function setApp(_app: App): void { export function setApp(_app: App): void {
app = _app; app = _app;
} }
...@@ -27,7 +32,7 @@ export function getApp(): App { ...@@ -27,7 +32,7 @@ export function getApp(): App {
return app; return app;
} }
// TODO 主题切换 // TODO Theme switching
export function useThemeMode(mode: ThemeModeEnum) { export function useThemeMode(mode: ThemeModeEnum) {
const modeRef = ref(mode); const modeRef = ref(mode);
const html = document.documentElement; const html = document.documentElement;
...@@ -43,7 +48,7 @@ export function useThemeMode(mode: ThemeModeEnum) { ...@@ -43,7 +48,7 @@ export function useThemeMode(mode: ThemeModeEnum) {
} }
// Initial project configuration // Initial project configuration
export function useInitAppConfigStore() { export function initAppConfigStore() {
let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig; let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig;
if (!projCfg) { if (!projCfg) {
projCfg = projectSetting; projCfg = projectSetting;
...@@ -67,8 +72,8 @@ export function useInitAppConfigStore() { ...@@ -67,8 +72,8 @@ export function useInitAppConfigStore() {
appStore.commitProjectConfigState(projCfg); appStore.commitProjectConfigState(projCfg);
} }
// Config Provider // antdv Config Provider
export function useConfigProvider() { export function getConfigProvider() {
function transformCellText({ text }: { text: string }) { function transformCellText({ text }: { text: string }) {
if (isNull(text) || isUnDef(text)) { if (isNull(text) || isUnDef(text)) {
return ' - '; return ' - ';
......
// Load on demand // Load on demand
// This module only introduces components globally before login
import type { App } from 'vue'; import type { App } from 'vue';
import { import {
......
@import (reference) '../../design/index.less';
.app-svg-loading {
position: relative;
width: auto;
&__tip {
display: block;
margin-top: 4px;
font-size: 13px;
color: #303133;
text-align: center;
}
}
import { Spin } from 'ant-design-vue'; import { Spin } from 'ant-design-vue';
import svgImg from '/@/assets/images/loading.svg'; import svgImg from '/@/assets/images/loading.svg';
import './spin.less';
Spin.setDefaultIndicator({ Spin.setDefaultIndicator({
indicator: () => { indicator: () => {
return ( return (
<div class="app-svg-loading"> <div
class="app-svg-loading"
style={{
position: 'relative',
width: 'auto',
}}
>
<img src={svgImg} alt="" height="32" width="32" class="g-loading" /> <img src={svgImg} alt="" height="32" width="32" class="g-loading" />
</div> </div>
); );
......
/**
* Application configuration
*/
import type { ProjectConfig } from '/@/types/config';
import type { App } from 'vue';
import { computed, ref } from 'vue';
import { ThemeModeEnum } from '/@/enums/appEnum';
import { PROJ_CFG_KEY } from '/@/enums/cacheEnum';
import projectSetting from '/@/settings/projectSetting';
import { getLocal } from '/@/utils/helper/persistent';
import { isUnDef, isNull } from '/@/utils/is';
import {
updateGrayMode,
updateColorWeak,
updateHeaderBgColor,
updateSidebarBgColor,
} from '/@/setup/theme';
import { appStore } from '/@/store/modules/app';
// Used to share global app instances
let app: App;
export function setApp(_app: App): void {
app = _app;
}
export function getApp(): App {
return app;
}
// TODO Theme switching
export function useThemeMode(mode: ThemeModeEnum) {
const modeRef = ref(mode);
const html = document.documentElement;
const clsList = html.classList;
const change = () => {
clsList.contains(mode) ? clsList.remove(mode) : clsList.add(mode);
};
return {
runChangeThemeMode: change,
mode: computed(() => modeRef.value),
};
}
// Initial project configuration
export function initAppConfigStore() {
let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig;
if (!projCfg) {
projCfg = projectSetting;
}
const { colorWeak, grayMode, headerBgColor, menuBgColor } = projCfg;
try {
// if (
// themeColor !== primaryColor &&
// themeColor &&
// process.env.VUE_APP_USE_THEME_REPLACER !== 'TRUE'
// ) {
// updateTheme(themeColor);
// }
headerBgColor && updateHeaderBgColor(headerBgColor);
menuBgColor && updateSidebarBgColor(menuBgColor);
grayMode && updateGrayMode(grayMode);
colorWeak && updateColorWeak(colorWeak);
} catch (error) {
console.log(error);
}
appStore.commitProjectConfigState(projCfg);
}
// antdv Config Provider
export function getConfigProvider() {
function transformCellText({ text }: { text: string }) {
if (isNull(text) || isUnDef(text)) {
return ' - ';
}
return text;
}
return {
transformCellText,
};
}
/**
* Configure and register global directives
*/
import type { App } from 'vue'; import type { App } from 'vue';
import { setupPermissionDirective } from './permission'; import { setupPermissionDirective } from './permission';
export function setupDirectives(app: App) {
export function setupGlobDirectives(app: App) {
setupPermissionDirective(app); setupPermissionDirective(app);
} }
/**
* Global authority directive
* Used for fine-grained control of component permissions
* @Example v-auth="RoleEnum.TEST"
*/
import type { App, Directive, DirectiveBinding } from 'vue';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import type { App } from 'vue';
import { usePermission } from '/@/hooks/web/usePermission'; import { usePermission } from '/@/hooks/web/usePermission';
import { PermissionModeEnum } from '/@/enums/appEnum'; import { PermissionModeEnum } from '/@/enums/appEnum';
const { hasPermission } = usePermission(); const { hasPermission } = usePermission();
...@@ -13,18 +19,28 @@ function isAuth(el: Element, binding: any) { ...@@ -13,18 +19,28 @@ function isAuth(el: Element, binding: any) {
} }
} }
} }
function isBackMode() { function isBackMode() {
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK; return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
} }
const mounted = (el: Element, binding: DirectiveBinding<any>) => {
if (isBackMode()) return;
isAuth(el, binding);
};
const updated = (el: Element, binding: DirectiveBinding<any>) => {
if (!isBackMode()) return;
isAuth(el, binding);
};
const authDirective: Directive = {
mounted,
updated,
};
export function setupPermissionDirective(app: App) { export function setupPermissionDirective(app: App) {
app.directive('auth', { app.directive('auth', authDirective);
mounted(el: Element, binding) {
if (isBackMode()) return;
isAuth(el, binding);
},
updated(el: Element, binding) {
if (!isBackMode()) return;
isAuth(el, binding);
},
});
} }
export default authDirective;
/**
* Prevent repeated clicks
* @Example v-repeat-click="()=>{}"
*/
import { on, once } from '/@/utils/domUtils'; import { on, once } from '/@/utils/domUtils';
import type { Directive, DirectiveBinding } from 'vue';
export default { const repeatDirective: Directive = {
beforeMount(el: Element, binding: any) { beforeMount(el: Element, binding: DirectiveBinding<any>) {
let interval: ReturnType<typeof setInterval> | null = null; let interval: Nullable<IntervalHandle> = null;
let startTime = 0; let startTime = 0;
const handler = () => binding.value && binding.value(); const handler = (): void => binding.value && binding.value();
const clear = () => { const clear = (): void => {
if (Date.now() - startTime < 100) { if (Date.now() - startTime < 100) {
handler(); handler();
} }
...@@ -13,7 +18,7 @@ export default { ...@@ -13,7 +18,7 @@ export default {
interval = null; interval = null;
}; };
on(el, 'mousedown', (e) => { on(el, 'mousedown', (e: MouseEvent): void => {
if ((e as any).button !== 0) return; if ((e as any).button !== 0) return;
startTime = Date.now(); startTime = Date.now();
once(document as any, 'mouseup', clear); once(document as any, 'mouseup', clear);
...@@ -22,3 +27,5 @@ export default { ...@@ -22,3 +27,5 @@ export default {
}); });
}, },
}; };
export default repeatDirective;
/**
* Used to configure the global error handling function, which can monitor vue errors, script errors, static resource errors and Promise errors
*/
import { errorStore, ErrorInfo } from '/@/store/modules/error'; import { errorStore, ErrorInfo } from '/@/store/modules/error';
import { useSetting } from '/@/hooks/core/useSetting'; import { useSetting } from '/@/hooks/core/useSetting';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import { App } from 'vue'; import { App } from 'vue';
/**
* Handling error stack information
* @param error
*/
function processStackMsg(error: Error) { function processStackMsg(error: Error) {
if (!error.stack) { if (!error.stack) {
return ''; return '';
} }
let stack = error.stack let stack = error.stack
.replace(/\n/gi, '') // 去掉换行,节省传输内容大小 .replace(/\n/gi, '') // Remove line breaks to save the size of the transmitted content
.replace(/\bat\b/gi, '@') // chrome中是at,ff中是@ .replace(/\bat\b/gi, '@') // At in chrome, @ in ff
.split('@') // 以@分割信息 .split('@') // Split information with @
.slice(0, 9) // 最大堆栈长度(Error.stackTraceLimit = 10),所以只取前10条 .slice(0, 9) // The maximum stack length (Error.stackTraceLimit = 10), so only take the first 10
.map((v) => v.replace(/^\s*|\s*$/g, '')) // 去除多余空格 .map((v) => v.replace(/^\s*|\s*$/g, '')) // Remove extra spaces
.join('~') // 手动添加分隔符,便于后期展示 .join('~') // Manually add separators for later display
.replace(/\?[^:]+/gi, ''); // 去除js文件链接的多余参数(?x=1之类) .replace(/\?[^:]+/gi, ''); // Remove redundant parameters of js file links (?x=1 and the like)
const msg = error.toString(); const msg = error.toString();
if (stack.indexOf(msg) < 0) { if (stack.indexOf(msg) < 0) {
stack = msg + '@' + stack; stack = msg + '@' + stack;
...@@ -21,6 +30,10 @@ function processStackMsg(error: Error) { ...@@ -21,6 +30,10 @@ function processStackMsg(error: Error) {
return stack; return stack;
} }
/**
* get comp name
* @param vm
*/
function formatComponentName(vm: any) { function formatComponentName(vm: any) {
if (vm.$root === vm) { if (vm.$root === vm) {
return { return {
...@@ -43,6 +56,10 @@ function formatComponentName(vm: any) { ...@@ -43,6 +56,10 @@ function formatComponentName(vm: any) {
}; };
} }
/**
* Configure Vue error handling function
*/
function vueErrorHandler(err: Error, vm: any, info: string) { function vueErrorHandler(err: Error, vm: any, info: string) {
const { name, path } = formatComponentName(vm); const { name, path } = formatComponentName(vm);
errorStore.commitErrorInfoState({ errorStore.commitErrorInfoState({
...@@ -56,6 +73,9 @@ function vueErrorHandler(err: Error, vm: any, info: string) { ...@@ -56,6 +73,9 @@ function vueErrorHandler(err: Error, vm: any, info: string) {
}); });
} }
/**
* Configure script error handling function
*/
export function scriptErrorHandler( export function scriptErrorHandler(
event: Event | string, event: Event | string,
source?: string, source?: string,
...@@ -86,6 +106,9 @@ export function scriptErrorHandler( ...@@ -86,6 +106,9 @@ export function scriptErrorHandler(
return true; return true;
} }
/**
* Configure Promise error handling function
*/
function registerPromiseErrorHandler() { function registerPromiseErrorHandler() {
window.addEventListener( window.addEventListener(
'unhandledrejection', 'unhandledrejection',
...@@ -104,8 +127,11 @@ function registerPromiseErrorHandler() { ...@@ -104,8 +127,11 @@ function registerPromiseErrorHandler() {
); );
} }
/**
* Configure monitoring resource loading error handling function
*/
function registerResourceErrorHandler() { function registerResourceErrorHandler() {
// 监控资源加载错误(img,script,css,以及jsonp) // Monitoring resource loading error(img,script,css,and jsonp)
window.addEventListener( window.addEventListener(
'error', 'error',
function (e: Event) { function (e: Event) {
...@@ -129,19 +155,23 @@ function registerResourceErrorHandler() { ...@@ -129,19 +155,23 @@ function registerResourceErrorHandler() {
); );
} }
/**
* Configure global error handling
* @param app
*/
export function setupErrorHandle(app: App) { export function setupErrorHandle(app: App) {
const { projectSetting } = useSetting(); const { projectSetting } = useSetting();
const { useErrorHandle } = projectSetting; const { useErrorHandle } = projectSetting;
if (!useErrorHandle) { if (!useErrorHandle) return;
return; // Vue exception monitoring;
}
// Vue异常监控;
app.config.errorHandler = vueErrorHandler; app.config.errorHandler = vueErrorHandler;
// js错误
// script error
window.onerror = scriptErrorHandler; window.onerror = scriptErrorHandler;
// promise 异常
// promise exception
registerPromiseErrorHandler(); registerPromiseErrorHandler();
// 静态资源异常 // Static resource exception
registerResourceErrorHandler(); registerResourceErrorHandler();
} }
import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color'; import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { MenuThemeEnum } from '/@/enums/menuEnum'; import { ThemeEnum } from '/@/enums/appEnum';
const HEADER_BG_COLOR_VAR = '--header-bg-color'; const HEADER_BG_COLOR_VAR = '--header-bg-color';
const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color'; const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color';
...@@ -22,14 +22,26 @@ function toggleClass(flag: boolean, clsName: string) { ...@@ -22,14 +22,26 @@ function toggleClass(flag: boolean, clsName: string) {
document.body.className = flag ? `${className} ${clsName} ` : className; document.body.className = flag ? `${className} ${clsName} ` : className;
} }
/**
* Change the status of the project's color weakness mode
* @param gray
*/
export const updateColorWeak = (colorWeak: boolean) => { export const updateColorWeak = (colorWeak: boolean) => {
toggleClass(colorWeak, 'color-weak'); toggleClass(colorWeak, 'color-weak');
}; };
/**
* Change project gray mode status
* @param gray
*/
export const updateGrayMode = (gray: boolean) => { export const updateGrayMode = (gray: boolean) => {
toggleClass(gray, 'gray-mode'); toggleClass(gray, 'gray-mode');
}; };
/**
* Change the background color of the top header
* @param color
*/
export function updateHeaderBgColor(color: string) { export function updateHeaderBgColor(color: string) {
if (!isHexColor(color)) return; if (!isHexColor(color)) return;
// bg color // bg color
...@@ -40,15 +52,20 @@ export function updateHeaderBgColor(color: string) { ...@@ -40,15 +52,20 @@ export function updateHeaderBgColor(color: string) {
setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor); setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor); setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
// Determine the depth of the color value and automatically switch the theme
const isDark = colorIsDark(color); const isDark = colorIsDark(color);
appStore.commitProjectConfigState({ appStore.commitProjectConfigState({
headerSetting: { headerSetting: {
theme: isDark ? MenuThemeEnum.DARK : MenuThemeEnum.LIGHT, theme: isDark ? ThemeEnum.DARK : ThemeEnum.LIGHT,
}, },
}); });
} }
/**
* Change the background color of the left menu
* @param color bg color
*/
export function updateSidebarBgColor(color: string) { export function updateSidebarBgColor(color: string) {
if (!isHexColor(color)) return; if (!isHexColor(color)) return;
...@@ -58,11 +75,12 @@ export function updateSidebarBgColor(color: string) { ...@@ -58,11 +75,12 @@ export function updateSidebarBgColor(color: string) {
setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8)); setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8));
// only #ffffff is light // only #ffffff is light
// Only when the background color is #fff, the theme of the menu will be changed to light
const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase()); const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase());
appStore.commitProjectConfigState({ appStore.commitProjectConfigState({
menuSetting: { menuSetting: {
theme: isLight ? MenuThemeEnum.LIGHT : MenuThemeEnum.DARK, theme: isLight ? ThemeEnum.LIGHT : ThemeEnum.DARK,
}, },
}); });
} }
import type { App } from 'vue'; import type { App } from 'vue';
import { import { createStore, createLogger, Plugin } from 'vuex';
createStore,
// createLogger, Plugin
} from 'vuex';
import { config } from 'vuex-module-decorators'; import { config } from 'vuex-module-decorators';
import { isDevMode } from '/@/utils/env'; import { isDevMode } from '/@/utils/env';
config.rawError = true; config.rawError = true;
const isDev = isDevMode(); const isDev = isDevMode();
// const plugins: Plugin<any>[] = isDev ? [createLogger()] : []; const plugins: Plugin<any>[] = isDev ? [createLogger()] : [];
const store = createStore({ const store = createStore({
modules: {}, // modules: {},
strict: isDev, strict: isDev,
// plugins, plugins,
}); });
export function setupStore(app: App<Element>) { export function setupStore(app: App<Element>) {
......
// 左侧菜单, 顶部菜单 // 左侧菜单, 顶部菜单
import { MenuTypeEnum, MenuModeEnum, MenuThemeEnum, TriggerEnum } from '/@/enums/menuEnum'; import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
export interface MessageSetting { export interface MessageSetting {
title: string; title: string;
...@@ -20,7 +20,7 @@ export interface MenuSetting { ...@@ -20,7 +20,7 @@ export interface MenuSetting {
menuWidth: number; menuWidth: number;
mode: MenuModeEnum; mode: MenuModeEnum;
type: MenuTypeEnum; type: MenuTypeEnum;
theme: MenuThemeEnum; theme: ThemeEnum;
topMenuAlign: 'start' | 'center' | 'end'; topMenuAlign: 'start' | 'center' | 'end';
collapsedShowSearch: boolean; collapsedShowSearch: boolean;
trigger: TriggerEnum; trigger: TriggerEnum;
...@@ -41,7 +41,7 @@ export interface MultiTabsSetting { ...@@ -41,7 +41,7 @@ export interface MultiTabsSetting {
export interface HeaderSetting { export interface HeaderSetting {
fixed: boolean; fixed: boolean;
show: boolean; show: boolean;
theme: MenuThemeEnum; theme: ThemeEnum;
// 显示刷新按钮 // 显示刷新按钮
showRedo: boolean; showRedo: boolean;
// 显示全屏按钮 // 显示全屏按钮
......
/**
* @description: 输入框事件
*/
declare interface ChangeEvent extends Event { declare interface ChangeEvent extends Event {
target: HTMLInputElement; target: HTMLInputElement;
} }
interface WheelEvent {
declare interface WheelEvent {
path?: EventTarget[]; path?: EventTarget[];
} }
...@@ -6,7 +6,6 @@ declare interface PromiseFn<T = any, R = T> { ...@@ -6,7 +6,6 @@ declare interface PromiseFn<T = any, R = T> {
(...arg: T[]): Promise<R>; (...arg: T[]): Promise<R>;
} }
// 任意对象
declare interface IObj<T = any> { declare interface IObj<T = any> {
[key: string]: T; [key: string]: T;
[key: number]: T; [key: number]: T;
...@@ -34,19 +33,11 @@ declare type Indexable<T = any> = { ...@@ -34,19 +33,11 @@ declare type Indexable<T = any> = {
declare type Hash<T> = Indexable<T>; declare type Hash<T> = Indexable<T>;
// declare type DeepPartial<T> = {
// [P in keyof T]?: T[P] extends (infer U)[]
// ? RecursivePartial<U>[]
// : T[P] extends object
// ? RecursivePartial<T[P]>
// : T[P];
// };
declare type DeepPartial<T> = { declare type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>; [P in keyof T]?: DeepPartial<T[P]>;
}; };
declare type SelectOptions = { declare type LabelValueOptions = {
label: string; label: string;
value: any; value: any;
}[]; }[];
...@@ -54,3 +45,7 @@ declare type SelectOptions = { ...@@ -54,3 +45,7 @@ declare type SelectOptions = {
declare type EmitType = (event: string, ...args: any[]) => void; declare type EmitType = (event: string, ...args: any[]) => void;
declare type TargetContext = '_self' | '_blank'; declare type TargetContext = '_self' | '_blank';
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
declare type IntervalHandle = ReturnType<typeof setInterval>;
...@@ -2,6 +2,7 @@ import type { App } from 'vue'; ...@@ -2,6 +2,7 @@ import type { App } from 'vue';
declare global { declare global {
declare interface Window { declare interface Window {
// Global vue app instance
__APP__: App<Element>; __APP__: App<Element>;
} }
} }
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
// import { permissionStore } from '@/store/modules/permission';
// import { RoleEnum } from '@/enums/roleEnum';
/** /**
* @description: 获取token * @description: Get token
* @return jwt token
*/ */
export function getToken(): string { export function getToken(): string {
return userStore.getTokenState; return userStore.getTokenState;
......
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
export function triggerWindowResize() { export function triggerWindowResize() {
const event = document.createEvent('HTMLEvents'); const event = document.createEvent('HTMLEvents');
event.initEvent('resize', true, true); event.initEvent('resize', true, true);
(event as any).eventType = 'message'; (event as ChangeEvent).eventType = 'message';
window.dispatchEvent(event); window.dispatchEvent(event);
} }
...@@ -50,10 +50,6 @@ export function isArray(val: unknown): val is Array<any> { ...@@ -50,10 +50,6 @@ export function isArray(val: unknown): val is Array<any> {
return val && Array.isArray(val); return val && Array.isArray(val);
} }
export const isClient = () => {
return typeof window !== 'undefined';
};
export const isWindow = (val: any): val is Window => { export const isWindow = (val: any): val is Window => {
return typeof window !== 'undefined' && is(val, 'Window'); return typeof window !== 'undefined' && is(val, 'Window');
}; };
...@@ -64,6 +60,8 @@ export const isElement = (val: unknown): val is Element => { ...@@ -64,6 +60,8 @@ export const isElement = (val: unknown): val is Element => {
export const isServer = typeof window === 'undefined'; export const isServer = typeof window === 'undefined';
export const isClient = typeof window !== 'undefined';
export function isImageDom(o: Element) { export function isImageDom(o: Element) {
return o && ['IMAGE', 'IMG'].includes(o.tagName); return o && ['IMAGE', 'IMG'].includes(o.tagName);
} }
......
const projectName = import.meta.env.VITE_GLOB_APP_TITLE; const projectName = import.meta.env.VITE_GLOB_APP_TITLE;
export function warn(message: string) { export function warn(message: string) {
console.warn(`[${projectName} warn]:${message}`); console.warn(`[${projectName} warn]:${message}`);
} }
...@@ -9,9 +9,6 @@ ...@@ -9,9 +9,6 @@
export default defineComponent({ export default defineComponent({
name: 'Welcome', name: 'Welcome',
components: { House }, components: { House },
setup() {
return {};
},
}); });
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
......
import { FormSchema } from '/@/components/Form'; import { FormSchema } from '/@/components/Form';
const basicOptions: SelectOptions = [ const basicOptions: LabelValueOptions = [
{ {
label: '付晓晓', label: '付晓晓',
value: '1', value: '1',
...@@ -11,7 +11,7 @@ const basicOptions: SelectOptions = [ ...@@ -11,7 +11,7 @@ const basicOptions: SelectOptions = [
}, },
]; ];
const storeTypeOptions: SelectOptions = [ const storeTypeOptions: LabelValueOptions = [
{ {
label: '私密', label: '私密',
value: '1', value: '1',
......
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
import { Alert, Divider } from 'ant-design-vue'; import { Alert, Divider } from 'ant-design-vue';
import CurrentPermissionMode from '../CurrentPermissionMode.vue'; import CurrentPermissionMode from '../CurrentPermissionMode.vue';
import { usePermission } from '/@/hooks/web/usePermission'; import { usePermission } from '/@/hooks/web/usePermission';
import Authority from '/@/components/Authority'; import { Authority } from '/@/components/Authority';
import { getPermCodeByUserId } from '/@/api/sys/user'; import { getPermCodeByUserId } from '/@/api/sys/user';
import { permissionStore } from '/@/store/modules/permission'; import { permissionStore } from '/@/store/modules/permission';
import { PermissionModeEnum } from '/@/enums/appEnum'; import { PermissionModeEnum } from '/@/enums/appEnum';
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
import { RoleEnum } from '/@/enums/roleEnum'; import { RoleEnum } from '/@/enums/roleEnum';
import { usePermission } from '/@/hooks/web/usePermission'; import { usePermission } from '/@/hooks/web/usePermission';
import Authority from '/@/components/Authority'; import { Authority } from '/@/components/Authority';
export default defineComponent({ export default defineComponent({
components: { Alert, CurrentPermissionMode, Divider, Authority }, components: { Alert, CurrentPermissionMode, Divider, Authority },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论