feat(projects): ceshitijiao

This commit is contained in:
shaoyou 2025-07-16 15:46:12 +08:00
parent e89b86ce56
commit e55a822add
18 changed files with 302 additions and 257 deletions

44
.env
View File

@ -1,60 +1,60 @@
# the base url of the application, the default is "/"
# if use a sub directory, it must be end with "/", like "/admin/" but not "/admin"
# 应用的基础路径,默认为 "/"
# 如果使用子目录,必须以 "/" 结尾,如 "/admin/" 而不是 "/admin"
VITE_BASE_URL=/
VITE_APP_TITLE=SoybeanAdmin
VITE_APP_DESC=SoybeanAdmin is a fresh and elegant admin template
VITE_APP_DESC=SoybeanAdmin 是一个清新优雅的管理后台模板
# the prefix of the icon name
# 图标名称的前缀
VITE_ICON_PREFIX=icon
# the prefix of the local svg icon component, must include VITE_ICON_PREFIX
# format {VITE_ICON_PREFIX}-{local icon name}
# 本地 svg 图标组件的前缀,必须包含 VITE_ICON_PREFIX
# 格式为 {VITE_ICON_PREFIX}-{本地图标名}
VITE_ICON_LOCAL_PREFIX=icon-local
# auth route mode: static dynamic
# 权限路由模式:static dynamic
VITE_AUTH_ROUTE_MODE=static
# static auth route home
# static 权限路由的首页
VITE_ROUTE_HOME=home
# default menu icon
# 默认菜单图标
VITE_MENU_ICON=mdi:menu
# whether to enable http proxy when is dev mode
# 是否在开发模式下启用 http 代理
VITE_HTTP_PROXY=Y
# vue-router mode: hash | history | memory
# vue-router 模式:hash | history | memory
VITE_ROUTER_HISTORY_MODE=history
# success code of backend service, when the code is received, the request is successful
# 后端服务的成功状态码,收到该状态码时请求成功
VITE_SERVICE_SUCCESS_CODE=0000
# logout codes of backend service, when the code is received, the user will be logged out and redirected to login page
# 后端服务登出状态码,收到该状态码时用户会被登出并跳转到登录页
VITE_SERVICE_LOGOUT_CODES=8888,8889
# modal logout codes of backend service, when the code is received, the user will be logged out by displaying a modal
# 后端服务弹窗登出状态码,收到该状态码时会弹窗提示并登出
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778
# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
# 后端服务 token 过期状态码,收到该状态码时会刷新 token 并重新发送请求
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998,3333
# when the route mode is static, the defined super role
# 路由模式为 static 时定义的超级角色
VITE_STATIC_SUPER_ROLE=R_SUPER
# sourcemap
# 是否生成 sourcemap
VITE_SOURCE_MAP=N
# Used to differentiate storage across different domains
# 用于区分不同域名下的存储
VITE_STORAGE_PREFIX=SOY_
# used to control whether the program automatically detects updates
# 控制程序打包后是否自动检测更新
VITE_AUTOMATICALLY_DETECT_UPDATE=Y
# show proxy url log in terminal
# 是否在终端显示代理地址日志
VITE_PROXY_LOG=Y
# used to control whether to launch editor
# by the way, this plugin is only available in dev mode, not in build mode
# 控制是否启动编辑器
# 此插件仅在开发模式下可用,构建模式下不可用
VITE_DEVTOOLS_LAUNCH_EDITOR=code

View File

@ -1,7 +1,7 @@
# backend service base url, prod environment
# # 后端服务基础地址,生产环境
VITE_SERVICE_BASE_URL=https://mock.apifox.cn/m1/3109515-0-default
# other backend service base url, prod environment
# 其他后端服务基础地址,生产环境
VITE_OTHER_SERVICE_BASE_URL= `{
"demo": "http://localhost:9529"
}`

View File

@ -1,7 +1,7 @@
# backend service base url, test environment
# 后端服务基础地址,测试环境
VITE_SERVICE_BASE_URL=https://mock.apifox.cn/m1/3109515-0-default
# other backend service base url, test environment
# 其他后端服务基础地址,测试环境
VITE_OTHER_SERVICE_BASE_URL= `{
"demo": "http://localhost:9528"
}`

View File

