提交 19011296 编写于 作者: V vben

feat: multi-language support

上级 4f8ad976
......@@ -2,7 +2,7 @@
### ✨ Refactor
- 重构整体 layout。更改代码实现方式。代码更精简,并加入多语言支持
- 重构整体 layout。更改代码实现方式。代码更精简
- 配置项重构
- 移除 messageSetting 配置
......@@ -10,6 +10,7 @@
- 缓存可以配置是否加密,默认生产环境开启 Aes 加密
- 新增标签页拖拽排序
- 除示例外加入全局国际化功能,支持中文与英文
### 🎫 Chores
......
......@@ -61,13 +61,20 @@ function varTemplate(data: string[][], name: string) {
// lastKey is a data
let pathValue = v[0].replace(/\//g, '.').split('.');
// let scopeKey = '';
// const len=pathValue.length
// const scope=pathValue[len-2]
let lastKey: string | undefined = pathValue.pop();
let deepValue: Record<any, any> = {};
if (lastKey) {
deepValue[lastKey.replace('_' + pathValue[0], '')] = lastKey;
// Solve the problem of files with the same name in different folders
const lastKeyList = lastKey.replace('_' + pathValue[0], '').split('_');
const key = lastKeyList.pop();
if (key) {
deepValue[key] = lastKey;
}
}
// Set Deep Value
deepValue = Object.assign(deepValue, dotProp.get(deepData, pathValue.join('.')));
dotProp.set(deepData, pathValue.join('.'), deepValue);
......@@ -169,7 +176,15 @@ const globTransform = function (config: SharedConfig): Transform {
if (matchedGroups && matchedGroups.length) {
const matchedSegments = matchedGroups[1]; //first everytime "Full Match"
const name = matchedGroups[2] + '_' + matchedSegments.split('/').shift();
const matchList = matchedSegments.split('/').filter(Boolean);
const lang = matchList.shift();
const scope = matchList.pop();
// Solve the problem of files with the same name in different folders
const scopeKey = scope ? `${scope}_` : '';
const fileName = matchedGroups[2];
const name = scopeKey + fileName + '_' + lang;
//send deep way like an (en/modules/system/dashboard) into groups
groups.push([matchedSegments + name, file]);
return templateRender({
......@@ -186,6 +201,10 @@ const globTransform = function (config: SharedConfig): Transform {
const filesJoined = replaceFiles.join('\n');
urlMap.set(path, filesJoined);
// console.log('======================');
// console.log(filesJoined, varTemplate(groups, name));
// console.log('======================');
return [
filesJoined,
compareString(injectPath, groups),
......
......@@ -3,7 +3,17 @@ import './index.less';
import type { MenuState } from './types';
import type { Menu as MenuType } from '/@/router/types';
import { computed, defineComponent, unref, reactive, watch, onMounted, ref, toRefs } from 'vue';
import {
computed,
defineComponent,
unref,
reactive,
watch,
onMounted,
ref,
toRefs,
ComputedRef,
} from 'vue';
import { Menu } from 'ant-design-vue';
import SearchInput from './SearchInput.vue';
import MenuContent from './MenuContent';
......@@ -34,7 +44,7 @@ export default defineComponent({
const menuState = reactive<MenuState>({
defaultSelectedKeys: [],
mode: props.mode,
theme: computed(() => props.theme),
theme: computed(() => props.theme) as ComputedRef<ThemeEnum>,
openKeys: [],
searchValue: '',
selectedKeys: [],
......
import { getI18n } from '/@/setup/i18n';
import projectSetting from '/@/settings/projectSetting';
export function useI18n(namespace?: string) {
const { t, ...methods } = getI18n().global;
function getKey(key: string) {
if (!namespace) {
return key;
......@@ -12,6 +11,18 @@ export function useI18n(namespace?: string) {
}
return `${namespace}.${key}`;
}
const normalFn = {
t: (key: string) => {
return getKey(key);
},
};
if (!projectSetting.locale.show || !getI18n()) {
return normalFn;
}
const { t, ...methods } = getI18n().global;
return {
...methods,
t: (key: string, ...arg: Parameters<typeof t>) => {
......
import { watch } from 'vue';
import { useRouter } from 'vue-router';
import { useGlobSetting } from '../setting';
import { useI18n } from './useI18n';
import { setTitle } from '/@/utils/browser';
export function useTitle() {
const { currentRoute } = useRouter();
const { t } = useI18n();
watch(
() => currentRoute.value.path,
() => {
const globSetting = useGlobSetting();
setTitle(t(currentRoute.value.meta.title), globSetting.title);
},
{ immediate: true, flush: 'post' }
);
}
......@@ -15,6 +15,7 @@ import { compile } from 'path-to-regexp';
import router from '/@/router';
import { PageEnum } from '/@/enums/pageEnum';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({
name: 'BasicBreadcrumb',
......@@ -28,7 +29,7 @@ export default defineComponent({
const itemList = ref<AppRouteRecordRaw[]>([]);
const { currentRoute, push } = useRouter();
const { t } = useI18n();
watch(
() => currentRoute.value,
() => {
......@@ -88,7 +89,7 @@ export default defineComponent({
}}
/>
)}
{item.meta.title}
{t(item.meta.title)}
</>
);
}
......
......@@ -17,7 +17,10 @@ import {
getShallowMenus,
} from '/@/router/menus';
import { permissionStore } from '/@/store/modules/permission';
import { useI18n } from '/@/hooks/web/useI18n';
import { cloneDeep } from 'lodash-es';
const { t } = useI18n();
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
// Menu array
const menusRef = ref<Menu[]>([]);
......@@ -42,6 +45,14 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit);
});
const getI18nFlatMenus = computed(() => {
return setI18nName(flatMenusRef.value, true, false);
});
const getI18nMenus = computed(() => {
return setI18nName(menusRef.value, true, true);
});
watch(
[() => unref(currentRoute).path, () => unref(splitType)],
async ([path]: [string, MenuSplitTyeEnum]) => {
......@@ -72,6 +83,18 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
genMenus();
});
function setI18nName(list: Menu[], clone = false, deep = true) {
const menus = clone ? cloneDeep(list) : list;
menus.forEach((item) => {
if (!item.name.includes('.')) return;
item.name = t(item.name);
if (item.children && deep) {
setI18nName(item.children, false, deep);
}
});
return menus;
}
// Handle left menu split
async function handleSplitLeftMenu(parentPath: string) {
if (unref(splitLeft)) return;
......@@ -109,5 +132,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
return;
}
}
return { flatMenusRef, menusRef };
return { flatMenusRef: getI18nFlatMenus, menusRef: getI18nMenus };
}
......@@ -15,6 +15,8 @@ import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useI18n } from '/@/hooks/web/useI18n';
const { t: titleT } = useI18n();
const ExtraContent: FunctionalComponent = () => {
return (
<span class={`multiple-tabs-content__extra `}>
......@@ -38,7 +40,7 @@ const TabContent: FunctionalComponent<{ tabItem: TabItem }> = (props) => {
return (
<div class={`multiple-tabs-content__content `} onContextmenu={handleContextMenu}>
<span class="ml-1">{meta && meta.title}</span>
<span class="ml-1">{meta && titleT(meta.title)}</span>
</div>
);
};
......
export default {
dashboard: 'Dashboard',
welcome: 'Home',
workbench: 'Workbench',
analysis: 'Analysis',
};
export default {
charts: 'Chart',
map: 'Map',
line: 'Line',
pie: 'Pie',
apexChart: 'ApexChart',
};
export default {
comp: 'Component',
basic: 'Basic',
transition: 'Animation',
countTo: 'Count To',
scroll: 'Scroll',
scrollBasic: 'Basic',
scrollAction: 'Scroll Function',
virtualScroll: 'Virtual Scroll',
modal: 'Modal',
drawer: 'Drawer',
desc: 'Desc',
lazy: 'Lazy',
lazyBasic: 'Basic',
lazyTransition: 'Animation',
verify: 'Verify',
verifyDrag: 'Drag ',
verifyRotate: 'Picture Restore',
qrcode: 'QR code',
strength: 'Password strength',
upload: 'Upload',
};
export default {
editor: 'Editor',
markdown: 'Markdown editor',
tinymce: 'Rich text',
tinymceBasic: 'Basic',
tinymceForm: 'embedded form',
};
export default {
excel: 'Excel',
customExport: 'Select export format',
jsonExport: 'JSON data export',
arrayExport: 'Array data export',
importExcel: 'Import',
};
export default {
feat: 'Page Function',
icon: 'Icon',
tabs: 'Tabs',
contextMenu: 'Context Menu',
download: 'Download',
clickOutSide: 'ClickOutSide',
imgPreview: 'Picture Preview',
copy: 'Clipboard',
msg: 'Message prompt',
watermark: 'Watermark',
fullScreen: 'Full Screen',
errorLog: 'Error Log',
tab: 'Tab with parameters',
tab1: 'Tab with parameter 1',
tab2: 'Tab with parameter 2',
};
export default {
form: 'Form',
basic: 'Basic',
useForm: 'useForm',
refForm: 'RefForm',
advancedForm: 'Shrinkable',
ruleForm: 'Form validation',
dynamicForm: 'Dynamic',
customerForm: 'Custom',
};
export default {
frame: 'External',
antv: 'antVue doc (embedded)',
doc: 'Project doc (embedded)',
docExternal: 'Project doc (external)',
};
export default {
page: 'Page',
form: 'Form',
formBasic: 'Basic Form',
formStep: 'Step Form',
formHigh: 'Advanced Form',
desc: 'Details',
descBasic: 'Basic Details',
descHigh: 'Advanced Details',
result: 'Result',
resultSuccess: 'Success',
resultFail: 'Failed',
account: 'Personal',
accountCenter: 'Personal Center',
accountSetting: 'Personal Settings',
exception: 'Exception',
netWorkError: 'Network Error',
notData: 'No data',
list: 'List page',
listCard: 'Card list',
};
export default {
permission: 'Permission',
front: 'front-end',
frontPage: 'Page',
frontBtn: 'Button',
frontTestA: 'Test page A',
frontTestB: 'Test page B',
back: 'background',
backPage: 'Page',
backBtn: 'Button',
};
export default {
table: 'Table',
basic: 'Basic',
treeTable: 'Tree',
fetchTable: 'Remote loading',
fixedColumn: 'Fixed column',
customerCell: 'Custom column',
formTable: 'Open search',
useTable: 'UseTable',
refTable: 'RefTable',
multipleHeader: 'MultiLevel header',
mergeHeader: 'Merge cells',
expandTable: 'Expandable table',
fixedHeight: 'Fixed height',
footerTable: 'Footer',
editCellTable: 'Editable cell',
editRowTable: 'Editable row',
};
export default {
tree: 'Tree',
basic: 'Basic',
editTree: 'Right-click',
actionTree: 'Function operation',
};
export default {
operationFailed: 'Operation failed',
errorTip: 'Error Tip',
errorMessage: 'The operation failed, the system is abnormal!',
timeoutMessage: 'Login timed out, please log in again!',
apiTimeoutMessage: 'The interface request timed out, please refresh the page and try again!',
networkException: 'network anomaly',
networkExceptionMsg: 'Please check if your network connection is normal! The network is abnormal',
errMsg401: 'The user does not have permission (token, user name, password error)!',
errMsg403: 'The user is authorized, but access is forbidden!',
errMsg404: 'Network request error, the resource was not found!',
errMsg405: 'Network request error, request method not allowed!',
errMsg408: 'Network request timed out!',
errMsg500: 'Server error, please contact the administrator!',
errMsg501: 'The network is not implemented!',
errMsg502: 'Network Error!',
errMsg503: 'The service is unavailable, the server is temporarily overloaded or maintained!',
errMsg504: 'Network timeout!',
errMsg505: 'The http version does not support the request!',
};
export default {
loginOutTip: 'Reminder',
loginOutMessage: 'Confirm to exit the system?',
menuLoading: 'Menu loading...',
};
export default {
loadingText: '加载中...',
cancelText: '关闭',
okText: '确认',
};
export default {
dashboard: 'Dashboard',
welcome: '首页',
workbench: '工作台',
analysis: '分析页',
};
export default {
charts: '图表库',
map: '地图',
line: '折线图',
pie: '饼图',
apexChart: 'ApexChart',
};
export default {
comp: '组件',
basic: '基础组件',
transition: '动画组件',
countTo: '数字动画',
scroll: '滚动组件',
scrollBasic: '基础滚动',
scrollAction: '滚动函数',
virtualScroll: '虚拟滚动',
modal: '弹窗扩展',
drawer: '抽屉扩展',
desc: '详情组件',
lazy: '懒加载组件',
lazyBasic: '基础示例',
lazyTransition: '动画效果',
verify: '验证组件',
verifyDrag: '拖拽校验',
verifyRotate: '图片还原',
qrcode: '二维码组件',
strength: '密码强度组件',
upload: '上传组件',
};
export default {
editor: '编辑器',
markdown: 'markdown编辑器',
tinymce: '富文本',
tinymceBasic: '基础使用',
tinymceForm: '嵌入form',
};
export default {
excel: 'Excel',
customExport: '选择导出格式',
jsonExport: 'JSON数据导出',
arrayExport: 'Array数据导出',
importExcel: '导入',
};
export default {
feat: '页面功能',
icon: '图标',
tabs: '标签页操作',
contextMenu: '右键菜单',
download: '文件下载',
clickOutSide: 'ClickOutSide组件',
imgPreview: '图片预览',
copy: '剪切板',
msg: '消息提示',
watermark: '水印',
fullScreen: '全屏',
errorLog: '错误日志',
tab: 'Tab带参',
tab1: 'Tab带参1',
tab2: 'Tab带参2',
};
export default {
form: 'Form',
basic: '基础表单',
useForm: 'useForm',
refForm: 'RefForm',
advancedForm: '可收缩表单',
ruleForm: '表单验证',
dynamicForm: '动态表单',
customerForm: '自定义组件',
};
export default {
frame: '外部页面',
antv: 'antVue文档(内嵌)',
doc: '项目文档(内嵌)',
docExternal: '项目文档(外链)',
};
export default {
page: '页面',
form: '表单页',
formBasic: '基础表单',
formStep: '分步表单',
formHigh: '高级表单',
desc: '详情页',
descBasic: '基础详情页',
descHigh: '高级详情页',
result: '结果页',
resultSuccess: '成功页',
resultFail: '失败页',
account: '个人页',
accountCenter: '个人中心',
accountSetting: '个人设置',
exception: '异常页',
netWorkError: '网络错误',
notData: '无数据',
list: '列表页',
listCard: '卡片列表',
};
export default {
permission: '权限管理',
front: '基于前端权限',
frontPage: '页面权限',
frontBtn: '按钮权限',
frontTestA: '权限测试页A',
frontTestB: '权限测试页B',
back: '基于后台权限',
backPage: '页面权限',
backBtn: '按钮权限',
};
export default {
table: 'Table',
basic: '基础表格',
treeTable: '树形表格',
fetchTable: '远程加载示例',
fixedColumn: '固定列',
customerCell: '自定义列',
formTable: '开启搜索区域',
useTable: 'UseTable',
refTable: 'RefTable',
multipleHeader: '多级表头',
mergeHeader: '合并单元格',
expandTable: '可展开表格',
fixedHeight: '定高/头部自定义',
footerTable: '表尾行合计',
editCellTable: '可编辑单元格',
editRowTable: '可编辑行',
};
export default {
tree: 'Tree',
basic: '基础树',
editTree: '右键示例',
actionTree: '函数操作示例',
};
export default {
operationFailed: '操作失败',
errorTip: '错误提示',
errorMessage: '操作失败,系统异常!',
timeoutMessage: '登录超时,请重新登录!',
apiTimeoutMessage: '接口请求超时,请刷新页面重试!',
networkException: '网络异常',
networkExceptionMsg: '网请检查您的网络连接是否正常!络异常',
errMsg401: '用户没有权限(令牌、用户名、密码错误)!',
errMsg403: '用户得到授权,但是访问是被禁止的。!',
errMsg404: '网络请求错误,未找到该资源!',
errMsg405: '网络请求错误,请求方法未允许!',
errMsg408: '网络请求超时!',
errMsg500: '服务器错误,请联系管理员!',
errMsg501: '网络未实现!',
errMsg502: '网络错误!',
errMsg503: '服务不可用,服务器暂时过载或维护!',
errMsg504: '网络超时!',
errMsg505: 'http版本不支持该请求!',
};
export default {
loginOutTip: '温馨提醒',
loginOutMessage: '是否确认退出系统?',
menuLoading: '菜单加载中...',
};
......@@ -13,6 +13,7 @@ import { setTitle } from '/@/utils/browser';
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
import { tabStore } from '/@/store/modules/tab';
import { useI18n } from '/@/hooks/web/useI18n';
const { closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
const globSetting = useGlobSetting();
......@@ -54,8 +55,9 @@ export function createGuard(router: Router) {
});
router.afterEach((to) => {
const { t } = useI18n();
// change html title
setTitle(to.meta.title, globSetting.title);
setTitle(t(to.meta.title), globSetting.title);
});
createProgressGuard(router);
createPermissionGuard(router);
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 10,
menu: {
name: 'Dashboard',
name: 'routes.dashboard.dashboard',
path: '/dashboard',
// tag: {
// dot: true,
// },
children: [
{
path: '/workbench',
name: '工作台',
// tag: {
// content: 'new',
// },
name: 'routes.dashboard.workbench',
},
{
path: '/analysis',
name: '分析页',
name: 'routes.dashboard.analysis',
},
{
path: '/welcome',
name: '首页',
name: 'routes.dashboard.welcome',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 500,
menu: {
name: '图表',
name: 'routes.demo.charts.charts',
path: '/charts',
children: [
{
path: 'apexChart',
name: 'ApexChart',
name: 'routes.demo.charts.apexChart',
},
{
path: 'echarts',
......@@ -15,15 +16,15 @@ const menu: MenuModule = {
children: [
{
path: 'map',
name: '地图',
name: 'routes.demo.charts.map',
},
{
path: 'line',
name: '折线图',
name: 'routes.demo.charts.line',
},
{
path: 'pie',
name: '饼图',
name: 'routes.demo.charts.pie',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 30,
menu: {
name: '组件',
name: 'routes.demo.comp.comp',
path: '/comp',
children: [
{
path: 'basic',
name: '基础组件',
name: 'routes.demo.comp.basic',
},
{
path: 'countTo',
name: '数字动画',
name: 'routes.demo.comp.countTo',
},
{
path: 'transition',
name: '动画组件',
name: 'routes.demo.comp.transition',
},
{
path: 'modal',
name: '弹窗扩展',
name: 'routes.demo.comp.modal',
},
{
path: 'drawer',
name: '抽屉扩展',
name: 'routes.demo.comp.drawer',
},
{
path: 'desc',
name: '详情组件',
name: 'routes.demo.comp.desc',
},
{
path: 'qrcode',
name: '二维码组件',
name: 'routes.demo.comp.qrcode',
},
{
path: 'strength-meter',
name: '密码强度组件',
name: 'routes.demo.comp.strength',
},
{
path: 'upload',
name: '上传组件',
name: 'routes.demo.comp.upload',
},
{
path: 'scroll',
name: '滚动组件',
name: 'routes.demo.comp.scroll',
children: [
{
path: 'basic',
name: '基础示例',
name: 'routes.demo.comp.scrollBasic',
},
{
path: 'action',
name: '函数操作示例',
name: 'routes.demo.comp.scrollAction',
},
{
path: 'virtualScroll',
name: '虚拟滚动',
name: 'routes.demo.comp.virtualScroll',
},
],
},
{
path: 'lazy',
name: '懒加载组件',
name: 'routes.demo.comp.lazy',
children: [
{
path: 'basic',
name: '基础示例',
name: 'routes.demo.comp.lazyBasic',
},
{
path: 'transition',
name: '动画效果',
name: 'routes.demo.comp.lazyTransition',
},
],
},
{
path: 'verify',
name: '验证组件',
name: 'routes.demo.comp.verify',
children: [
{
path: 'drag',
name: '拖拽校验',
name: 'routes.demo.comp.verifyDrag',
},
{
path: 'rotate',
name: '图片还原校验',
},
],
},
{
path: '/form',
name: '验证组件',
children: [
{
path: '/base',
name: '拖拽校验',
name: 'routes.demo.comp.verifyRotate',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 500,
menu: {
name: '编辑器',
name: 'routes.demo.editor.editor',
path: '/editor',
children: [
{
path: 'markdown',
name: 'markdown编辑器',
name: 'routes.demo.editor.markdown',
},
{
path: 'tinymce',
name: '富文本',
name: 'routes.demo.editor.tinymce',
children: [
{
path: 'index',
name: '基础使用',
name: 'routes.demo.editor.tinymceBasic',
},
{
path: 'editor',
name: '嵌入form使用',
name: 'routes.demo.editor.tinymceForm',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 500,
menu: {
name: 'Excel',
name: 'routes.demo.excel.excel',
path: '/excel',
children: [
{
path: 'customExport',
name: '选择导出格式',
name: 'routes.demo.excel.customExport',
},
{
path: 'jsonExport',
name: 'JSON数据导出',
name: 'routes.demo.excel.jsonExport',
},
{
path: 'arrayExport',
name: 'Array数据导出',
name: 'routes.demo.excel.arrayExport',
},
{
path: 'importExcel',
name: '导入',
name: 'routes.demo.excel.importExcel',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 19,
menu: {
name: '功能',
name: 'routes.demo.feat.feat',
path: '/feat',
children: [
{
path: 'icon',
name: '图标',
name: 'routes.demo.feat.icon',
},
{
path: 'tabs',
name: '标签页操作',
name: 'routes.demo.feat.tabs',
},
{
path: 'context-menu',
name: '右键菜单',
name: 'routes.demo.feat.contextMenu',
},
{
path: 'download',
name: '文件下载',
name: 'routes.demo.feat.download',
},
{
path: 'click-out-side',
name: 'ClickOutSide',
name: 'routes.demo.feat.clickOutSide',
},
{
path: 'img-preview',
name: '图片预览',
name: 'routes.demo.feat.imgPreview',
},
{
path: 'copy',
name: '剪切板',
name: 'routes.demo.feat.copy',
},
{
path: 'msg',
name: '消息提示',
name: 'routes.demo.feat.msg',
},
{
path: 'watermark',
name: '水印',
name: 'routes.demo.feat.watermark',
},
{
path: 'full-screen',
name: '全屏',
name: 'routes.demo.feat.fullScreen',
},
{
path: 'error-log',
name: '错误日志',
name: 'routes.demo.feat.errorLog',
},
{
path: 'testTab',
name: '带参Tab',
name: 'routes.demo.feat.tab',
children: [
{
path: 'id1',
name: '带参tab1',
name: 'routes.demo.feat.tab1',
},
{
path: 'id2',
name: '带参tab2',
name: 'routes.demo.feat.tab2',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 40,
menu: {
path: '/form',
name: 'Form',
name: 'routes.demo.form.form',
children: [
{
path: 'basic',
name: '基础表单',
name: 'routes.demo.form.basic',
},
{
path: 'useForm',
name: 'useForm',
name: 'routes.demo.form.useForm',
},
{
path: 'refForm',
name: 'RefForm',
name: 'routes.demo.form.refForm',
},
{
path: 'advancedForm',
name: '可收缩表单',
name: 'routes.demo.form.advancedForm',
},
{
path: 'ruleForm',
name: '表单校验',
name: 'routes.demo.form.ruleForm',
},
{
path: 'dynamicForm',
name: '动态表单',
name: 'routes.demo.form.dynamicForm',
},
{
path: 'customerForm',
name: '自定义组件',
name: 'routes.demo.form.customerForm',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 1000,
menu: {
name: '外部页面',
name: 'routes.demo.iframe.frame',
path: '/frame',
children: [
{
path: 'antv',
name: 'antVue文档(内嵌)',
name: 'routes.demo.iframe.antv',
},
{
path: 'doc',
name: '项目文档(内嵌)',
name: 'routes.demo.iframe.doc',
},
{
path: 'docExternal',
name: '项目文档(外链)',
name: 'routes.demo.iframe.docExternal',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 20,
menu: {
name: '页面',
name: 'routes.demo.page.page',
path: '/page-demo',
tag: {
dot: true,
......@@ -10,56 +11,56 @@ const menu: MenuModule = {
children: [
{
path: 'form',
name: '表单页',
name: 'routes.demo.page.form',
children: [
{
path: 'basic',
name: '基础表单',
name: 'routes.demo.page.formBasic',
},
{
path: 'step',
name: '分步表单',
name: 'routes.demo.page.formStep',
},
{
path: 'high',
name: '高级表单',
name: 'routes.demo.page.formHigh',
},
],
},
{
path: 'desc',
name: '详情页',
name: 'routes.demo.page.desc',
children: [
{
path: 'basic',
name: '基础详情页',
name: 'routes.demo.page.descBasic',
},
{
path: 'high',
name: '高级详情页',
name: 'routes.demo.page.descHigh',
},
],
},
{
path: 'result',
name: '结果页',
name: 'routes.demo.page.result',
children: [
{
path: 'success',
name: '成功页',
name: 'routes.demo.page.resultSuccess',
},
{
path: 'fail',
name: '失败页',
name: 'routes.demo.page.resultFail',
},
],
},
{
path: 'exception',
name: '异常页',
name: 'routes.demo.page.exception',
children: [
{
path: '403',
......@@ -75,38 +76,38 @@ const menu: MenuModule = {
},
{
path: 'net-work-error',
name: '网络错误',
name: 'routes.demo.page.netWorkError',
},
{
path: 'not-data',
name: '无数据',
name: 'routes.demo.page.notData',
},
],
},
{
path: 'account',
name: '个人页',
name: 'routes.demo.page.account',
children: [
{
path: 'center',
name: '个人中心',
name: 'routes.demo.page.accountCenter',
},
{
path: 'setting',
name: '个人设置',
name: 'routes.demo.page.accountSetting',
},
],
},
{
path: 'list',
name: '列表页',
name: 'routes.demo.page.list',
tag: {
content: 'new',
},
children: [
{
path: 'card',
name: '卡片列表',
name: 'routes.demo.page.listCard',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 15,
menu: {
name: '权限管理',
name: 'routes.demo.permission.permission',
path: '/permission',
children: [
{
path: 'front',
name: '基于前端',
name: 'routes.demo.permission.front',
children: [
{
path: 'page',
name: '页面权限',
name: 'routes.demo.permission.frontPage',
},
{
path: 'btn',
name: '按钮权限',
name: 'routes.demo.permission.frontBtn',
},
{
path: 'auth-pageA',
name: '权限测试页A',
name: 'routes.demo.permission.frontTestA',
},
{
path: 'auth-pageB',
name: '权限测试页B',
name: 'routes.demo.permission.frontTestB',
},
],
},
{
path: 'back',
name: '基于后台',
name: 'routes.demo.permission.back',
children: [
{
path: 'page',
name: '页面权限',
name: 'routes.demo.permission.backPage',
},
{
path: 'btn',
name: '按钮权限',
name: 'routes.demo.permission.backBtn',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 30,
menu: {
path: '/table',
name: 'Table',
name: 'routes.demo.table.table',
children: [
{
path: 'basic',
name: '基础表格',
name: 'routes.demo.table.basic',
},
{
path: 'treeTable',
name: '树形表格',
name: 'routes.demo.table.treeTable',
},
{
path: 'fetchTable',
name: '远程加载',
name: 'routes.demo.table.fetchTable',
},
{
path: 'fixedColumn',
name: '固定列',
name: 'routes.demo.table.fixedColumn',
},
{
path: 'customerCell',
name: '自定义列',
name: 'routes.demo.table.customerCell',
},
{
path: 'formTable',
name: '开启搜索区域',
name: 'routes.demo.table.formTable',
},
{
path: 'useTable',
name: 'UseTable',
name: 'routes.demo.table.useTable',
},
{
path: 'refTable',
name: 'RefTable',
name: 'routes.demo.table.refTable',
},
{
path: 'multipleHeader',
name: '多级表头',
name: 'routes.demo.table.multipleHeader',
},
{
path: 'mergeHeader',
name: '合并单元格',
name: 'routes.demo.table.mergeHeader',
},
{
path: 'expandTable',
name: '可展开表格',
name: 'routes.demo.table.expandTable',
},
{
path: 'fixedHeight',
name: '定高/头部自定义',
name: 'routes.demo.table.fixedHeight',
},
{
path: 'footerTable',
name: '表尾行合计',
name: 'routes.demo.table.footerTable',
},
{
path: 'editCellTable',
name: '可编辑单元格',
name: 'routes.demo.table.editCellTable',
},
{
path: 'editRowTable',
name: '可编辑行',
name: 'routes.demo.table.editRowTable',
},
],
},
......
import type { MenuModule } from '/@/router/types.d';
const menu: MenuModule = {
orderNo: 50,
menu: {
path: '/tree',
name: 'Tree',
name: 'routes.demo.tree.tree',
children: [
{
path: 'basic',
name: '基础示例',
name: 'routes.demo.tree.basic',
},
{
path: 'editTree',
name: '右键示例',
name: 'routes.demo.tree.editTree',
},
{
path: 'actionTree',
name: '函数操作示例',
name: 'routes.demo.tree.actionTree',
},
],
},
......
......@@ -33,7 +33,7 @@ export const LoginRoute: AppRouteRecordRaw = {
name: 'Login',
component: () => import('/@/views/sys/login/Login.vue'),
meta: {
title: '登录',
title: 'routes.basic.login',
},
};
......
......@@ -10,7 +10,7 @@ const dashboard: AppRouteModule = {
redirect: '/dashboard/workbench',
meta: {
icon: 'ant-design:home-outlined',
title: 'Dashboard',
title: 'routes.dashboard.dashboard',
},
},
......@@ -20,7 +20,7 @@ const dashboard: AppRouteModule = {
name: 'Welcome',
component: () => import('/@/views/dashboard/welcome/index.vue'),
meta: {
title: '首页',
title: 'routes.dashboard.welcome',
},
},
{
......@@ -28,7 +28,7 @@ const dashboard: AppRouteModule = {
name: 'Workbench',
component: () => import('/@/views/dashboard/workbench/index.vue'),
meta: {
title: '工作台',
title: 'routes.dashboard.workbench',
affix: true,
},
},
......@@ -37,7 +37,7 @@ const dashboard: AppRouteModule = {
name: 'Analysis',
component: () => import('/@/views/dashboard/analysis/index.vue'),
meta: {
title: '分析页',
title: 'routes.dashboard.analysis',
},
},
],
......
......@@ -10,7 +10,7 @@ const charts: AppRouteModule = {
redirect: '/charts/apexChart',
meta: {
icon: 'ant-design:area-chart-outlined',
title: '图表库',
title: 'routes.demo.charts.charts',
},
},
......@@ -27,7 +27,7 @@ const charts: AppRouteModule = {
name: 'Map',
component: () => import('/@/views/demo/echarts/Map.vue'),
meta: {
title: '地图',
title: 'routes.demo.charts.map',
},
},
{
......@@ -35,7 +35,7 @@ const charts: AppRouteModule = {
name: 'Line',
component: () => import('/@/views/demo/echarts/Line.vue'),
meta: {
title: '折线图',
title: 'routes.demo.charts.line',
},
},
{
......@@ -43,7 +43,7 @@ const charts: AppRouteModule = {
name: 'Pie',
component: () => import('/@/views/demo/echarts/Pie.vue'),
meta: {
title: '饼图',
title: 'routes.demo.charts.pie',
},
},
],
......@@ -52,7 +52,7 @@ const charts: AppRouteModule = {
path: '/apexChart',
name: 'ApexChart',
meta: {
title: 'ApexChart',
title: 'routes.demo.charts.apexChart',
},
component: () => import('/@/views/demo/echarts/apex/index.vue'),
},
......
......@@ -10,7 +10,7 @@ const comp: AppRouteModule = {
redirect: '/comp/basic',
meta: {
icon: 'ant-design:table-outlined',
title: '组件',
title: 'routes.demo.comp.comp',
},
},
......@@ -20,7 +20,7 @@ const comp: AppRouteModule = {
name: 'BasicDemo',
component: () => import('/@/views/demo/comp/button/index.vue'),
meta: {
title: '基础组件',
title: 'routes.demo.comp.basic',
},
},
{
......@@ -28,7 +28,7 @@ const comp: AppRouteModule = {
name: 'transitionDemo',
component: () => import('/@/views/demo/comp/transition/index.vue'),
meta: {
title: '动画组件',
title: 'routes.demo.comp.transition',
},
},
{
......@@ -36,7 +36,7 @@ const comp: AppRouteModule = {
name: 'CountTo',
component: () => import('/@/views/demo/comp/count-to/index.vue'),
meta: {
title: '数字动画',
title: 'routes.demo.comp.countTo',
},
},
......@@ -45,7 +45,7 @@ const comp: AppRouteModule = {
name: 'ScrollDemo',
redirect: '/comp/scroll/basic',
meta: {
title: '滚动组件',
title: 'routes.demo.comp.scroll',
},
children: [
{
......@@ -53,7 +53,7 @@ const comp: AppRouteModule = {
name: 'BasicScrollDemo',
component: () => import('/@/views/demo/comp/scroll/index.vue'),
meta: {
title: '基础滚动',
title: 'routes.demo.comp.scrollBasic',
},
},
{
......@@ -61,7 +61,7 @@ const comp: AppRouteModule = {
name: 'ActionScrollDemo',
component: () => import('/@/views/demo/comp/scroll/Action.vue'),
meta: {
title: '滚动函数',
title: 'routes.demo.comp.scrollAction',
},
},
{
......@@ -69,7 +69,7 @@ const comp: AppRouteModule = {
name: 'VirtualScrollDemo',
component: () => import('/@/views/demo/comp/scroll/VirtualScroll.vue'),
meta: {
title: '虚拟滚动',
title: 'routes.demo.comp.virtualScroll',
},
},
],
......@@ -80,7 +80,7 @@ const comp: AppRouteModule = {
name: 'ModalDemo',
component: () => import('/@/views/demo/comp/modal/index.vue'),
meta: {
title: '弹窗扩展',
title: 'routes.demo.comp.modal',
},
},
{
......@@ -88,7 +88,7 @@ const comp: AppRouteModule = {
name: 'DrawerDemo',
component: () => import('/@/views/demo/comp/drawer/index.vue'),
meta: {
title: '抽屉扩展',
title: 'routes.demo.comp.drawer',
},
},
{
......@@ -96,7 +96,7 @@ const comp: AppRouteModule = {
name: 'DescDemo',
component: () => import('/@/views/demo/comp/desc/index.vue'),
meta: {
title: '详情组件',
title: 'routes.demo.comp.desc',
},
},
......@@ -105,7 +105,7 @@ const comp: AppRouteModule = {
name: 'lazyDemo',
redirect: '/comp/lazy/basic',
meta: {
title: '懒加载组件',
title: 'routes.demo.comp.lazy',
},
children: [
{
......@@ -113,7 +113,7 @@ const comp: AppRouteModule = {
name: 'BasicLazyDemo',
component: () => import('/@/views/demo/comp/lazy/index.vue'),
meta: {
title: '基础示例',
title: 'routes.demo.comp.lazyBasic',
},
},
{
......@@ -121,7 +121,7 @@ const comp: AppRouteModule = {
name: 'BasicTransitionDemo',
component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
meta: {
title: '动画效果',
title: 'routes.demo.comp.lazyTransition',
},
},
],
......@@ -131,7 +131,7 @@ const comp: AppRouteModule = {
name: 'VerifyDemo',
redirect: '/comp/verify/drag',
meta: {
title: '验证组件',
title: 'routes.demo.comp.verify',
},
children: [
{
......@@ -139,7 +139,7 @@ const comp: AppRouteModule = {
name: 'VerifyDragDemo',
component: () => import('/@/views/demo/comp/verify/index.vue'),
meta: {
title: '拖拽校验',
title: 'routes.demo.comp.verifyDrag',
},
},
{
......@@ -147,7 +147,7 @@ const comp: AppRouteModule = {
name: 'VerifyRotateDemo',
component: () => import('/@/views/demo/comp/verify/Rotate.vue'),
meta: {
title: '图片还原',
title: 'routes.demo.comp.verifyRotate',
},
},
],
......@@ -159,7 +159,7 @@ const comp: AppRouteModule = {
name: 'QrCodeDemo',
component: () => import('/@/views/demo/comp/qrcode/index.vue'),
meta: {
title: '二维码组件',
title: 'routes.demo.comp.qrcode',
},
},
{
......@@ -167,7 +167,7 @@ const comp: AppRouteModule = {
name: 'StrengthMeterDemo',
component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
meta: {
title: '密码强度组件',
title: 'routes.demo.comp.strength',
},
},
{
......@@ -175,7 +175,7 @@ const comp: AppRouteModule = {
name: 'UploadDemo',
component: () => import('/@/views/demo/comp/upload/index.vue'),
meta: {
title: '上传组件',
title: 'routes.demo.comp.upload',
},
},
],
......
......@@ -10,7 +10,7 @@ const editor: AppRouteModule = {
redirect: '/editor/markdown',
meta: {
icon: 'ant-design:table-outlined',
title: '编辑器',
title: 'routes.demo.editor.editor',
},
},
......@@ -20,14 +20,14 @@ const editor: AppRouteModule = {
name: 'MarkdownDemo',
component: () => import('/@/views/demo/editor/Markdown.vue'),
meta: {
title: 'markdown编辑器',
title: 'routes.demo.editor.markdown',
},
},
{
path: '/tinymce',
name: 'TinymceDemo',
meta: {
title: '富文本',
title: 'routes.demo.editor.tinymce',
},
redirect: '/editor/tinymce/index',
children: [
......@@ -36,7 +36,7 @@ const editor: AppRouteModule = {
name: 'TinymceBasicDemo',
component: () => import('/@/views/demo/editor/tinymce/index.vue'),
meta: {
title: '基础使用',
title: 'routes.demo.editor.tinymceBasic',
},
},
// TODO
......@@ -45,7 +45,7 @@ const editor: AppRouteModule = {
name: 'TinymceFormDemo',
component: () => import('/@/views/demo/editor/tinymce/Editor.vue'),
meta: {
title: '嵌入form使用',
title: 'routes.demo.editor.tinymceForm',
},
},
],
......
......@@ -10,7 +10,7 @@ const excel: AppRouteModule = {
redirect: '/excel/customExport',
meta: {
icon: 'mdi:microsoft-excel',
title: 'Excel',
title: 'routes.demo.excel.excel',
},
},
......@@ -20,7 +20,7 @@ const excel: AppRouteModule = {
name: 'CustomExport',
component: () => import('/@/views/demo/excel/CustomExport.vue'),
meta: {
title: '选择导出格式',
title: 'routes.demo.excel.customExport',
},
},
{
......@@ -28,7 +28,7 @@ const excel: AppRouteModule = {
name: 'JsonExport',
component: () => import('/@/views/demo/excel/JsonExport.vue'),
meta: {
title: 'JSON数据导出',
title: 'routes.demo.excel.jsonExport',
},
},
{
......@@ -36,7 +36,7 @@ const excel: AppRouteModule = {
name: 'ArrayExport',
component: () => import('/@/views/demo/excel/ArrayExport.vue'),
meta: {
title: 'Array数据导出',
title: 'routes.demo.excel.arrayExport',
},
},
{
......@@ -44,7 +44,7 @@ const excel: AppRouteModule = {
name: 'ImportExcel',
component: () => import('/@/views/demo/excel/ImportExcel.vue'),
meta: {
title: '导入',
title: 'routes.demo.excel.importExcel',
},
},
],
......
......@@ -10,7 +10,7 @@ const feat: AppRouteModule = {
redirect: '/feat/icon',
meta: {
icon: 'ic:outline-featured-play-list',
title: '页面功能',
title: 'routes.demo.feat.feat',
},
},
......@@ -20,7 +20,7 @@ const feat: AppRouteModule = {
name: 'IconDemo',
component: () => import('/@/views/demo/feat/icon/index.vue'),
meta: {
title: '图标',
title: 'routes.demo.feat.icon',
},
},
{
......@@ -28,7 +28,7 @@ const feat: AppRouteModule = {
name: 'TabsDemo',
component: () => import('/@/views/demo/feat/tabs/index.vue'),
meta: {
title: '标签页操作',
title: 'routes.demo.feat.tabs',
},
},
......@@ -37,7 +37,7 @@ const feat: AppRouteModule = {
name: 'ContextMenuDemo',
component: () => import('/@/views/demo/feat/context-menu/index.vue'),
meta: {
title: '右键菜单',
title: 'routes.demo.feat.contextMenu',
},
},
{
......@@ -45,7 +45,7 @@ const feat: AppRouteModule = {
name: 'DownLoadDemo',
component: () => import('/@/views/demo/feat/download/index.vue'),
meta: {
title: '文件下载',
title: 'routes.demo.feat.download',
},
},
{
......@@ -53,7 +53,7 @@ const feat: AppRouteModule = {
name: 'ClickOutSideDemo',
component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
meta: {
title: 'ClickOutSide组件',
title: 'routes.demo.feat.clickOutSide',
},
},
{
......@@ -61,7 +61,7 @@ const feat: AppRouteModule = {
name: 'ImgPreview',
component: () => import('/@/views/demo/feat/img-preview/index.vue'),
meta: {
title: '图片预览',
title: 'routes.demo.feat.imgPreview',
},
},
{
......@@ -69,7 +69,7 @@ const feat: AppRouteModule = {
name: 'CopyDemo',
component: () => import('/@/views/demo/feat/copy/index.vue'),
meta: {
title: '剪切板',
title: 'routes.demo.feat.copy',
},
},
{
......@@ -77,7 +77,7 @@ const feat: AppRouteModule = {
name: 'MsgDemo',
component: () => import('/@/views/demo/feat/msg/index.vue'),
meta: {
title: '消息提示',
title: 'routes.demo.feat.msg',
},
},
{
......@@ -85,7 +85,7 @@ const feat: AppRouteModule = {
name: 'WatermarkDemo',
component: () => import('/@/views/demo/feat/watermark/index.vue'),
meta: {
title: '水印',
title: 'routes.demo.feat.watermark',
},
},
{
......@@ -93,7 +93,7 @@ const feat: AppRouteModule = {
name: 'FullScreenDemo',
component: () => import('/@/views/demo/feat/full-screen/index.vue'),
meta: {
title: '全屏',
title: 'routes.demo.feat.fullScreen',
},
},
{
......@@ -101,7 +101,7 @@ const feat: AppRouteModule = {
name: 'ErrorLog',
component: () => import('/@/views/sys/error-log/index.vue'),
meta: {
title: '错误日志',
title: 'routes.demo.feat.errorLog',
},
},
{
......@@ -109,7 +109,7 @@ const feat: AppRouteModule = {
name: 'TestTab',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
title: 'Tab带参',
title: 'routes.demo.feat.tab',
carryParam: true,
},
},
......
......@@ -10,7 +10,7 @@ const form: AppRouteModule = {
redirect: '/form/basic',
meta: {
icon: 'ant-design:table-outlined',
title: 'Form',
title: 'rroutes.demo.form.form',
},
},
......@@ -20,7 +20,7 @@ const form: AppRouteModule = {
name: 'FormBasicDemo',
component: () => import('/@/views/demo/form/index.vue'),
meta: {
title: '基础表单',
title: 'rroutes.demo.form.basic',
},
},
{
......@@ -28,7 +28,7 @@ const form: AppRouteModule = {
name: 'UseFormDemo',
component: () => import('/@/views/demo/form/UseForm.vue'),
meta: {
title: 'useForm',
title: 'rroutes.demo.form.useForm',
},
},
{
......@@ -36,7 +36,7 @@ const form: AppRouteModule = {
name: 'RefFormDemo',
component: () => import('/@/views/demo/form/RefForm.vue'),
meta: {
title: 'RefForm',
title: 'rroutes.demo.form.refForm',
},
},
{
......@@ -44,7 +44,7 @@ const form: AppRouteModule = {
name: 'AdvancedFormDemo',
component: () => import('/@/views/demo/form/AdvancedForm.vue'),
meta: {
title: '可收缩表单',
title: 'rroutes.demo.form.advancedForm',
},
},
{
......@@ -52,7 +52,7 @@ const form: AppRouteModule = {
name: 'RuleFormDemo',
component: () => import('/@/views/demo/form/RuleForm.vue'),
meta: {
title: '表单验证',
title: 'rroutes.demo.form.ruleForm',
},
},
{
......@@ -60,7 +60,7 @@ const form: AppRouteModule = {
name: 'DynamicFormDemo',
component: () => import('/@/views/demo/form/DynamicForm.vue'),
meta: {
title: '动态表单',
title: 'rroutes.demo.form.dynamicForm',
},
},
{
......@@ -68,7 +68,7 @@ const form: AppRouteModule = {
name: 'CustomerFormDemo',
component: () => import('/@/views/demo/form/CustomerForm.vue'),
meta: {
title: '自定义组件',
title: 'rroutes.demo.form.customerForm',
},
},
],
......
......@@ -11,7 +11,7 @@ const iframe: AppRouteModule = {
redirect: '/frame/antv',
meta: {
icon: 'mdi:page-next-outline',
title: '外部页面',
title: 'routes.demo.iframe.frame',
},
},
......@@ -22,7 +22,7 @@ const iframe: AppRouteModule = {
component: IFrame,
meta: {
frameSrc: 'https://2x.antdv.com/docs/vue/introduce-cn/',
title: 'antVue文档(内嵌)',
title: 'routes.demo.iframe.antv',
afterCloseLoading: true,
},
},
......@@ -32,7 +32,7 @@ const iframe: AppRouteModule = {
component: IFrame,
meta: {
frameSrc: 'https://vvbin.cn/doc-next/',
title: '项目文档(内嵌)',
title: 'routes.demo.iframe.doc',
afterCloseLoading: true,
},
},
......@@ -42,7 +42,7 @@ const iframe: AppRouteModule = {
component: IFrame,
meta: {
externalLink: 'https://vvbin.cn/doc-next/',
title: '项目文档(外链)',
title: 'routes.demo.iframe.docExternal',
},
},
],
......
......@@ -12,7 +12,7 @@ const page: AppRouteModule = {
redirect: '/page-demo/exception',
meta: {
icon: 'mdi:page-next-outline',
title: '页面',
title: 'routes.demo.page.page',
},
children: [
// =============================form start=============================
......@@ -21,7 +21,7 @@ const page: AppRouteModule = {
name: 'FormPage',
redirect: '/page-demo/form/basic',
meta: {
title: '表单页',
title: 'routes.demo.page.form',
},
children: [
{
......@@ -29,7 +29,7 @@ const page: AppRouteModule = {
name: 'FormBasicPage',
component: () => import('/@/views/demo/page/form/basic/index.vue'),
meta: {
title: '基础表单',
title: 'routes.demo.page.formBasic',
},
},
{
......@@ -37,7 +37,7 @@ const page: AppRouteModule = {
name: 'FormStepPage',
component: () => import('/@/views/demo/page/form/step/index.vue'),
meta: {
title: '分步表单',
title: 'routes.demo.page.formStep',
},
},
{
......@@ -45,7 +45,7 @@ const page: AppRouteModule = {
name: 'FormHightPage',
component: () => import('/@/views/demo/page/form/high/index.vue'),
meta: {
title: '高级表单',
title: 'routes.demo.page.formHigh',
},
},
],
......@@ -57,7 +57,7 @@ const page: AppRouteModule = {
name: 'DescPage',
redirect: '/page-demo/desc/basic',
meta: {
title: '详情页',
title: 'routes.demo.page.desc',
},
children: [
{
......@@ -65,7 +65,7 @@ const page: AppRouteModule = {
name: 'DescBasicPage',
component: () => import('/@/views/demo/page/desc/basic/index.vue'),
meta: {
title: '基础详情页',
title: 'routes.demo.page.descBasic',
},
},
{
......@@ -73,7 +73,7 @@ const page: AppRouteModule = {
name: 'DescHighPage',
component: () => import('/@/views/demo/page/desc/high/index.vue'),
meta: {
title: '高级详情页',
title: 'routes.demo.page.descHigh',
},
},
],
......@@ -86,7 +86,7 @@ const page: AppRouteModule = {
name: 'ResultPage',
redirect: '/page-demo/result/success',
meta: {
title: '结果页',
title: 'routes.demo.page.result',
},
children: [
{
......@@ -94,7 +94,7 @@ const page: AppRouteModule = {
name: 'ResultSuccessPage',
component: () => import('/@/views/demo/page/result/success/index.vue'),
meta: {
title: '成功页',
title: 'routes.demo.page.resultSuccess',
},
},
{
......@@ -102,7 +102,7 @@ const page: AppRouteModule = {
name: 'ResultFailPage',
component: () => import('/@/views/demo/page/result/fail/index.vue'),
meta: {
title: '失败页',
title: 'routes.demo.page.resultFail',
},
},
],
......@@ -115,7 +115,7 @@ const page: AppRouteModule = {
name: 'AccountPage',
redirect: '/page-demo/account/setting',
meta: {
title: '个人页',
title: 'routes.demo.page.account',
},
children: [
{
......@@ -123,7 +123,7 @@ const page: AppRouteModule = {
name: 'AccountCenterPage',
component: () => import('/@/views/demo/page/account/center/index.vue'),
meta: {
title: '个人中心',
title: 'routes.demo.page.accountCenter',
},
},
{
......@@ -131,7 +131,7 @@ const page: AppRouteModule = {
name: 'AccountSettingPage',
component: () => import('/@/views/demo/page/account/setting/index.vue'),
meta: {
title: '个人设置',
title: 'routes.demo.page.accountSetting',
},
},
],
......@@ -143,7 +143,7 @@ const page: AppRouteModule = {
name: 'ExceptionPage',
redirect: '/page-demo/exception/404',
meta: {
title: '异常页',
title: 'routes.demo.page.exception',
},
children: [
{
......@@ -190,7 +190,7 @@ const page: AppRouteModule = {
status: ExceptionEnum.NET_WORK_ERROR,
},
meta: {
title: '网络错误',
title: 'routes.demo.page.netWorkError',
afterCloseLoading: true,
},
},
......@@ -202,7 +202,7 @@ const page: AppRouteModule = {
status: ExceptionEnum.PAGE_NOT_DATA,
},
meta: {
title: '无数据',
title: 'routes.demo.page.notData',
afterCloseLoading: true,
},
},
......@@ -215,7 +215,7 @@ const page: AppRouteModule = {
name: 'ListPage',
redirect: '/page-demo/list/card',
meta: {
title: '列表页',
title: 'routes.demo.page.list',
},
children: [
{
......@@ -223,7 +223,7 @@ const page: AppRouteModule = {
name: 'ListCardPage',
component: () => import('/@/views/demo/page/list/card/index.vue'),
meta: {
title: '卡片列表',
title: 'routes.demo.page.listCard',
},
},
],
......
......@@ -11,7 +11,7 @@ const permission: AppRouteModule = {
redirect: '/permission/front/page',
meta: {
icon: 'carbon:user-role',
title: '权限管理',
title: 'routes.demo.permission.permission',
},
},
......@@ -20,7 +20,7 @@ const permission: AppRouteModule = {
path: '/front',
name: 'PermissionFrontDemo',
meta: {
title: '基于前端权限',
title: 'routes.demo.permission.front',
},
children: [
{
......@@ -28,7 +28,7 @@ const permission: AppRouteModule = {
name: 'FrontPageAuth',
component: () => import('/@/views/demo/permission/front/index.vue'),
meta: {
title: '页面权限',
title: 'routes.demo.permission.frontPage',
},
},
{
......@@ -36,7 +36,7 @@ const permission: AppRouteModule = {
name: 'FrontBtnAuth',
component: () => import('/@/views/demo/permission/front/Btn.vue'),
meta: {
title: '按钮权限',
title: 'routes.demo.permission.frontBtn',
},
},
{
......@@ -44,7 +44,7 @@ const permission: AppRouteModule = {
name: 'FrontAuthPageA',
component: () => import('/@/views/demo/permission/front/AuthPageA.vue'),
meta: {
title: '权限测试页A',
title: 'routes.demo.permission.frontTestA',
roles: [RoleEnum.SUPER],
},
},
......@@ -53,7 +53,7 @@ const permission: AppRouteModule = {
name: 'FrontAuthPageB',
component: () => import('/@/views/demo/permission/front/AuthPageB.vue'),
meta: {
title: '权限测试页B',
title: 'routes.demo.permission.frontTestB',
roles: [RoleEnum.TEST],
},
},
......@@ -63,7 +63,7 @@ const permission: AppRouteModule = {
path: '/back',
name: 'PermissionBackDemo',
meta: {
title: '基于后台权限',
title: 'routes.demo.permission.back',
},
children: [
{
......@@ -71,7 +71,7 @@ const permission: AppRouteModule = {
name: 'BackAuthPage',
component: () => import('/@/views/demo/permission/back/index.vue'),
meta: {
title: '页面权限',
title: 'routes.demo.permission.backPage',
},
},
{
......@@ -79,7 +79,7 @@ const permission: AppRouteModule = {
name: 'BackAuthBtn',
component: () => import('/@/views/demo/permission/back/Btn.vue'),
meta: {
title: '按钮权限',
title: 'routes.demo.permission.backBtn',
},
},
],
......
......@@ -10,7 +10,7 @@ const table: AppRouteModule = {
redirect: '/table/basic',
meta: {
icon: 'ant-design:table-outlined',
title: 'Table',
title: 'routes.demo.table.table',
},
},
......@@ -20,7 +20,7 @@ const table: AppRouteModule = {
name: 'TableBasicDemo',
component: () => import('/@/views/demo/table/Basic.vue'),
meta: {
title: '基础表格',
title: 'routes.demo.table.basic',
},
},
{
......@@ -28,7 +28,7 @@ const table: AppRouteModule = {
name: 'TreeTableDemo',
component: () => import('/@/views/demo/table/TreeTable.vue'),
meta: {
title: '树形表格',
title: 'routes.demo.table.treeTable',
},
},
{
......@@ -36,7 +36,7 @@ const table: AppRouteModule = {
name: 'FetchTableDemo',
component: () => import('/@/views/demo/table/FetchTable.vue'),
meta: {
title: '远程加载示例',
title: 'routes.demo.table.fetchTable',
},
},
{
......@@ -44,7 +44,7 @@ const table: AppRouteModule = {
name: 'FixedColumnDemo',
component: () => import('/@/views/demo/table/FixedColumn.vue'),
meta: {
title: '固定列',
title: 'routes.demo.table.fixedColumn',
},
},
{
......@@ -52,7 +52,7 @@ const table: AppRouteModule = {
name: 'CustomerCellDemo',
component: () => import('/@/views/demo/table/CustomerCell.vue'),
meta: {
title: '自定义列',
title: 'routes.demo.table.customerCell',
},
},
{
......@@ -60,7 +60,7 @@ const table: AppRouteModule = {
name: 'FormTableDemo',
component: () => import('/@/views/demo/table/FormTable.vue'),
meta: {
title: '开启搜索区域',
title: 'routes.demo.table.formTable',
},
},
{
......@@ -68,7 +68,7 @@ const table: AppRouteModule = {
name: 'UseTableDemo',
component: () => import('/@/views/demo/table/UseTable.vue'),
meta: {
title: 'UseTable',
title: 'routes.demo.table.useTable',
},
},
{
......@@ -76,7 +76,7 @@ const table: AppRouteModule = {
name: 'RefTableDemo',
component: () => import('/@/views/demo/table/RefTable.vue'),
meta: {
title: 'RefTable',
title: 'routes.demo.table.refTable',
},
},
{
......@@ -84,7 +84,7 @@ const table: AppRouteModule = {
name: 'MultipleHeaderDemo',
component: () => import('/@/views/demo/table/MultipleHeader.vue'),
meta: {
title: '多级表头',
title: 'routes.demo.table.multipleHeader',
},
},
{
......@@ -92,7 +92,7 @@ const table: AppRouteModule = {
name: 'MergeHeaderDemo',
component: () => import('/@/views/demo/table/MergeHeader.vue'),
meta: {
title: '合并单元格',
title: 'routes.demo.table.mergeHeader',
},
},
{
......@@ -100,7 +100,7 @@ const table: AppRouteModule = {
name: 'ExpandTableDemo',
component: () => import('/@/views/demo/table/ExpandTable.vue'),
meta: {
title: '可展开表格',
title: 'routes.demo.table.expandTable',
},
},
{
......@@ -108,7 +108,7 @@ const table: AppRouteModule = {
name: 'FixedHeightDemo',
component: () => import('/@/views/demo/table/FixedHeight.vue'),
meta: {
title: '定高/头部自定义',
title: 'routes.demo.table.fixedHeight',
},
},
{
......@@ -116,7 +116,7 @@ const table: AppRouteModule = {
name: 'FooterTableDemo',
component: () => import('/@/views/demo/table/FooterTable.vue'),
meta: {
title: '表尾行合计',
title: 'routes.demo.table.footerTable',
},
},
{
......@@ -124,7 +124,7 @@ const table: AppRouteModule = {
name: 'EditCellTableDemo',
component: () => import('/@/views/demo/table/EditCellTable.vue'),
meta: {
title: '可编辑单元格',
title: 'routes.demo.table.editCellTable',
},
},
{
......@@ -132,7 +132,7 @@ const table: AppRouteModule = {
name: 'EditRowTableDemo',
component: () => import('/@/views/demo/table/EditRowTable.vue'),
meta: {
title: '可编辑行',
title: 'routes.demo.table.editRowTable',
},
},
],
......
......@@ -10,7 +10,7 @@ const tree: AppRouteModule = {
redirect: '/tree/basic',
meta: {
icon: 'clarity:tree-view-line',
title: 'Tree',
title: 'routes.demo.tree.tree',
},
},
routes: [
......@@ -19,7 +19,7 @@ const tree: AppRouteModule = {
name: 'BasicTreeDemo',
component: () => import('/@/views/demo/tree/index.vue'),
meta: {
title: '基础树',
title: 'routes.demo.tree.basic',
},
},
{
......@@ -27,7 +27,7 @@ const tree: AppRouteModule = {
name: 'EditTreeDemo',
component: () => import('/@/views/demo/tree/EditTree.vue'),
meta: {
title: '右键示例',
title: 'routes.demo.tree.editTree',
},
},
{
......@@ -35,7 +35,7 @@ const tree: AppRouteModule = {
name: 'ActionTreeDemo',
component: () => import('/@/views/demo/tree/ActionTree.vue'),
meta: {
title: '函数操作示例',
title: 'routes.demo.tree.actionTree',
},
},
],
......
......@@ -20,7 +20,7 @@ import {
} from '/@/setup/theme';
import { appStore } from '/@/store/modules/app';
import { deepMerge } from '../utils/index';
import { deepMerge } from '/@/utils';
// Used to share global app instances
let app: App;
......
import { App, unref } from 'vue';
import { App } from 'vue';
import type { I18n, I18nOptions } from 'vue-i18n';
import { createI18n } from 'vue-i18n';
import localeMessages from '/@/locales';
import { useLocale } from '/@/hooks/web/useLocale';
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
import projectSetting from '/@/settings/projectSetting';
const { setupLocale } = useLocale();
const { getLang, getAvailableLocales, getFallbackLocale } = useLocaleSetting();
const { lang, availableLocales, fallback } = projectSetting?.locale;
const localeData: I18nOptions = {
legacy: false,
locale: unref(getLang),
fallbackLocale: unref(getFallbackLocale),
locale: lang,
fallbackLocale: fallback,
messages: localeMessages,
availableLocales: unref(getAvailableLocales),
availableLocales: availableLocales,
sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
silentTranslationWarn: false, // true - warning off
silentFallbackWarn: true,
......
......@@ -20,6 +20,9 @@ import { transformRouteToMenu } from '/@/utils/helper/menuHelper';
import { useMessage } from '/@/hooks/web/useMessage';
// import { warn } from '/@/utils/log';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('sys.app');
const { createMessage } = useMessage();
const NAME = 'permission';
......@@ -101,7 +104,7 @@ class Permission extends VuexModule {
} else if (permissionMode === PermissionModeEnum.BACK) {
const messageKey = 'loadMenu';
createMessage.loading({
content: '菜单加载中...',
content: t('menuLoading'),
key: messageKey,
duration: 1,
});
......
......@@ -21,6 +21,7 @@ import { loginApi, getUserInfoById } from '/@/api/sys/user';
import { setLocal, getLocal, getSession, setSession } from '/@/utils/helper/persistent';
import { useProjectSetting } from '/@/hooks/setting';
import { useI18n } from '/@/hooks/web/useI18n';
export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>;
......@@ -29,6 +30,8 @@ hotModuleUnregisterModule(NAME);
const { permissionCacheType } = useProjectSetting();
const { t } = useI18n('sys.app');
function getCache<T>(key: string) {
const fn = permissionCacheType === CacheTypeEnum.LOCAL ? getLocal : getSession;
return fn(key) as T;
......@@ -144,8 +147,8 @@ class User extends VuexModule {
const { createConfirm } = useMessage();
createConfirm({
iconType: 'warning',
title: '温馨提醒',
content: '是否确认退出系统?',
title: t('loginOutTip'),
content: t('loginOutMessage'),
onOk: async () => {
await this.loginOut(true);
},
......
import { useMessage } from '/@/hooks/web/useMessage';
import { userStore } from '/@/store/modules/user';
import { useI18n } from '/@/hooks/web/useI18n';
const { createMessage } = useMessage();
const { t } = useI18n('sys.api');
const error = createMessage.error!;
export function checkStatus(status: number, msg: string): void {
switch (status) {
......@@ -12,39 +15,39 @@ export function checkStatus(status: number, msg: string): void {
// 未登录则跳转登录页面,并携带当前页面的路径
// 在登录成功后返回当前页面,这一步需要在登录页操作。
case 401:
error('用户没有权限(令牌、用户名、密码错误)!');
error(t('errMsg401'));
userStore.loginOut(true);
break;
case 403:
error('用户得到授权,但是访问是被禁止的。!');
error(t('errMsg403'));
break;
// 404请求不存在
case 404:
error('网络请求错误,未找到该资源!');
error(t('errMsg404'));
break;
case 405:
error('网络请求错误,请求方法未允许!');
error(t('errMsg405'));
break;
case 408:
error('网络请求超时!');
error(t('errMsg408'));
break;
case 500:
error('服务器错误,请联系管理员!');
error(t('errMsg500'));
break;
case 501:
error('网络未实现!');
error(t('errMsg501'));
break;
case 502:
error('网络错误!');
error(t('errMsg502'));
break;
case 503:
error('服务不可用,服务器暂时过载或维护!');
error(t('errMsg503'));
break;
case 504:
error('网络超时!');
error(t('errMsg504'));
break;
case 505:
error('http版本不支持该请求!');
error(t('errMsg505'));
break;
default:
}
......
......@@ -20,7 +20,9 @@ import { formatRequestDate } from '/@/utils/dateUtil';
import { setObjToUrlParams, deepMerge } from '/@/utils';
import { errorStore } from '/@/store/modules/error';
import { errorResult } from './const';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('sys.api');
const globSetting = useGlobSetting();
const prefix = globSetting.urlPrefix;
const { createMessage, createErrorModal } = useMessage();
......@@ -55,7 +57,7 @@ const transform: AxiosTransform = {
if (message) {
// errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
if (options.errorMessageMode === 'modal') {
createErrorModal({ title: '错误提示', content: message });
createErrorModal({ title: t('errorTip'), content: message });
} else {
createMessage.error(message);
}
......@@ -74,7 +76,7 @@ const transform: AxiosTransform = {
createMessage.error(data.message);
Promise.reject(new Error(message));
} else {
const msg = '操作失败,系统异常!';
const msg = t('errorMessage');
createMessage.error(msg);
Promise.reject(new Error(msg));
}
......@@ -82,9 +84,9 @@ const transform: AxiosTransform = {
}
// 登录超时
if (code === ResultEnum.TIMEOUT) {
const timeoutMsg = '登录超时,请重新登录!';
const timeoutMsg = t('timeoutMessage');
createErrorModal({
title: '操作失败',
title: t('operationFailed'),
content: timeoutMsg,
});
Promise.reject(new Error(timeoutMsg));
......@@ -159,12 +161,12 @@ const transform: AxiosTransform = {
const err: string = error.toString();
try {
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
createMessage.error('接口请求超时,请刷新页面重试!');
createMessage.error(t('apiTimeoutMessage'));
}
if (err && err.includes('Network Error')) {
createErrorModal({
title: '网络异常',
content: '请检查您的网络连接是否正常!',
title: t('networkException'),
content: t('networkExceptionMsg'),
});
}
} catch (error) {
......
......@@ -3,8 +3,8 @@
<div class="login-mask" />
<div class="login-form-wrap">
<div class="login-form mx-6">
<AppLocalePicker v-if="showLocale" class="login-form__locale" />
<div class="login-form__content px-2 py-10">
<AppLocalePicker v-if="showLocale" class="login-form__locale" />
<header>
<img :src="logo" class="mr-4" />
<h1>{{ title }}</h1>
......@@ -158,9 +158,16 @@
},
});
</script>
<style lang="less" scoped>
<style lang="less">
@import (reference) '../../../design/index.less';
.login-form__locale {
position: absolute;
top: 14px;
right: 14px;
z-index: 1;
}
.login {
position: relative;
height: 100vh;
......@@ -178,7 +185,9 @@
}
&-form {
width: 520px;
position: relative;
bottom: 60px;
width: 400px;
background: @white;
border: 10px solid rgba(255, 255, 255, 0.5);
border-width: 8px;
......@@ -192,26 +201,20 @@
right: 0;
display: flex;
width: 100%;
height: 90%;
height: 100%;
// height: 90%;
justify-content: center;
align-items: center;
.respond-to(large, {
width: 600px;
right: calc(50% - 270px);
.respond-to(xlarge, {
justify-content: flex-end;
});
.respond-to(xlarge, { width: 540px; right:0});
}
&__locale {
position: absolute;
top: 10px;
right: 10px;
}
&__content {
position: relative;
width: 100%;
height: 100%;
padding: 60px 0 40px 0;
border: 1px solid #999;
border-radius: 2px;
......@@ -228,7 +231,6 @@
h1 {
margin-bottom: 0;
font-size: 24px;
// color: @primary-color;
text-align: center;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册