@ -4,10 +4,10 @@ import { consola } from 'consola';
import { createServiceConfig } from '../../src/utils/service';
/**
* Set http proxy
* http
*
* @param env - The current env
* @param enable - If enable http proxy
* @param env -
* @param enable - http
*/
export function createViteProxy(env: Env.ImportMeta, enable: boolean) {
const isEnableHttpProxy = enable && env.VITE_HTTP_PROXY === 'Y';
@ -27,6 +27,12 @@ export function createViteProxy(env: Env.ImportMeta, enable: boolean) {
return proxy;
}
/**
*
*
* @param item
* @param enableLog
*/
function createProxyItem(item: App.Service.ServiceConfigItem, enableLog: boolean) {
const proxy: Record<string, ProxyOptions> = {};

View File

@ -12,22 +12,22 @@ type CommandAction<A extends object> = (args?: A) => Promise<void> | void;
type CommandWithAction<A extends object = object> = Record<Command, { desc: string; action: CommandAction<A> }>;
interface CommandArg {
/** Execute additional command after bumping and before git commit. Defaults to 'pnpm sa changelog' */
/** bump 版本并 git commit 之前执行的额外命令,默认为 'pnpm sa changelog' */
execute?: string;
/** Indicates whether to push the git commit and tag. Defaults to true */
/** 是否推送 git commit 和 tag默认为 true */
push?: boolean;
/** Generate changelog by total tags */
/** 是否根据所有 tag 生成 changelog */
total?: boolean;
/**
* The glob pattern of dirs to clean up
* glob
*
* If not set, it will use the default value
* 使
*
* Multiple values use "," to separate them
* ","
*/
cleanupDir?: string;
/**
* display lang of cli
* CLI
*
* @default 'en-us'
*/
@ -41,58 +41,52 @@ export async function setupCli() {
cli
.version(lightGreen(version))
.option(
'-e, --execute [command]',
"Execute additional command after bumping and before git commit. Defaults to 'npx soy changelog'"
)
.option('-p, --push', 'Indicates whether to push the git commit and tag')
.option('-t, --total', 'Generate changelog by total tags')
.option(
'-c, --cleanupDir <dir>',
'The glob pattern of dirs to cleanup, If not set, it will use the default value, Multiple values use "," to separate them'
)
.option('-l, --lang <lang>', 'display lang of cli', { default: 'en-us', type: [String] })
.option('-e, --execute [command]', "bump 版本并 git commit 之前执行的额外命令,默认为 'npx soy changelog'")
.option('-p, --push', '是否推送 git commit 和 tag')
.option('-t, --total', '是否根据所有 tag 生成 changelog')
.option('-c, --cleanupDir <dir>', '需要清理的目录的 glob 模式,未设置则使用默认值,多个值用 "," 分隔')
.option('-l, --lang <lang>', 'CLI 显示语言', { default: 'en-us', type: [String] })
.help();
const commands: CommandWithAction<CommandArg> = {
cleanup: {
desc: 'delete dirs: node_modules, dist, etc.',
desc: '删除 node_modules、dist 等目录',
action: async () => {
await cleanup(cliOptions.cleanupDirs);
}
},
'update-pkg': {
desc: 'update package.json dependencies versions',
desc: '更新 package.json 依赖版本',
action: async () => {
await updatePkg(cliOptions.ncuCommandArgs);
}
},
'git-commit': {
desc: 'git commit, generate commit message which match Conventional Commits standard',
desc: 'git commit,生成符合 Conventional Commits 规范的提交信息',
action: async args => {
await gitCommit(args?.lang);
}
},
'git-commit-verify': {
desc: 'verify git commit message, make sure it match Conventional Commits standard',
desc: '校验 git commit 信息,确保符合 Conventional Commits 规范',
action: async args => {
await gitCommitVerify(args?.lang, cliOptions.gitCommitVerifyIgnores);
}
},
changelog: {
desc: 'generate changelog',
desc: '生成 changelog',
action: async args => {
await genChangelog(cliOptions.changelogOptions, args?.total);
}
},
release: {
desc: 'release: update version, generate changelog, commit code',
desc: '发布:更新版本、生成 changelog、提交代码',
action: async args => {
await release(args?.execute, args?.push);
}
},
'gen-route': {
desc: 'generate route',
desc: '生成路由',
action: async () => {
await generateRoute();
}

View File

@ -166,7 +166,8 @@ const local: App.I18n.Schema = {
404: 'Page Not Found',
500: 'Server Error',
'iframe-page': 'Iframe',
home: 'Home'
home: 'Home',
cesium: 'Cesium'
},
page: {
login: {

View File

@ -166,7 +166,8 @@ const local: App.I18n.Schema = {
404: '页面不存在',
500: '服务器错误',
'iframe-page': '外链页面',
home: '首页'
home: '首页',
cesium: '三维地球'
},
page: {
login: {

View File

@ -20,5 +20,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
500: () => import("@/views/_builtin/500/index.vue"),
"iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
login: () => import("@/views/_builtin/login/index.vue"),
cesium: () => import("@/views/cesium/index.vue"),
home: () => import("@/views/home/index.vue"),
};

View File

@ -39,6 +39,16 @@ export const generatedRoutes: GeneratedRoute[] = [
hideInMenu: true
}
},
{
name: 'cesium',
path: '/cesium',
component: 'layout.base$view.cesium',
meta: {
title: 'cesium',
i18nKey: 'route.cesium',
order: 1
}
},
{
name: 'home',
path: '/home',
@ -47,7 +57,7 @@ export const generatedRoutes: GeneratedRoute[] = [
title: 'home',
i18nKey: 'route.home',
icon: 'mdi:monitor-dashboard',
order: 1
order: 0
}
},
{

View File

@ -166,6 +166,7 @@ const routeMap: RouteMap = {
"403": "/403",
"404": "/404",
"500": "/500",
"cesium": "/cesium",
"home": "/home",
"iframe-page": "/iframe-page/:url",
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"

View File

@ -12,9 +12,9 @@ import { localStg } from '@/utils/storage';
import { getRouteName } from '@/router/elegant/transform';
/**
* create route guard
*
*
* @param router router instance
* @param router
*/
export function createRouteGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
@ -38,39 +38,39 @@ export function createRouteGuard(router: Router) {
const hasRole = authStore.userInfo.roles.some(role => routeRoles.includes(role));
const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
// if it is login route when logged in, then switch to the root page
// 已登录时访问登录页,跳转到首页
if (to.name === loginRoute && isLogin) {
next({ name: rootRoute });
return;
}
// if the route does not need login, then it is allowed to access directly
// 路由不需要登录,直接放行
if (!needLogin) {
handleRouteSwitch(to, from, next);
return;
}
// the route need login but the user is not logged in, then switch to the login page
// 路由需要登录但用户未登录,跳转到登录页
if (!isLogin) {
next({ name: loginRoute, query: { redirect: to.fullPath } });
return;
}
// if the user is logged in but does not have authorization, then switch to the 403 page
// 已登录但无权限,跳转到 403 页面
if (!hasAuth) {
next({ name: noAuthorizationRoute });
return;
}
// switch route normally
// 正常切换路由
handleRouteSwitch(to, from, next);
});
}
/**
* initialize route
*
*
* @param to to route
* @param to
*/
async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> {
const routeStore = useRouteStore();
@ -78,12 +78,12 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
const notFoundRoute: RouteKey = 'not-found';
const isNotFoundRoute = to.name === notFoundRoute;
// if the constant route is not initialized, then initialize the constant route
// 如果常量路由未初始化,则初始化常量路由
if (!routeStore.isInitConstantRoute) {
await routeStore.initConstantRoute();
// the route is captured by the "not-found" route because the constant route is not initialized
// after the constant route is initialized, redirect to the original route
// 因为常量路由未初始化,被 not-found 路由捕获
// 常量路由初始化后,重定向到原始路由
const path = to.fullPath;
const location: RouteLocationRaw = {
path,
@ -98,14 +98,14 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
const isLogin = Boolean(localStg.get('token'));
if (!isLogin) {
// if the user is not logged in and the route is a constant route but not the "not-found" route, then it is allowed to access.
// 未登录且为常量路由但不是 not-found 路由,允许访问
if (to.meta.constant && !isNotFoundRoute) {
routeStore.onRouteSwitchWhenNotLoggedIn();
return null;
}
// if the user is not logged in, then switch to the login page
// 未登录,跳转到登录页
const loginRoute: RouteKey = 'login';
const query = getRouteQueryOfLoginRoute(to, routeStore.routeHome);
@ -118,11 +118,11 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
}
if (!routeStore.isInitAuthRoute) {
// initialize the auth route
// 初始化权限路由
await routeStore.initAuthRoute();
// the route is captured by the "not-found" route because the auth route is not initialized
// after the auth route is initialized, redirect to the original route
// 因为权限路由未初始化,被 not-found 路由捕获
// 权限路由初始化后,重定向到原始路由
if (isNotFoundRoute) {
const rootRoute: RouteKey = 'root';
const path = to.redirectedFrom?.name === rootRoute ? '/' : to.fullPath;
@ -140,13 +140,12 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
routeStore.onRouteSwitchWhenLoggedIn();
// the auth route is initialized
// it is not the "not-found" route, then it is allowed to access
// 权限路由已初始化,且不是 not-found 路由,允许访问
if (!isNotFoundRoute) {
return null;
}
// it is captured by the "not-found" route, then check whether the route exists
// 被 not-found 路由捕获,判断路由是否存在
const exist = await routeStore.getIsAuthRouteExist(to.path as RoutePath);
const noPermissionRoute: RouteKey = '403';
@ -161,8 +160,11 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
return null;
}
/**
*
*/
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
// route with href
// 带 href 的路由
if (to.meta.href) {
window.open(to.meta.href, '_blank');
@ -174,6 +176,9 @@ function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNorma
next();
}
/**
* query
*/
function getRouteQueryOfLoginRoute(to: RouteLocationNormalized, routeHome: RouteKey) {
const loginRoute: RouteKey = 'login';
const redirect = to.fullPath;

View File

@ -1,19 +1,19 @@
import { request } from '../request';
/** get constant routes */
/** 获取常量路由 */
export function fetchGetConstantRoutes() {
return request<Api.Route.MenuRoute[]>({ url: '/route/getConstantRoutes' });
}
/** get user routes */
/** 获取用户路由 */
export function fetchGetUserRoutes() {
return request<Api.Route.UserRoute>({ url: '/route/getUserRoutes' });
}
/**
* whether the route is exist
*
*
* @param routeName route name
* @param routeName
*/
export function fetchIsRouteExist(routeName: string) {
return request<boolean>({ url: '/route/isRouteExist', params: { routeName } });

49
src/typings/api.d.ts vendored
View File

@ -1,64 +1,67 @@
/**
* Namespace Api
* Api
*
* All backend api type
* API
*/
declare namespace Api {
namespace Common {
/** common params of paginating */
/** 分页通用参数 */
interface PaginatingCommonParams {
/** current page number */
/** 当前页码 */
current: number;
/** page size */
/** 每页数量 */
size: number;
/** total count */
/** 总条数 */
total: number;
}
/** common params of paginating query list data */
/** 分页查询列表数据的通用参数 */
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
/** 数据列表 */
records: T[];
}
/** common search params of table */
/** 表格通用搜索参数 */
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'current' | 'size'>;
/**
* enable status
*
*
* - "1": enabled
* - "2": disabled
* - "1":
* - "2":
*/
type EnableStatus = '1' | '2';
/** common record */
/** 通用记录 */
type CommonRecord<T = any> = {
/** record id */
/** 记录ID */
id: number;
/** record creator */
/** 创建人 */
createBy: string;
/** record create time */
/** 创建时间 */
createTime: string;
/** record updater */
/** 更新人 */
updateBy: string;
/** record update time */
/** 更新时间 */
updateTime: string;
/** record status */
/** 状态 */
status: EnableStatus | null;
} & T;
}
/**
* namespace Auth
* Auth
*
* backend api module: "auth"
* API "auth"
*/
namespace Auth {
/** 登录令牌 */
interface LoginToken {
token: string;
refreshToken: string;
}
/** 用户信息 */
interface UserInfo {
userId: string;
userName: string;
@ -68,17 +71,19 @@ declare namespace Api {
}
/**
* namespace Route
* Route
*
* backend api module: "route"
* API "route"
*/
namespace Route {
type ElegantConstRoute = import('@elegant-router/types').ElegantConstRoute;
/** 菜单路由 */
interface MenuRoute extends ElegantConstRoute {
id: string;
}
/** 用户路由 */
interface UserRoute {
routes: MenuRoute[];
home: import('@elegant-router/types').LastLevelRouteKey;

204
src/typings/app.d.ts vendored
View File

@ -1,121 +1,121 @@
/** The global namespace for the app */
/** 应用全局命名空间 */
declare namespace App {
/** Theme namespace */
/** 主题命名空间 */
namespace Theme {
type ColorPaletteNumber = import('@sa/color').ColorPaletteNumber;
/** Theme setting */
/** 主题设置 */
interface ThemeSetting {
/** Theme scheme */
/** 主题方案 */
themeScheme: UnionKey.ThemeScheme;
/** grayscale mode */
/** 灰度模式 */
grayscale: boolean;
/** colour weakness mode */
/** 色弱模式 */
colourWeakness: boolean;
/** Whether to recommend color */
/** 是否推荐配色 */
recommendColor: boolean;
/** Theme color */
/** 主题色 */
themeColor: string;
/** Other color */
/** 其他颜色 */
otherColor: OtherColor;
/** Whether info color is followed by the primary color */
/** info颜色是否跟随主色 */
isInfoFollowPrimary: boolean;
/** Reset cache strategy */
/** 重置缓存策略 */
resetCacheStrategy: UnionKey.ResetCacheStrategy;
/** Layout */
/** 布局 */
layout: {
/** Layout mode */
/** 布局模式 */
mode: UnionKey.ThemeLayoutMode;
/** Scroll mode */
/** 滚动模式 */
scrollMode: UnionKey.ThemeScrollMode;
/**
* Whether to reverse the horizontal mix
*
*
* if true, the vertical child level menus in left and horizontal first level menus in top
* true
*/
reverseHorizontalMix: boolean;
};
/** Page */
/** 页面 */
page: {
/** Whether to show the page transition */
/** 是否显示页面切换动画 */
animate: boolean;
/** Page animate mode */
/** 页面动画模式 */
animateMode: UnionKey.ThemePageAnimateMode;
};
/** Header */
/** 顶栏 */
header: {
/** Header height */
/** 顶栏高度 */
height: number;
/** Header breadcrumb */
/** 顶栏面包屑 */
breadcrumb: {
/** Whether to show the breadcrumb */
/** 是否显示面包屑 */
visible: boolean;
/** Whether to show the breadcrumb icon */
/** 是否显示面包屑图标 */
showIcon: boolean;
};
/** Multilingual */
/** 多语言 */
multilingual: {
/** Whether to show the multilingual */
/** 是否显示多语言 */
visible: boolean;
};
globalSearch: {
/** Whether to show the GlobalSearch */
/** 是否显示全局搜索 */
visible: boolean;
};
};
/** Tab */
/** 标签栏 */
tab: {
/** Whether to show the tab */
/** 是否显示标签栏 */
visible: boolean;
/**
* Whether to cache the tab
*
*
* If cache, the tabs will get from the local storage when the page is refreshed
*
*/
cache: boolean;
/** Tab height */
/** 标签栏高度 */
height: number;
/** Tab mode */
/** 标签栏模式 */
mode: UnionKey.ThemeTabMode;
};
/** Fixed header and tab */
/** 固定头部和标签栏 */
fixedHeaderAndTab: boolean;
/** Sider */
/** 侧边栏 */
sider: {
/** Inverted sider */
/** 侧边栏反色 */
inverted: boolean;
/** Sider width */
/** 侧边栏宽度 */
width: number;
/** Collapsed sider width */
/** 侧边栏收起宽度 */
collapsedWidth: number;
/** Sider width when the layout is 'vertical-mix' or 'horizontal-mix' */
/** 混合布局下侧边栏宽度 */
mixWidth: number;
/** Collapsed sider width when the layout is 'vertical-mix' or 'horizontal-mix' */
/** 混合布局下收起宽度 */
mixCollapsedWidth: number;
/** Child menu width when the layout is 'vertical-mix' or 'horizontal-mix' */
/** 混合布局下子菜单宽度 */
mixChildMenuWidth: number;
};
/** Footer */
/** 页脚 */
footer: {
/** Whether to show the footer */
/** 是否显示页脚 */
visible: boolean;
/** Whether fixed the footer */
/** 是否固定页脚 */
fixed: boolean;
/** Footer height */
/** 页脚高度 */
height: number;
/** Whether float the footer to the right when the layout is 'horizontal-mix' */
/** 混合布局下页脚是否右浮动 */
right: boolean;
};
/** Watermark */
/** 水印 */
watermark: {
/** Whether to show the watermark */
/** 是否显示水印 */
visible: boolean;
/** Watermark text */
/** 水印文本 */
text: string;
/** Whether to use user name as watermark text */
/** 是否使用用户名作为水印文本 */
enableUserName: boolean;
};
/** define some theme settings tokens, will transform to css variables */
/** 定义部分主题 token会转换为 css 变量 */
tokens: {
light: ThemeSettingToken;
dark?: {
@ -144,7 +144,7 @@ declare namespace App {
type BaseToken = Record<string, Record<string, string>>;
interface ThemeSettingTokenColor {
/** the progress bar color, if not set, will use the primary color */
/** 进度条颜色,未设置时使用主色 */
nprogress?: string;
container: string;
layout: string;
@ -165,14 +165,14 @@ declare namespace App {
type ThemeTokenColor = ThemePaletteColor & ThemeSettingTokenColor;
/** Theme token CSS variables */
/** 主题 token CSS 变量 */
type ThemeTokenCSSVars = {
colors: ThemeTokenColor & { [key: string]: string };
boxShadow: ThemeSettingTokenBoxShadow & { [key: string]: string };
};
}
/** Global namespace */
/** 全局命名空间 */
namespace Global {
type VNode = import('vue').VNode;
type RouteLocationNormalizedLoaded = import('vue-router').RouteLocationNormalizedLoaded;
@ -181,41 +181,41 @@ declare namespace App {
type RoutePath = import('@elegant-router/types').RoutePath;
type LastLevelRouteKey = import('@elegant-router/types').LastLevelRouteKey;
/** The router push options */
/** 路由跳转参数 */
type RouterPushOptions = {
query?: Record<string, string>;
params?: Record<string, string>;
};
/** The global header props */
/** 全局头部属性 */
interface HeaderProps {
/** Whether to show the logo */
/** 是否显示 logo */
showLogo?: boolean;
/** Whether to show the menu toggler */
/** 是否显示菜单切换按钮 */
showMenuToggler?: boolean;
/** Whether to show the menu */
/** 是否显示菜单 */
showMenu?: boolean;
}
/** The global menu */
/** 全局菜单 */
type Menu = {
/**
* The menu key
* key
*
* Equal to the route key
* key
*/
key: string;
/** The menu label */
/** 菜单名称 */
label: string;
/** The menu i18n key */
/** 菜单 i18n key */
i18nKey?: I18n.I18nKey | null;
/** The route key */
/** 路由 key */
routeKey: RouteKey;
/** The route path */
/** 路由 path */
routePath: RoutePath;
/** The menu icon */
/** 菜单图标 */
icon?: () => VNode;
/** The menu children */
/** 子菜单 */
children?: Menu[];
};
@ -223,63 +223,63 @@ declare namespace App {
options?: Breadcrumb[];
};
/** Tab route */
/** 标签页路由 */
type TabRoute = Pick<RouteLocationNormalizedLoaded, 'name' | 'path' | 'meta'> &
Partial<Pick<RouteLocationNormalizedLoaded, 'fullPath' | 'query' | 'matched'>>;
/** The global tab */
/** 全局标签页 */
type Tab = {
/** The tab id */
/** 标签页 id */
id: string;
/** The tab label */
/** 标签页名称 */
label: string;
/**
* The new tab label
*
*
* If set, the tab label will be replaced by this value
*
*/
newLabel?: string;
/**
* The old tab label
*
*
* when reset the tab label, the tab label will be replaced by this value
*
*/
oldLabel?: string;
/** The tab route key */
/** 标签页路由 key */
routeKey: LastLevelRouteKey;
/** The tab route path */
/** 标签页路由 path */
routePath: RouteMap[LastLevelRouteKey];
/** The tab route full path */
/** 标签页完整路径 */
fullPath: string;
/** The tab fixed index */
/** 固定标签页索引 */
fixedIndex?: number | null;
/**
* Tab icon
*
*
* Iconify icon
* Iconify
*/
icon?: string;
/**
* Tab local icon
*
*
* Local icon
*
*/
localIcon?: string;
/** I18n key */
i18nKey?: I18n.I18nKey | null;
};
/** Form rule */
/** 表单校验规则 */
type FormRule = import('naive-ui').FormItemRule;
/** The global dropdown key */
/** 全局下拉菜单 key */
type DropdownKey = 'closeCurrent' | 'closeOther' | 'closeLeft' | 'closeRight' | 'closeAll';
}
/**
* I18n namespace
* I18n
*
* Locales type
*
*/
namespace I18n {
type RouteKey = import('@elegant-router/types').RouteKey;
@ -549,15 +549,15 @@ declare namespace App {
}
}
/** Service namespace */
/** 服务命名空间 */
namespace Service {
/** Other baseURL key */
/** 其他 baseURL key */
type OtherBaseURLKey = 'demo';
interface ServiceConfigItem {
/** The backend service base url */
/** 后端服务基础地址 */
baseURL: string;
/** The proxy pattern of the backend service base url */
/** 后端服务基础地址的代理前缀 */
proxyPattern: string;
}
@ -565,9 +565,9 @@ declare namespace App {
key: OtherBaseURLKey;
}
/** The backend service config */
/** 后端服务配置 */
interface ServiceConfig extends ServiceConfigItem {
/** Other backend service config */
/** 其他后端服务配置 */
other: OtherServiceConfigItem[];
}
@ -575,23 +575,23 @@ declare namespace App {
other: Record<OtherBaseURLKey, string>;
}
/** The backend service response data */
/** 后端服务响应数据 */
type Response<T = unknown> = {
/** The backend service response code */
/** 响应码 */
code: string;
/** The backend service response message */
/** 响应信息 */
msg: string;
/** The backend service response data */
/** 响应数据 */
data: T;
};
/** The demo backend service response data */
/** demo 后端服务响应数据 */
type DemoResponse<T = unknown> = {
/** The backend service response code */
/** 响应码 */
status: string;
/** The backend service response message */
/** 响应信息 */
message: string;
/** The backend service response data */
/** 响应数据 */
result: T;
};
}

View File

@ -20,6 +20,7 @@ declare module "@elegant-router/types" {
"403": "/403";
"404": "/404";
"500": "/500";
"cesium": "/cesium";
"home": "/home";
"iframe-page": "/iframe-page/:url";
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
@ -57,6 +58,7 @@ declare module "@elegant-router/types" {
| "403"
| "404"
| "500"
| "cesium"
| "home"
| "iframe-page"
| "login"
@ -81,6 +83,7 @@ declare module "@elegant-router/types" {
| "500"
| "iframe-page"
| "login"
| "cesium"
| "home"
>;

View File

@ -1,114 +1,113 @@
/**
* Namespace Env
* Env
*
* It is used to declare the type of the import.meta object
* import.meta
*/
declare namespace Env {
/** The router history mode */
/** 路由历史模式 */
type RouterHistoryMode = 'hash' | 'history' | 'memory';
/** Interface for import.meta */
/** import.meta 的接口 */
// eslint-disable-next-line @typescript-eslint/no-shadow
interface ImportMeta extends ImportMetaEnv {
/** The base url of the application */
/** 应用的基础路径 */
readonly VITE_BASE_URL: string;
/** The title of the application */
/** 应用标题 */
readonly VITE_APP_TITLE: string;
/** The description of the application */
/** 应用描述 */
readonly VITE_APP_DESC: string;
/** The router history mode */
/** 路由历史模式 */
readonly VITE_ROUTER_HISTORY_MODE?: RouterHistoryMode;
/** The prefix of the iconify icon */
/** iconify 图标前缀 */
readonly VITE_ICON_PREFIX: 'icon';
/**
* The prefix of the local icon
*
*
* This prefix is start with the icon prefix
* icon
*/
readonly VITE_ICON_LOCAL_PREFIX: 'icon-local';
/** backend service base url */
/** 后端服务基础地址 */
readonly VITE_SERVICE_BASE_URL: string;
/**
* success code of backend service
*
*
* when the code is received, the request is successful
*
*/
readonly VITE_SERVICE_SUCCESS_CODE: string;
/**
* logout codes of backend service
*
*
* when the code is received, the user will be logged out and redirected to login page
*
*
* use "," to separate multiple codes
* ","
*/
readonly VITE_SERVICE_LOGOUT_CODES: string;
/**
* modal logout codes of backend service
*
*
* when the code is received, the user will be logged out by displaying a modal
*
*
* use "," to separate multiple codes
* ","
*/
readonly VITE_SERVICE_MODAL_LOGOUT_CODES: string;
/**
* token expired codes of backend service
* token
*
* when the code is received, it will refresh the token and resend the request
* token
*
* use "," to separate multiple codes
* ","
*/
readonly VITE_SERVICE_EXPIRED_TOKEN_CODES: string;
/** when the route mode is static, the defined super role */
/** 路由模式为 static 时定义的超级角色 */
readonly VITE_STATIC_SUPER_ROLE: string;
/**
* other backend service base url
*
*
* the value is a json
* json
*/
readonly VITE_OTHER_SERVICE_BASE_URL: string;
/**
* Whether to enable the http proxy
* http
*
* Only valid in the development environment
*
*/
readonly VITE_HTTP_PROXY?: CommonType.YesOrNo;
/**
* The auth route mode
*
*
* - Static: the auth routes is generated in front-end
* - Dynamic: the auth routes is generated in back-end
* - static
* - dynamic
*/
readonly VITE_AUTH_ROUTE_MODE: 'static' | 'dynamic';
/**
* The home route key
* key
*
* It only has effect when the auth route mode is static, if the route mode is dynamic, the home route key is
* defined in the back-end
* static dynamic
*/
readonly VITE_ROUTE_HOME: import('@elegant-router/types').LastLevelRouteKey;
/**
* Default menu icon if menu icon is not set
* 使
*
* Iconify icon name
* Iconify
*/
readonly VITE_MENU_ICON: string;
/** Whether to build with sourcemap */
/** 是否构建 sourcemap */
readonly VITE_SOURCE_MAP?: CommonType.YesOrNo;
/**
* Iconify api provider url
* Iconify API
*
* If the project is deployed in intranet, you can set the api provider url to the local iconify server
* iconify
*
* @link https://docs.iconify.design/api/providers.html
*/
readonly VITE_ICONIFY_URL?: string;
/** Used to differentiate storage across different domains */
/** 用于区分不同域名下的存储 */
readonly VITE_STORAGE_PREFIX?: string;
/** Whether to automatically detect updates after configuring application packaging */
/** 配置应用打包后是否自动检测更新 */
readonly VITE_AUTOMATICALLY_DETECT_UPDATE?: CommonType.YesOrNo;
/** show proxy url log in terminal */
/** 是否在终端显示代理地址日志 */
readonly VITE_PROXY_LOG?: CommonType.YesOrNo;
/** The launch editor */
/** 启动的编辑器 */
readonly VITE_DEVTOOLS_LAUNCH_EDITOR?: import('vite-plugin-vue-devtools').VitePluginVueDevToolsOptions['launchEditor'];
}
}

View File

@ -1,9 +1,9 @@
import json5 from 'json5';
/**
* Create service config by current env
*
*
* @param env The current env
* @param env
*/
export function createServiceConfig(env: Env.ImportMeta) {
const { VITE_SERVICE_BASE_URL, VITE_OTHER_SERVICE_BASE_URL } = env;
@ -13,7 +13,7 @@ export function createServiceConfig(env: Env.ImportMeta) {
other = json5.parse(VITE_OTHER_SERVICE_BASE_URL);
} catch {
// eslint-disable-next-line no-console
console.error('VITE_OTHER_SERVICE_BASE_URL is not a valid json5 string');
console.error('VITE_OTHER_SERVICE_BASE_URL 不是有效的 json5 字符串');
}
const httpConfig: App.Service.SimpleServiceConfig = {
@ -41,10 +41,10 @@ export function createServiceConfig(env: Env.ImportMeta) {
}
/**
* get backend service base url
*
*
* @param env - the current env
* @param isProxy - if use proxy
* @param env
* @param isProxy 使
*/
export function getServiceBaseURL(env: Env.ImportMeta, isProxy: boolean) {
const { baseURL, other } = createServiceConfig(env);
@ -62,9 +62,9 @@ export function getServiceBaseURL(env: Env.ImportMeta, isProxy: boolean) {
}
/**
* Get proxy pattern of backend service base url
*
*
* @param key If not set, will use the default key
* @param key 使 key
*/
function createProxyPattern(key?: App.Service.OtherBaseURLKey) {
if (!key) {

View File

@ -0,0 +1,19 @@
<script setup lang="ts"></script>
<template>
<div>
这是cesium页面
<div class="cesium-container">
<div id="cesiumContainer"></div>
</div>
<p>请在控制台查看Cesium相关信息</p>
</div>
</template>
<style scoped>
#cesiumContainer {
width: 100%;
height: 100vh;
background-color: red;
}
</style>