├── .eslintignore ├── babel.config.js ├── .prettierignore ├── commitlint.config.js ├── src ├── utils │ ├── env.ts │ ├── copyText.ts │ ├── auth.ts │ ├── setup-mock.ts │ ├── event.ts │ ├── monitor.ts │ ├── route-listener.ts │ ├── jsonp.ts │ └── is.ts ├── types │ ├── mock.ts │ ├── echarts.ts │ └── global.ts ├── assets │ ├── images │ │ ├── login-banner.png │ │ └── qrcode-icon.png │ ├── style │ │ ├── breakpoint.less │ │ └── global.less │ └── logo.svg ├── directive │ ├── index.ts │ └── permission │ │ └── index.ts ├── mock │ ├── index.ts │ └── message-box.ts ├── router │ ├── routes │ │ ├── externalModules │ │ │ ├── arco.ts │ │ │ └── faq.ts │ │ ├── types.ts │ │ ├── index.ts │ │ ├── base.ts │ │ └── modules │ │ │ ├── park.ts │ │ │ ├── parkingVip.ts │ │ │ ├── files.ts │ │ │ ├── chatRoute.ts │ │ │ ├── verification.ts │ │ │ └── dashboard.ts │ ├── app-menus │ │ └── index.ts │ ├── constants.ts │ ├── guard │ │ ├── index.ts │ │ ├── userLoginInfo.ts │ │ └── permission.ts │ ├── typings.d.ts │ └── index.ts ├── store │ ├── modules │ │ ├── tab-bar │ │ │ ├── types.ts │ │ │ └── index.ts │ │ ├── app │ │ │ └── types.ts │ │ └── user │ │ │ ├── types.ts │ │ │ └── index.ts │ └── index.ts ├── hooks │ ├── themes.ts │ ├── loading.ts │ ├── visible.ts │ ├── locale.ts │ ├── user.ts │ ├── request.ts │ ├── chart-option.ts │ ├── responsive.ts │ └── permission.ts ├── components │ ├── tab-bar │ │ └── readme.md │ ├── footer │ │ └── index.vue │ ├── message-box │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── breadcrumb │ │ └── index.vue │ ├── index.ts │ ├── global-setting │ │ ├── form-wrapper.vue │ │ └── block.vue │ ├── chart │ │ └── index.vue │ └── menu │ │ └── use-menu-tree.ts ├── config │ └── settings.json ├── views │ ├── redirect │ │ └── index.vue │ ├── login │ │ ├── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ │ ├── components │ │ │ └── banner.vue │ │ └── index.vue │ ├── visualization │ │ ├── parkingDataCount - 副本 │ │ │ ├── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ ├── popular-author.vue │ │ │ │ └── public-opinion.vue │ │ ├── chargingDataCount │ │ │ ├── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ └── public-opinion - 副本.vue │ │ ├── parkingDataCount │ │ │ ├── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ └── public-opinion - 副本.vue │ │ ├── villageDataCount │ │ │ ├── locale │ │ │ │ ├── zh-CN.ts │ │ │ │ └── en-US.ts │ │ │ ├── index.vue │ │ │ └── components │ │ │ │ └── public-opinion - 副本.vue │ │ └── multi-dimension-data-analysis │ │ │ ├── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ │ │ ├── components │ │ │ └── data-chain-growth.vue │ │ │ ├── mock.ts │ │ │ └── index.vue │ ├── not-found │ │ └── index.vue │ ├── dashboard │ │ └── workplace │ │ │ ├── components │ │ │ ├── banner.vue │ │ │ ├── carousel.vue │ │ │ ├── docs.vue │ │ │ ├── recently-visited.vue │ │ │ ├── quick-operation.vue │ │ │ └── announcement.vue │ │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── user │ │ ├── setting │ │ │ ├── components │ │ │ │ ├── certification.vue │ │ │ │ └── certification-records.vue │ │ │ └── index.vue │ │ └── locale │ │ │ └── en-US.ts │ ├── files │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── internet_of_things │ │ ├── carParkList │ │ │ └── components │ │ │ │ └── rules-preset.vue │ │ ├── chargingStation │ │ │ └── components │ │ │ │ └── rules-preset.vue │ │ ├── locale │ │ │ └── en-US.ts │ │ └── packageList │ │ │ └── packageBuyImport.vue │ ├── pay │ │ ├── serviceProvider │ │ │ └── components │ │ │ │ ├── career │ │ │ │ ├── index.vue │ │ │ │ └── Settlement.vue │ │ │ │ ├── society │ │ │ │ └── index.vue │ │ │ │ ├── enterprise │ │ │ │ └── index.vue │ │ │ │ ├── government │ │ │ │ ├── index.vue │ │ │ │ └── Settlement.vue │ │ │ │ └── individual │ │ │ │ └── index.vue │ │ └── locale │ │ │ ├── en-US.ts │ │ │ └── zh-CN.ts │ ├── park │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── parkingVip │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── chatView │ │ └── locale │ │ │ ├── zh-CN.ts │ │ │ └── en-US.ts │ ├── verification │ │ └── locale │ │ │ ├── en-US.ts │ │ │ └── zh-CN.ts │ └── wisdomCommunity │ │ └── locale │ │ └── en-US.ts ├── env.d.ts ├── locale │ ├── index.ts │ ├── zh-CN │ │ └── settings.ts │ ├── en-US │ │ └── settings.ts │ ├── en-US.ts │ └── zh-CN.ts ├── main.ts ├── layout │ └── page-layout.vue ├── App.vue └── api │ ├── dashboard.ts │ ├── message.ts │ ├── files.ts │ ├── verification.ts │ └── chatApi.ts ├── 微信图片_20231128142155.png ├── 微信截图_20231128142253.png ├── 微信截图_20231128142505.png ├── 微信截图_20231128142527.png ├── 微信截图_20240306213557.png ├── 微信截图_20240306213611.png ├── 微信截图_20240306213706.png ├── 微信截图_20240306213723.png ├── 微信截图_20240306213745.png ├── 微信截图_20240306213758.png ├── 微信截图_20240306213824.png ├── 微信截图_20240306213836.png ├── 微信截图_20240306213909.png ├── 微信截图_20240306213953.png ├── 微信截图_20240306214119.png ├── 微信截图_20240306214150.png ├── 微信截图_20240306214217.png ├── 微信截图_20240306214228.png ├── 微信截图_20240306214303.png ├── .gitignore ├── .env.development ├── .env.production ├── config ├── utils │ └── index.ts ├── plugin │ ├── visualizer.ts │ ├── arcoResolver.ts │ ├── imagemin.ts │ └── compress.ts ├── vite.config.dev.ts ├── vite.config.prod.ts └── vite.config.base.ts ├── vite.config.ts ├── .prettierrc.js ├── 配置文件说明.txt ├── tsconfig.json ├── index.html ├── .stylelintrc.js ├── .vscode └── settings.json ├── README.en.md ├── .eslintrc.js ├── README.md └── beizhu.txt /.eslintignore: -------------------------------------------------------------------------------- 1 | /*.json 2 | /*.js 3 | dist 4 | /*.vue -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['@vue/babel-plugin-jsx'], 3 | }; 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | .local 3 | .output.js 4 | /node_modules/** 5 | 6 | **/*.svg 7 | **/*.sh -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /src/utils/env.ts: -------------------------------------------------------------------------------- 1 | const debug = process.env.NODE_ENV !== 'production'; 2 | 3 | export default debug; 4 | -------------------------------------------------------------------------------- /微信图片_20231128142155.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信图片_20231128142155.png -------------------------------------------------------------------------------- /微信截图_20231128142253.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20231128142253.png -------------------------------------------------------------------------------- /微信截图_20231128142505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20231128142505.png -------------------------------------------------------------------------------- /微信截图_20231128142527.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20231128142527.png -------------------------------------------------------------------------------- /微信截图_20240306213557.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213557.png -------------------------------------------------------------------------------- /微信截图_20240306213611.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213611.png -------------------------------------------------------------------------------- /微信截图_20240306213706.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213706.png -------------------------------------------------------------------------------- /微信截图_20240306213723.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213723.png -------------------------------------------------------------------------------- /微信截图_20240306213745.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213745.png -------------------------------------------------------------------------------- /微信截图_20240306213758.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213758.png -------------------------------------------------------------------------------- /微信截图_20240306213824.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213824.png -------------------------------------------------------------------------------- /微信截图_20240306213836.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213836.png -------------------------------------------------------------------------------- /微信截图_20240306213909.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213909.png -------------------------------------------------------------------------------- /微信截图_20240306213953.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306213953.png -------------------------------------------------------------------------------- /微信截图_20240306214119.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306214119.png -------------------------------------------------------------------------------- /微信截图_20240306214150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306214150.png -------------------------------------------------------------------------------- /微信截图_20240306214217.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306214217.png -------------------------------------------------------------------------------- /微信截图_20240306214228.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306214228.png -------------------------------------------------------------------------------- /微信截图_20240306214303.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/微信截图_20240306214303.png -------------------------------------------------------------------------------- /src/types/mock.ts: -------------------------------------------------------------------------------- 1 | export interface MockParams { 2 | url: string; 3 | type: string; 4 | body: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/images/login-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/src/assets/images/login-banner.png -------------------------------------------------------------------------------- /src/assets/images/qrcode-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/archttp/cfzhv3.0_public_admin/HEAD/src/assets/images/qrcode-icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | node_modules 7 | .DS_Store 8 | dist 9 | dist-ssr 10 | *.local 11 | node_modules.* -------------------------------------------------------------------------------- /src/directive/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue'; 2 | import permission from './permission'; 3 | 4 | export default { 5 | install(Vue: App) { 6 | Vue.directive('permission', permission); 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | #接口服务地址 2 | VITE_API_BASE_URL= 'https://v3.cfeng.wang' 3 | #腾讯位置服务key 4 | VITE_TC_MAP_KEY= '腾讯位置服务key替换掉这' 5 | #登录域名id 6 | VITE_DOMAIN_ID= '0' 7 | #登录二维码底部文字 8 | VITE_LOGIN_QRCODE_TEXT= '智慧城市一张网,行业顶级专家' -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | #接口服务地址 2 | VITE_API_BASE_URL= 'https://v3.cfeng.wang' 3 | #腾讯位置服务key 4 | VITE_TC_MAP_KEY= '腾讯位置服务key替换掉这' 5 | #登录域名id 6 | VITE_DOMAIN_ID= '0' 7 | #登录二维码底部文字 8 | VITE_LOGIN_QRCODE_TEXT= '智慧城市一张网,行业顶级专家' -------------------------------------------------------------------------------- /src/mock/index.ts: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | 3 | import './user'; 4 | import './message-box'; 5 | 6 | import '@/views/dashboard/workplace/mock'; 7 | 8 | Mock.setup({ 9 | timeout: '600-1000', 10 | }); 11 | -------------------------------------------------------------------------------- /config/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Whether to generate package preview 3 | * 是否生成打包报告 4 | */ 5 | export default {}; 6 | 7 | export function isReportMode(): boolean { 8 | return process.env.REPORT === 'true'; 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | // vite.config.js 4 | import { viteCommonjs } from '@originjs/vite-plugin-commonjs' 5 | 6 | export default defineConfig({ 7 | plugins: [vue(),viteCommonjs()], 8 | }) -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 2, 3 | semi: true, 4 | printWidth: 80, 5 | singleQuote: true, 6 | quoteProps: 'consistent', 7 | htmlWhitespaceSensitivity: 'strict', 8 | vueIndentScriptAndStyle: true, 9 | endOfLine: "auto", 10 | }; 11 | -------------------------------------------------------------------------------- /src/router/routes/externalModules/arco.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | path: 'https://arco.design', 3 | name: 'arcoWebsite', 4 | meta: { 5 | locale: 'menu.arcoWebsite', 6 | icon: 'icon-link', 7 | requiresAuth: true, 8 | order: 8, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /配置文件说明.txt: -------------------------------------------------------------------------------- 1 | ①-------------------------- 2 | 请设置 根目录下 3 | .env.development 4 | .env.production 5 | 这两个文件里面的 相关配置值 6 | ②-------------------------- 7 | 修改 根目录下 index.html 文件里面的腾讯地图密钥 8 | ③-------------------------- 9 | 请将自己的二维码logo放到 \src\assets\images ,文件名称为 qrcode-icon.png,默认有一个,替换掉即可 -------------------------------------------------------------------------------- /src/router/routes/externalModules/faq.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | path: 'https://arco.design/vue/docs/pro/faq', 3 | name: 'faq', 4 | meta: { 5 | locale: 'menu.faq', 6 | icon: 'icon-question-circle', 7 | requiresAuth: true, 8 | order: 9, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/store/modules/tab-bar/types.ts: -------------------------------------------------------------------------------- 1 | export interface TagProps { 2 | title: string; 3 | name: string; 4 | fullPath: string; 5 | query?: any; 6 | ignoreCache?: boolean; 7 | } 8 | 9 | export interface TabBarState { 10 | tagList: TagProps[]; 11 | cacheTabList: Set; 12 | } 13 | -------------------------------------------------------------------------------- /src/hooks/themes.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { useAppStore } from '@/store'; 3 | 4 | export default function useThemes() { 5 | const appStore = useAppStore(); 6 | const isDark = computed(() => { 7 | return appStore.theme === 'dark'; 8 | }); 9 | return { 10 | isDark, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/types/echarts.ts: -------------------------------------------------------------------------------- 1 | import { CallbackDataParams } from 'echarts/types/dist/shared'; 2 | 3 | export interface ToolTipFormatterParams extends CallbackDataParams { 4 | axisDim: string; 5 | axisIndex: number; 6 | axisType: string; 7 | axisId: string; 8 | axisValue: string; 9 | axisValueLabel: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia'; 2 | import useAppStore from './modules/app'; 3 | import useUserStore from './modules/user'; 4 | import useTabBarStore from './modules/tab-bar'; 5 | 6 | const pinia = createPinia(); 7 | 8 | export { useAppStore, useUserStore, useTabBarStore }; 9 | export default pinia; 10 | -------------------------------------------------------------------------------- /src/components/tab-bar/readme.md: -------------------------------------------------------------------------------- 1 | ## 组件说明 2 | 3 | 该组件非官方最终设计规范,以单独组件存在。 4 | 5 | 同时仅仅提供最基本的功能,后续进行优化及更改。 6 | 7 | 8 | ## Component description 9 | 10 | The component unofficial final design specification exists as a separate component. 11 | 12 | At the same time, only the most basic functions are provided, and subsequent optimizations and changes will be made. -------------------------------------------------------------------------------- /src/config/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "theme": "light", 3 | "colorWeak": false, 4 | "navbar": true, 5 | "menu": true, 6 | "hideMenu": false, 7 | "menuCollapse": false, 8 | "footer": true, 9 | "themeColor": "#165DFF", 10 | "menuWidth": 220, 11 | "globalSettings": false, 12 | "device": "desktop", 13 | "tabBar": true, 14 | "menuFromServer": true, 15 | "serverMenu": [] 16 | } 17 | -------------------------------------------------------------------------------- /src/views/redirect/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/hooks/loading.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | export default function useLoading(initValue = false) { 4 | const loading = ref(initValue); 5 | const setLoading = (value: boolean) => { 6 | loading.value = value; 7 | }; 8 | const toggle = () => { 9 | loading.value = !loading.value; 10 | }; 11 | return { 12 | loading, 13 | setLoading, 14 | toggle, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/hooks/visible.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | export default function useVisible(initValue = false) { 4 | const visible = ref(initValue); 5 | const setVisible = (value: boolean) => { 6 | visible.value = value; 7 | }; 8 | const toggle = () => { 9 | visible.value = !visible.value; 10 | }; 11 | return { 12 | visible, 13 | setVisible, 14 | toggle, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/router/app-menus/index.ts: -------------------------------------------------------------------------------- 1 | import { appRoutes, appExternalRoutes } from '../routes'; 2 | 3 | const mixinRoutes = [...appRoutes, ...appExternalRoutes]; 4 | 5 | const appClientMenus = mixinRoutes.map((el) => { 6 | const { name, path, meta, redirect, children } = el; 7 | return { 8 | name, 9 | path, 10 | meta, 11 | redirect, 12 | children, 13 | }; 14 | }); 15 | 16 | export default appClientMenus; 17 | -------------------------------------------------------------------------------- /src/utils/copyText.ts: -------------------------------------------------------------------------------- 1 | import useClipboard from 'vue-clipboard3'; 2 | import { Message } from '@arco-design/web-vue'; 3 | const { toClipboard } = useClipboard(); 4 | 5 | export const copyText = async (val: any) => { 6 | try { 7 | await toClipboard(JSON.stringify(val)); 8 | Message.success(`复制成功!内容:${JSON.stringify(val)}`); 9 | } catch (e) { 10 | Message.success(`复制失败!原因:${JSON.stringify(e)}`); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/footer/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /src/assets/style/breakpoint.less: -------------------------------------------------------------------------------- 1 | // ==============breakpoint============ 2 | 3 | // Extra small screen / phone 4 | @screen-xs: 480px; 5 | 6 | // Small screen / tablet 7 | @screen-sm: 576px; 8 | 9 | // Medium screen / desktop 10 | @screen-md: 768px; 11 | 12 | // Large screen / wide desktop 13 | @screen-lg: 992px; 14 | 15 | // Extra large screen / full hd 16 | @screen-xl: 1200px; 17 | 18 | // Extra extra large screen / large desktop 19 | @screen-xxl: 1600px; 20 | -------------------------------------------------------------------------------- /src/utils/auth.ts: -------------------------------------------------------------------------------- 1 | const TOKEN_KEY = 'token'; 2 | 3 | const isLogin = () => { 4 | return !!localStorage.getItem(TOKEN_KEY); 5 | }; 6 | 7 | const getToken = () => { 8 | return localStorage.getItem(TOKEN_KEY); 9 | }; 10 | 11 | const setToken = (token: string) => { 12 | localStorage.setItem(TOKEN_KEY, token); 13 | }; 14 | 15 | const clearToken = () => { 16 | localStorage.removeItem(TOKEN_KEY); 17 | }; 18 | 19 | export { isLogin, getToken, setToken, clearToken }; 20 | -------------------------------------------------------------------------------- /src/router/constants.ts: -------------------------------------------------------------------------------- 1 | export const WHITE_LIST = [ 2 | { name: 'notFound', children: [] }, 3 | { name: 'login', children: [] }, 4 | ]; 5 | 6 | export const NOT_FOUND = { 7 | name: 'notFound', 8 | }; 9 | 10 | export const REDIRECT_ROUTE_NAME = 'Redirect'; 11 | 12 | export const DEFAULT_ROUTE_NAME = 'Workplace'; 13 | 14 | export const DEFAULT_ROUTE = { 15 | title: 'menu.dashboard.workplace', 16 | name: DEFAULT_ROUTE_NAME, 17 | fullPath: '/dashboard/workplace', 18 | }; 19 | -------------------------------------------------------------------------------- /config/plugin/visualizer.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generation packaging analysis 3 | * 生成打包分析 4 | */ 5 | import visualizer from 'rollup-plugin-visualizer'; 6 | import { isReportMode } from '../utils'; 7 | 8 | export default function configVisualizerPlugin() { 9 | if (isReportMode()) { 10 | return visualizer({ 11 | filename: './node_modules/.cache/visualizer/stats.html', 12 | open: true, 13 | gzipSize: true, 14 | brotliSize: true, 15 | }); 16 | } 17 | return []; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/message-box/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'messageBox.tab.title.message': '消息', 3 | 'messageBox.tab.title.notice': '通知', 4 | 'messageBox.tab.title.todo': '待办', 5 | 'messageBox.tab.button': '清空', 6 | 'messageBox.allRead': '全部已读', 7 | 'messageBox.viewMore': '查看更多', 8 | 'messageBox.noContent': '暂无内容', 9 | 'messageBox.switchRoles': '切换角色', 10 | 'messageBox.userCenter': '用户中心', 11 | 'messageBox.userSettings': '用户设置', 12 | 'messageBox.logout': '登出登录', 13 | }; 14 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import { DefineComponent } from 'vue'; 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any>; 7 | export default component; 8 | } 9 | interface ImportMetaEnv { 10 | readonly VITE_API_BASE_URL: string; 11 | readonly VITE_TC_MAP_KEY: string; 12 | readonly VITE_DOMAIN_ID: string; 13 | readonly VITE_LOGIN_QRCODE_TEXT: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/store/modules/app/types.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordNormalized } from 'vue-router'; 2 | 3 | export interface AppState { 4 | theme: string; 5 | colorWeak: boolean; 6 | navbar: boolean; 7 | menu: boolean; 8 | hideMenu: boolean; 9 | menuCollapse: boolean; 10 | footer: boolean; 11 | themeColor: string; 12 | menuWidth: number; 13 | globalSettings: boolean; 14 | device: string; 15 | tabBar: boolean; 16 | menuFromServer: boolean; 17 | serverMenu: RouteRecordNormalized[]; 18 | [key: string]: unknown; 19 | } 20 | -------------------------------------------------------------------------------- /src/store/modules/user/types.ts: -------------------------------------------------------------------------------- 1 | export type RoleType = '' | '*' | 'admin' | 'user'; 2 | export interface UserState { 3 | name?: string; 4 | avatar?: string; 5 | job?: string; 6 | organization?: string; 7 | location?: string; 8 | email?: string; 9 | introduction?: string; 10 | personalWebsite?: string; 11 | jobName?: string; 12 | organizationName?: string; 13 | locationName?: string; 14 | phone?: string; 15 | registrationDate?: string; 16 | accountId?: string; 17 | certification?: number; 18 | role: RoleType; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/message-box/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'messageBox.tab.title.message': 'Message', 3 | 'messageBox.tab.title.notice': 'Notice', 4 | 'messageBox.tab.title.todo': 'Todo', 5 | 'messageBox.tab.button': 'empty', 6 | 'messageBox.allRead': 'All Read', 7 | 'messageBox.viewMore': 'View More', 8 | 'messageBox.noContent': 'No Content', 9 | 'messageBox.switchRoles': 'Switch Roles', 10 | 'messageBox.userCenter': 'User Center', 11 | 'messageBox.userSettings': 'User Settings', 12 | 'messageBox.logout': 'Logout', 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/setup-mock.ts: -------------------------------------------------------------------------------- 1 | import debug from './env'; 2 | 3 | export default ({ mock, setup }: { mock?: boolean; setup: () => void }) => { 4 | if (mock !== false && debug) setup(); 5 | }; 6 | 7 | export const successResponseWrap = (data: unknown) => { 8 | return { 9 | data, 10 | status: 'ok', 11 | msg: '请求成功', 12 | code: 20000, 13 | }; 14 | }; 15 | 16 | export const failResponseWrap = (data: unknown, msg: string, code = 50000) => { 17 | return { 18 | data, 19 | status: 'fail', 20 | msg, 21 | code, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/locale/index.ts: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n'; 2 | import en from './en-US'; 3 | import cn from './zh-CN'; 4 | 5 | export const LOCALE_OPTIONS = [ 6 | { label: '中文', value: 'zh-CN' }, 7 | { label: 'English', value: 'en-US' }, 8 | ]; 9 | const defaultLocale = localStorage.getItem('arco-locale') || 'zh-CN'; 10 | 11 | const i18n = createI18n({ 12 | locale: defaultLocale, 13 | fallbackLocale: 'en-US', 14 | allowComposition: true, 15 | messages: { 16 | 'en-US': en, 17 | 'zh-CN': cn, 18 | }, 19 | }); 20 | 21 | export default i18n; 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ES2020", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "baseUrl": ".", 12 | "paths": { 13 | "@/*": ["src/*"] 14 | }, 15 | "lib": ["es2020", "dom"], 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src/**/*", "src/**/*.vue"], 19 | "exclude": ["node_modules"], 20 | "paths": { 21 | "@/*": ["src/*"] 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /src/hooks/locale.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { useI18n } from 'vue-i18n'; 3 | import { Message } from '@arco-design/web-vue'; 4 | 5 | export default function useLocale() { 6 | const i18 = useI18n(); 7 | const currentLocale = computed(() => { 8 | return i18.locale.value; 9 | }); 10 | const changeLocale = (value: string) => { 11 | i18.locale.value = value; 12 | localStorage.setItem('arco-locale', value); 13 | Message.success(i18.t('navbar.action.locale')); 14 | }; 15 | return { 16 | currentLocale, 17 | changeLocale, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/router/guard/index.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router'; 2 | import { setRouteEmitter } from '@/utils/route-listener'; 3 | import setupUserLoginInfoGuard from './userLoginInfo'; 4 | import setupPermissionGuard from './permission'; 5 | 6 | function setupPageGuard(router: Router) { 7 | router.beforeEach(async (to) => { 8 | // emit route change 9 | setRouteEmitter(to); 10 | }); 11 | } 12 | 13 | export default function createRouteGuard(router: Router) { 14 | setupPageGuard(router); 15 | setupUserLoginInfoGuard(router); 16 | setupPermissionGuard(router); 17 | } 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 智慧城市管理后台 - 全国一张网 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/router/routes/types.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent } from 'vue'; 2 | import type { RouteMeta, NavigationGuard } from 'vue-router'; 3 | 4 | export type Component = 5 | | ReturnType 6 | | (() => Promise) 7 | | (() => Promise); 8 | 9 | export interface AppRouteRecordRaw { 10 | path: string; 11 | name?: string | symbol; 12 | meta?: RouteMeta; 13 | redirect?: string; 14 | component: Component | string; 15 | children?: AppRouteRecordRaw[]; 16 | alias?: string | string[]; 17 | props?: Record; 18 | beforeEnter?: NavigationGuard | NavigationGuard[]; 19 | fullPath?: string; 20 | } 21 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'stylelint-config-standard', 4 | 'stylelint-config-rational-order', 5 | 'stylelint-config-prettier', 6 | ], 7 | defaultSeverity: 'warning', 8 | plugins: ['stylelint-order'], 9 | rules: { 10 | 'at-rule-no-unknown': [ 11 | true, 12 | { 13 | ignoreAtRules: ['plugin'], 14 | }, 15 | ], 16 | 'rule-empty-line-before': [ 17 | 'always', 18 | { 19 | except: ['after-single-line-comment', 'first-nested'], 20 | }, 21 | ], 22 | 'selector-pseudo-class-no-unknown': [ 23 | true, 24 | { 25 | ignorePseudoClasses: ['deep'], 26 | }, 27 | ], 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/utils/event.ts: -------------------------------------------------------------------------------- 1 | export function addEventListen( 2 | target: Window | HTMLElement, 3 | event: string, 4 | handler: EventListenerOrEventListenerObject, 5 | capture = false 6 | ) { 7 | if ( 8 | target.addEventListener && 9 | typeof target.addEventListener === 'function' 10 | ) { 11 | target.addEventListener(event, handler, capture); 12 | } 13 | } 14 | 15 | export function removeEventListen( 16 | target: Window | HTMLElement, 17 | event: string, 18 | handler: EventListenerOrEventListenerObject, 19 | capture = false 20 | ) { 21 | if ( 22 | target.removeEventListener && 23 | typeof target.removeEventListener === 'function' 24 | ) { 25 | target.removeEventListener(event, handler, capture); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/views/login/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'login.form.title': '金融级保护您的资产', 3 | 'login.form.userName.errMsg': '用户名不能为空', 4 | 'login.form.password.errMsg': '密码不能为空', 5 | 'login.form.login.errMsg': '登录出错,轻刷新重试', 6 | 'login.form.login.success': '欢迎使用', 7 | 'login.form.userName.placeholder': '用户名:admin', 8 | 'login.form.password.placeholder': '密码:admin', 9 | 'login.form.rememberPassword': '记住密码', 10 | 'login.form.forgetPassword': '忘记密码', 11 | 'login.form.login': '登录', 12 | 'login.form.register': '注册账号', 13 | 'login.banner.slogan1': '', 14 | 'login.banner.subSlogan1': '', 15 | 'login.banner.slogan2': '', 16 | 'login.banner.subSlogan2': '', 17 | 'login.banner.slogan3': '', 18 | 'login.banner.subSlogan3': '', 19 | }; 20 | -------------------------------------------------------------------------------- /src/hooks/user.ts: -------------------------------------------------------------------------------- 1 | import { useRouter } from 'vue-router'; 2 | import { Message } from '@arco-design/web-vue'; 3 | 4 | import { useUserStore } from '@/store'; 5 | 6 | export default function useUser() { 7 | const router = useRouter(); 8 | const userStore = useUserStore(); 9 | const logout = async (logoutTo?: string) => { 10 | await userStore.logout(); 11 | const currentRoute = router.currentRoute.value; 12 | Message.success('登出成功'); 13 | router.push({ 14 | name: logoutTo && typeof logoutTo === 'string' ? logoutTo : 'login', 15 | query: { 16 | ...router.currentRoute.value.query, 17 | redirect: currentRoute.name as string, 18 | }, 19 | }); 20 | }; 21 | return { 22 | logout, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/monitor.ts: -------------------------------------------------------------------------------- 1 | import { App, ComponentPublicInstance } from 'vue'; 2 | import axios from 'axios'; 3 | 4 | export default function handleError(Vue: App, baseUrl: string) { 5 | if (!baseUrl) { 6 | return; 7 | } 8 | Vue.config.errorHandler = ( 9 | err: unknown, 10 | instance: ComponentPublicInstance | null, 11 | info: string 12 | ) => { 13 | // send error info 14 | axios.post(`${baseUrl}/report-error`, { 15 | err, 16 | instance, 17 | info, 18 | // location: window.location.href, 19 | // message: err.message, 20 | // stack: err.stack, 21 | // browserInfo: getBrowserInfo(), 22 | // user info 23 | // dom info 24 | // url info 25 | // ... 26 | }); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import ArcoVue from '@arco-design/web-vue'; 3 | import ArcoVueIcon from '@arco-design/web-vue/es/icon'; 4 | import globalComponents from '@/components'; 5 | import router from './router'; 6 | import store from './store'; 7 | import i18n from './locale'; 8 | import directive from './directive'; 9 | // import './mock'; 10 | import App from './App.vue'; 11 | import '@arco-design/web-vue/dist/arco.css'; 12 | import '@/assets/style/global.less'; 13 | import '@/api/interceptor'; 14 | 15 | const app = createApp(App); 16 | 17 | app.use(ArcoVue, {}); 18 | app.use(ArcoVueIcon); 19 | 20 | app.use(router); 21 | app.use(store); 22 | app.use(i18n); 23 | app.use(globalComponents); 24 | app.use(directive); 25 | 26 | app.mount('#app'); 27 | -------------------------------------------------------------------------------- /src/types/global.ts: -------------------------------------------------------------------------------- 1 | export interface AnyObject { 2 | [key: string]: unknown; 3 | } 4 | 5 | export interface Options { 6 | value: unknown; 7 | label: string; 8 | } 9 | 10 | export interface NodeOptions extends Options { 11 | children?: NodeOptions[]; 12 | } 13 | 14 | export interface GetParams { 15 | body: null; 16 | type: string; 17 | url: string; 18 | } 19 | 20 | export interface PostData { 21 | body: string; 22 | type: string; 23 | url: string; 24 | } 25 | 26 | export interface Pagination { 27 | current: number; 28 | pageSize: number; 29 | total?: number; 30 | } 31 | 32 | export type TimeRanger = [string, string]; 33 | 34 | export interface GeneralChart { 35 | xAxis: string[]; 36 | data: Array<{ name: string; value: number[] }>; 37 | } 38 | -------------------------------------------------------------------------------- /src/layout/page-layout.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | -------------------------------------------------------------------------------- /src/api/dashboard.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import type { TableData } from '@arco-design/web-vue/es/table/interface'; 3 | 4 | export interface ContentDataRecord { 5 | x: string; 6 | y: number; 7 | } 8 | 9 | export function queryContentData() { 10 | return axios.get('/api/content-data'); 11 | } 12 | 13 | export interface PopularRecord { 14 | key: number; 15 | clickNumber: string; 16 | title: string; 17 | increases: number; 18 | } 19 | 20 | export function queryPopularList(params: { type: string }) { 21 | return axios.get('/api/popular/list', { params }); 22 | } 23 | 24 | 25 | export function getDailyIncomeStatisticsListByQuery(params: any) { 26 | return axios.get('/payAdmin/cfAccount/getDailyIncomeStatisticsListByQuery', { params }); 27 | } -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount - 副本/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': '分析页', 3 | 'dataAnalysis.title.publicOpinion': '舆情分析', 4 | 'dataAnalysis.card.title.allVisitors': '访问总人次', 5 | 'dataAnalysis.card.title.contentPublished': '内容发布量', 6 | 'dataAnalysis.card.title.totalComment': '评论总量', 7 | 'dataAnalysis.card.title.totalShare': '分享总量', 8 | 'dataAnalysis.card.yesterday': '较昨日', 9 | 'dataAnalysis.contentPublishRatio': '内容发布比例', 10 | 'dataAnalysis.popularAuthor': '热门作者榜单', 11 | 'dataAnalysis.popularAuthor.column.ranking': '排名', 12 | 'dataAnalysis.popularAuthor.column.author': '作者', 13 | 'dataAnalysis.popularAuthor.column.content': '内容量', 14 | 'dataAnalysis.popularAuthor.column.click': '点击量', 15 | 'dataAnalysis.contentPeriodAnalysis': '内容时段分析', 16 | }; 17 | -------------------------------------------------------------------------------- /config/plugin/arcoResolver.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * If you use the template method for development, you can use the unplugin-vue-components plugin to enable on-demand loading support. 3 | * 按需引入 4 | * https://github.com/antfu/unplugin-vue-components 5 | * https://arco.design/vue/docs/start 6 | * Although the Pro project is full of imported components, this plugin will be used by default. 7 | * 虽然Pro项目中是全量引入组件,但此插件会默认使用。 8 | */ 9 | import Components from 'unplugin-vue-components/vite'; 10 | import { ArcoResolver } from 'unplugin-vue-components/resolvers'; 11 | 12 | export default function configArcoResolverPlugin() { 13 | const arcoResolverPlugin = Components({ 14 | dirs: [], // Avoid parsing src/components. 避免解析到src/components 15 | deep: false, 16 | resolvers: [ArcoResolver()], 17 | }); 18 | return arcoResolverPlugin; 19 | } 20 | -------------------------------------------------------------------------------- /src/views/not-found/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 31 | -------------------------------------------------------------------------------- /config/vite.config.dev.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vite'; 2 | // import eslint from 'vite-plugin-eslint'; 3 | import baseConfig from './vite.config.base'; 4 | 5 | export default mergeConfig( 6 | { 7 | mode: 'development', 8 | server: { 9 | open: true, 10 | fs: { 11 | strict: true, 12 | }, 13 | port: '3000', 14 | // proxy: { 15 | // '/api': { 16 | // target: 'http://192.168.3.19', 17 | // changeOrigin: true, 18 | // rewrite: (path) => path.replace(/^\/api/, ''), // 不可以省略rewrite 19 | // }, 20 | // }, 21 | }, 22 | plugins: [ 23 | // eslint({ 24 | // cache: false, 25 | // include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'], 26 | // exclude: ['node_modules'], 27 | // }), 28 | ], 29 | }, 30 | baseConfig 31 | ); 32 | -------------------------------------------------------------------------------- /src/components/breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /src/router/routes/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordNormalized } from 'vue-router'; 2 | 3 | const modules = import.meta.glob('./modules/*.ts', { eager: true }); 4 | const externalModules = import.meta.glob('./externalModules/*.ts', { 5 | eager: true, 6 | }); 7 | 8 | function formatModules(_modules: any, result: RouteRecordNormalized[]) { 9 | Object.keys(_modules).forEach((key) => { 10 | const defaultModule = _modules[key].default; 11 | if (!defaultModule) return; 12 | const moduleList = Array.isArray(defaultModule) 13 | ? [...defaultModule] 14 | : [defaultModule]; 15 | result.push(...moduleList); 16 | }); 17 | return result; 18 | } 19 | 20 | export const appRoutes: RouteRecordNormalized[] = formatModules(modules, []); 21 | 22 | export const appExternalRoutes: RouteRecordNormalized[] = formatModules( 23 | externalModules, 24 | [] 25 | ); 26 | -------------------------------------------------------------------------------- /src/views/visualization/chargingDataCount/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': '分析页', 3 | 'dataAnalysis.title.publicOpinion': '基本信息', 4 | 'dataAnalysis.card.title.allVisitors': '访问总人次', 5 | 'dataAnalysis.card.title.contentPublished': '内容发布量', 6 | 'dataAnalysis.card.title.totalComment': '评论总量', 7 | 'dataAnalysis.card.title.totalShare': '分享总量', 8 | 'dataAnalysis.card.yesterday': '较昨日', 9 | 'dataAnalysis.contentPublishRatio': '内容发布比例', 10 | 'dataAnalysis.popularAuthor': '热门作者榜单', 11 | 'dataAnalysis.popularAuthor.column.ranking': '排名', 12 | 'dataAnalysis.popularAuthor.column.author': '作者', 13 | 'dataAnalysis.popularAuthor.column.content': '内容量', 14 | 'dataAnalysis.popularAuthor.column.click': '点击量', 15 | 'dataAnalysis.contentPeriodAnalysis': '停车总览(月数据)', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': '充电总览(月数据)', 17 | }; 18 | -------------------------------------------------------------------------------- /src/hooks/request.ts: -------------------------------------------------------------------------------- 1 | import { ref, UnwrapRef } from 'vue'; 2 | import { AxiosResponse } from 'axios'; 3 | import { HttpResponse } from '@/api/interceptor'; 4 | import useLoading from './loading'; 5 | 6 | // use to fetch list 7 | // Don't use async function. It doesn't work in async function. 8 | // Use the bind function to add parameters 9 | // example: useRequest(api.bind(null, {})) 10 | 11 | export default function useRequest( 12 | api: () => Promise>, 13 | defaultValue = [] as unknown as T, 14 | isLoading = true 15 | ) { 16 | const { loading, setLoading } = useLoading(isLoading); 17 | const response = ref(defaultValue); 18 | api() 19 | .then((res) => { 20 | response.value = res.data as unknown as UnwrapRef; 21 | }) 22 | .finally(() => { 23 | setLoading(false); 24 | }); 25 | return { loading, response }; 26 | } 27 | -------------------------------------------------------------------------------- /src/router/routes/base.ts: -------------------------------------------------------------------------------- 1 | import { REDIRECT_ROUTE_NAME } from '@/router/constants'; 2 | import { AppRouteRecordRaw } from './types'; 3 | 4 | export const DEFAULT_LAYOUT = () => import('@/layout/default-layout.vue'); 5 | 6 | export const REDIRECT_MAIN: AppRouteRecordRaw = { 7 | path: '/redirect', 8 | name: 'redirectWrapper', 9 | component: DEFAULT_LAYOUT, 10 | meta: { 11 | requiresAuth: true, 12 | hideInMenu: true, 13 | }, 14 | children: [ 15 | { 16 | path: '/redirect/:path', 17 | name: REDIRECT_ROUTE_NAME, 18 | component: () => import('@/views/redirect/index.vue'), 19 | meta: { 20 | requiresAuth: true, 21 | hideInMenu: true, 22 | }, 23 | }, 24 | ], 25 | }; 26 | 27 | export const NOT_FOUND_ROUTE = { 28 | path: '/:pathMatch(.*)*', 29 | name: 'notFound', 30 | component: () => import('@/views/not-found/index.vue'), 31 | }; 32 | -------------------------------------------------------------------------------- /src/views/login/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'login.form.title': 'Financial-level protection of your assets', 3 | 'login.form.userName.errMsg': 'Username cannot be empty', 4 | 'login.form.password.errMsg': 'Password cannot be empty', 5 | 'login.form.login.errMsg': 'Login error, refresh and try again', 6 | 'login.form.login.success': 'welcome to use', 7 | 'login.form.userName.placeholder': 'Username: admin', 8 | 'login.form.password.placeholder': 'Password: admin', 9 | 'login.form.rememberPassword': 'Remember password', 10 | 'login.form.forgetPassword': 'Forgot password', 11 | 'login.form.login': 'login', 12 | 'login.form.register': 'register account', 13 | 'login.banner.slogan1': '', 14 | 'login.banner.subSlogan1': '', 15 | 'login.banner.slogan2': '', 16 | 'login.banner.subSlogan2': '', 17 | 'login.banner.slogan3': '', 18 | 'login.banner.subSlogan3': '', 19 | }; 20 | -------------------------------------------------------------------------------- /config/plugin/imagemin.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Image resource files used to compress the output of the production environment 3 | * 图片压缩 4 | * https://github.com/anncwb/vite-plugin-imagemin 5 | */ 6 | import viteImagemin from 'vite-plugin-imagemin'; 7 | 8 | export default function configImageminPlugin() { 9 | const imageminPlugin = viteImagemin({ 10 | gifsicle: { 11 | optimizationLevel: 7, 12 | interlaced: false, 13 | }, 14 | optipng: { 15 | optimizationLevel: 7, 16 | }, 17 | mozjpeg: { 18 | quality: 20, 19 | }, 20 | pngquant: { 21 | quality: [0.8, 0.9], 22 | speed: 4, 23 | }, 24 | svgo: { 25 | plugins: [ 26 | { 27 | name: 'removeViewBox', 28 | }, 29 | { 30 | name: 'removeEmptyAttrs', 31 | active: false, 32 | }, 33 | ], 34 | }, 35 | }); 36 | return imageminPlugin; 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/route-listener.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Listening to routes alone would waste rendering performance. Use the publish-subscribe model for distribution management 3 | * 单独监听路由会浪费渲染性能。使用发布订阅模式去进行分发管理。 4 | */ 5 | import mitt, { Handler } from 'mitt'; 6 | import type { RouteLocationNormalized } from 'vue-router'; 7 | 8 | const emitter = mitt(); 9 | 10 | const key = Symbol('ROUTE_CHANGE'); 11 | 12 | let latestRoute: RouteLocationNormalized; 13 | 14 | export function setRouteEmitter(to: RouteLocationNormalized) { 15 | emitter.emit(key, to); 16 | latestRoute = to; 17 | } 18 | 19 | export function listenerRouteChange( 20 | handler: (route: RouteLocationNormalized) => void, 21 | immediate = true 22 | ) { 23 | emitter.on(key, handler as Handler); 24 | if (immediate && latestRoute) { 25 | handler(latestRoute); 26 | } 27 | } 28 | 29 | export function removeRouteListener() { 30 | emitter.off(key); 31 | } 32 | -------------------------------------------------------------------------------- /src/api/message.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export interface MessageRecord { 4 | id: number; 5 | type: string; 6 | title: string; 7 | subTitle: string; 8 | avatar?: string; 9 | content: string; 10 | time: string; 11 | status: 0 | 1; 12 | messageType?: number; 13 | } 14 | export type MessageListType = MessageRecord[]; 15 | 16 | export function queryMessageList() { 17 | return axios.post('/api/message/list'); 18 | } 19 | 20 | interface MessageStatus { 21 | ids: number[]; 22 | } 23 | 24 | export function setMessageStatus(data: MessageStatus) { 25 | return axios.post('/api/message/read', data); 26 | } 27 | 28 | export interface ChatRecord { 29 | id: number; 30 | username: string; 31 | content: string; 32 | time: string; 33 | isCollect: boolean; 34 | } 35 | 36 | export function queryChatList() { 37 | return axios.post('/api/chat/list'); 38 | } 39 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/banner.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | 24 | 36 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': '分析页', 3 | 'dataAnalysis.title.publicOpinion': '基本信息', 4 | 'dataAnalysis.card.title.allVisitors': '访问总人次', 5 | 'dataAnalysis.card.title.contentPublished': '内容发布量', 6 | 'dataAnalysis.card.title.totalComment': '评论总量', 7 | 'dataAnalysis.card.title.totalShare': '分享总量', 8 | 'dataAnalysis.card.yesterday': '较昨日', 9 | 'dataAnalysis.contentPublishRatio': '内容发布比例', 10 | 'dataAnalysis.popularAuthor': '热门作者榜单', 11 | 'dataAnalysis.popularAuthor.column.ranking': '排名', 12 | 'dataAnalysis.popularAuthor.column.author': '作者', 13 | 'dataAnalysis.popularAuthor.column.content': '内容量', 14 | 'dataAnalysis.popularAuthor.column.click': '点击量', 15 | 'dataAnalysis.contentPeriodAnalysis': '停车总览(月数据)', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': '充电总览(月数据)', 17 | 'dataAnalysis.contentVillagePeriodAnalysis': '社区总览(月数据)', 18 | }; 19 | -------------------------------------------------------------------------------- /src/views/visualization/villageDataCount/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': '分析页', 3 | 'dataAnalysis.title.publicOpinion': '基本信息', 4 | 'dataAnalysis.card.title.allVisitors': '访问总人次', 5 | 'dataAnalysis.card.title.contentPublished': '内容发布量', 6 | 'dataAnalysis.card.title.totalComment': '评论总量', 7 | 'dataAnalysis.card.title.totalShare': '分享总量', 8 | 'dataAnalysis.card.yesterday': '较昨日', 9 | 'dataAnalysis.contentPublishRatio': '内容发布比例', 10 | 'dataAnalysis.popularAuthor': '热门作者榜单', 11 | 'dataAnalysis.popularAuthor.column.ranking': '排名', 12 | 'dataAnalysis.popularAuthor.column.author': '作者', 13 | 'dataAnalysis.popularAuthor.column.content': '内容量', 14 | 'dataAnalysis.popularAuthor.column.click': '点击量', 15 | 'dataAnalysis.contentPeriodAnalysis': '停车总览(月数据)', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': '充电总览(月数据)', 17 | 'dataAnalysis.contentVillagePeriodAnalysis': '社区总览(月数据)', 18 | }; 19 | -------------------------------------------------------------------------------- /config/plugin/compress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated 3 | * gzip压缩 4 | * https://github.com/anncwb/vite-plugin-compression 5 | */ 6 | import type { Plugin } from 'vite'; 7 | import compressPlugin from 'vite-plugin-compression'; 8 | 9 | export default function configCompressPlugin( 10 | compress: 'gzip' | 'brotli', 11 | deleteOriginFile = false 12 | ): Plugin | Plugin[] { 13 | const plugins: Plugin[] = []; 14 | 15 | if (compress === 'gzip') { 16 | plugins.push( 17 | compressPlugin({ 18 | ext: '.gz', 19 | deleteOriginFile, 20 | }) 21 | ); 22 | } 23 | 24 | if (compress === 'brotli') { 25 | plugins.push( 26 | compressPlugin({ 27 | ext: '.br', 28 | algorithm: 'brotliCompress', 29 | deleteOriginFile, 30 | }) 31 | ); 32 | } 33 | return plugins; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue'; 2 | import { use } from 'echarts/core'; 3 | import { CanvasRenderer } from 'echarts/renderers'; 4 | import { BarChart, LineChart, PieChart, RadarChart } from 'echarts/charts'; 5 | import { 6 | GridComponent, 7 | TooltipComponent, 8 | LegendComponent, 9 | DataZoomComponent, 10 | GraphicComponent, 11 | } from 'echarts/components'; 12 | import Chart from './chart/index.vue'; 13 | import Breadcrumb from './breadcrumb/index.vue'; 14 | 15 | // Manually introduce ECharts modules to reduce packing size 16 | 17 | use([ 18 | CanvasRenderer, 19 | BarChart, 20 | LineChart, 21 | PieChart, 22 | RadarChart, 23 | GridComponent, 24 | TooltipComponent, 25 | LegendComponent, 26 | DataZoomComponent, 27 | GraphicComponent, 28 | ]); 29 | 30 | export default { 31 | install(Vue: App) { 32 | Vue.component('Chart', Chart); 33 | Vue.component('Breadcrumb', Breadcrumb); 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount - 副本/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': 'Analysis', 3 | 'dataAnalysis.title.publicOpinion': 'Public Opinion Analysis', 4 | 'dataAnalysis.card.title.allVisitors': 'All Visitors', 5 | 'dataAnalysis.card.title.contentPublished': 'Content Published', 6 | 'dataAnalysis.card.title.totalComment': 'Total Comment', 7 | 'dataAnalysis.card.title.totalShare': 'Total Share', 8 | 'dataAnalysis.card.yesterday': 'Yesterday', 9 | 'dataAnalysis.contentPublishRatio': 'Content Publishing Ratio', 10 | 'dataAnalysis.popularAuthor': 'Popular Author', 11 | 'dataAnalysis.popularAuthor.column.ranking': 'ranking', 12 | 'dataAnalysis.popularAuthor.column.author': 'author', 13 | 'dataAnalysis.popularAuthor.column.content': 'Content Number', 14 | 'dataAnalysis.popularAuthor.column.click': 'Click Number', 15 | 'dataAnalysis.contentPeriodAnalysis': 'Content Period Analysis', 16 | }; 17 | -------------------------------------------------------------------------------- /src/directive/permission/index.ts: -------------------------------------------------------------------------------- 1 | import { DirectiveBinding } from 'vue'; 2 | import { useUserStore } from '@/store'; 3 | 4 | function checkPermission(el: HTMLElement, binding: DirectiveBinding) { 5 | const { value } = binding; 6 | const userStore = useUserStore(); 7 | const { role } = userStore; 8 | 9 | if (Array.isArray(value)) { 10 | if (value.length > 0) { 11 | const permissionValues = value; 12 | 13 | const hasPermission = permissionValues.includes(role); 14 | if (!hasPermission && el.parentNode) { 15 | el.parentNode.removeChild(el); 16 | } 17 | } 18 | } else { 19 | throw new Error(`need roles! Like v-permission="['admin','user']"`); 20 | } 21 | } 22 | 23 | export default { 24 | mounted(el: HTMLElement, binding: DirectiveBinding) { 25 | checkPermission(el, binding); 26 | }, 27 | updated(el: HTMLElement, binding: DirectiveBinding) { 28 | checkPermission(el, binding); 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/global-setting/form-wrapper.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "i18n-ally.localesPaths": [ 3 | "src/locale", 4 | "src/components/message-box/locale", 5 | "src/views/chatView/locale", 6 | "src/views/files/locale", 7 | "src/views/park/locale", 8 | "src/views/parkingVip/locale", 9 | "src/views/internet_of_things/locale", 10 | "src/views/login/locale", 11 | "src/views/pay/locale", 12 | "src/views/user/locale", 13 | "src/views/verification/locale", 14 | "src/views/wisdomCommunity/locale", 15 | "src/views/dashboard/workplace/locale", 16 | "src/views/user/setting/locale", 17 | "src/views/visualization/chargingDataCount/locale", 18 | "src/views/visualization/multi-dimension-data-analysis/locale", 19 | "src/views/visualization/parkingDataCount/locale", 20 | "src/views/visualization/parkingDataCount - 副本/locale", 21 | "src/views/visualization/villageDataCount/locale" 22 | ] 23 | } -------------------------------------------------------------------------------- /src/api/files.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | 4 | export function cfFileGet(params: any) { 5 | return axios.get( 6 | '/fileAdmin/cfFile/getListByQuery', 7 | params 8 | ); 9 | } 10 | export function cfFileDelete(params: any) { 11 | return axios.delete( 12 | '/fileAdmin/cfFile/delete', 13 | params 14 | ); 15 | } 16 | 17 | 18 | export function getFilePlatformListByQuery(params: any) { 19 | return axios.get( 20 | '/fileAdmin/cfFile/getFilePlatformListByQuery', 21 | params 22 | ); 23 | } 24 | 25 | export function addFilePlatform(data: any) { 26 | return axios.post('/fileAdmin/cfFile/addFilePlatform', data); 27 | } 28 | 29 | export function deleteFilePlatform(params: any) { 30 | return axios.delete( 31 | '/fileAdmin/cfFile/deleteFilePlatform', 32 | params 33 | ); 34 | } 35 | 36 | export function updateFilePlatform(data: any) { 37 | return axios.put( 38 | '/fileAdmin/cfFile/updateFilePlatform', 39 | data 40 | ); 41 | } -------------------------------------------------------------------------------- /src/router/typings.d.ts: -------------------------------------------------------------------------------- 1 | import 'vue-router'; 2 | 3 | declare module 'vue-router' { 4 | interface RouteMeta { 5 | roles?: string[]; // Controls roles that have access to the page 6 | requiresAuth: boolean; // Whether login is required to access the current page (every route must declare) 7 | icon?: string; // The icon show in the side menu 8 | locale?: string; // The locale name show in side menu and breadcrumb 9 | hideInMenu?: boolean; // If true, it is not displayed in the side menu 10 | hideChildrenInMenu?: boolean; // if set true, the children are not displayed in the side menu 11 | activeMenu?: string; // if set name, the menu will be highlighted according to the name you set 12 | order?: number; // Sort routing menu items. If set key, the higher the value, the more forward it is 13 | noAffix?: boolean; // if set true, the tag will not affix in the tab-bar 14 | ignoreCache?: boolean; // if set true, the page will not be cached 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/router/routes/modules/park.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/park', 6 | name: 'Park', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.park', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'carparkList', 17 | name: 'CarparkList', 18 | component: () => import('@/views/park/list/index.vue'), 19 | meta: { 20 | locale: 'menu.park.list', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'carparkLog', 27 | name: 'CarparkLog', 28 | component: () => import('@/views/park/parkingRecord/index.vue'), 29 | meta: { 30 | locale: 'menu.park.parkingRecord', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | }, 35 | ], 36 | }; 37 | 38 | export default DASHBOARD; 39 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': 'Analysis', 3 | 'dataAnalysis.title.publicOpinion': 'Public Opinion Analysis', 4 | 'dataAnalysis.card.title.allVisitors': 'All Visitors', 5 | 'dataAnalysis.card.title.contentPublished': 'Content Published', 6 | 'dataAnalysis.card.title.totalComment': 'Total Comment', 7 | 'dataAnalysis.card.title.totalShare': 'Total Share', 8 | 'dataAnalysis.card.yesterday': 'Yesterday', 9 | 'dataAnalysis.contentPublishRatio': 'Content Publishing Ratio', 10 | 'dataAnalysis.popularAuthor': 'Popular Author', 11 | 'dataAnalysis.popularAuthor.column.ranking': 'ranking', 12 | 'dataAnalysis.popularAuthor.column.author': 'author', 13 | 'dataAnalysis.popularAuthor.column.content': 'Content Number', 14 | 'dataAnalysis.popularAuthor.column.click': 'Click Number', 15 | 'dataAnalysis.contentPeriodAnalysis': 'Content Period Analysis', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': 'Content Period Analysis', 17 | }; 18 | -------------------------------------------------------------------------------- /src/views/visualization/chargingDataCount/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': 'Analysis', 3 | 'dataAnalysis.title.publicOpinion': 'Public Opinion Analysis', 4 | 'dataAnalysis.card.title.allVisitors': 'All Visitors', 5 | 'dataAnalysis.card.title.contentPublished': 'Content Published', 6 | 'dataAnalysis.card.title.totalComment': 'Total Comment', 7 | 'dataAnalysis.card.title.totalShare': 'Total Share', 8 | 'dataAnalysis.card.yesterday': 'Yesterday', 9 | 'dataAnalysis.contentPublishRatio': 'Content Publishing Ratio', 10 | 'dataAnalysis.popularAuthor': 'Popular Author', 11 | 'dataAnalysis.popularAuthor.column.ranking': 'ranking', 12 | 'dataAnalysis.popularAuthor.column.author': 'author', 13 | 'dataAnalysis.popularAuthor.column.content': 'Content Number', 14 | 'dataAnalysis.popularAuthor.column.click': 'Click Number', 15 | 'dataAnalysis.contentPeriodAnalysis': 'Content Period Analysis', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': 'Content Period Analysis', 17 | }; 18 | -------------------------------------------------------------------------------- /src/views/visualization/multi-dimension-data-analysis/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.multiDimensionDataAnalysis': '多维数据分析', 3 | 'menu.dashboard.parkingDataCount': '车场数据', 4 | 'menu.dashboard.chargingDataCount': '充电数据', 5 | 'menu.dashboard.villageDataCount': '社区数据', 6 | 'multiDAnalysis.card.title.dataOverview': '数据总览', 7 | 'multiDAnalysis.dataOverview.contentProduction': '停车次数', 8 | 'multiDAnalysis.dataOverview.contentClick': '充电度数', 9 | 'multiDAnalysis.dataOverview.contentExposure': '到访次数', 10 | 'multiDAnalysis.dataOverview.activeUsers': '物业缴费', 11 | 'multiDAnalysis.card.title.userActions': '异常放行排名', 12 | 'multiDAnalysis.card.title.contentTypeDistribution': '资产来源分析', 13 | 'multiDAnalysis.card.title.retentionTrends': '停车场数量', 14 | 'multiDAnalysis.card.title.userRetention': '充电站数量', 15 | 'multiDAnalysis.card.title.contentConsumptionTrends': '社区数量', 16 | 'multiDAnalysis.card.title.contentConsumption': '设备数量', 17 | 'multiDAnalysis.card.title.contentPublishingSource': '支付渠道详细分析', 18 | }; 19 | -------------------------------------------------------------------------------- /src/router/routes/modules/parkingVip.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/parkVip', 6 | name: 'ParkVip', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.parkVip', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'vipList', 17 | name: 'VipList', 18 | component: () => import('@/views/parkingVip/list/index.vue'), 19 | meta: { 20 | locale: 'menu.parkVip.list', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'packageType', 27 | name: 'PackageType', 28 | component: () => import('@/views/parkingVip/packageType/index.vue'), 29 | meta: { 30 | locale: 'menu.parkVip.packageType', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | }, 35 | ], 36 | }; 37 | 38 | export default DASHBOARD; 39 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # 停车场系统后台管理,新能源电动车充电系统,智慧社区物业人脸门禁后台管理 2 | 3 | #### 介绍 4 | 【涵盖内容】:城市智慧停车系统,汽车新能源充电,两轮电动车充电,物业缴费,社区到访记录,人脸门禁,上门报修等。 5 | 6 | 【开发框架】:字节跳动arco (https://arco.design/vue/docs/start) 7 | 8 | 【效果图】:方便大家直接看到效果,测试环境,不涉及任何广告,希望本产品能帮到各位开发者 9 | 10 | ![输入图片说明](%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231128142155.png) 11 | 12 | ![输入图片说明](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20231128142253.png) 13 | 14 | ![输入图片说明](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20231128142505.png) 15 | 16 | ![输入图片说明](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20231128142527.png) 17 | 18 | 19 | 20 | 【使用教程】:本代码全开源且完整,没有任何缺失和加密,不会存在我们故意动手脚导致你跑不起来的情况,建议使用Visual Studio Code打开和运行本代码,小白若需要技术支持(毕设勿扰,感谢您的万分理解),可以联系我公司技术人员(有偿:5000元/次) 21 | 22 | 【注意事项】:启动前请 仔细查阅 配置文件说明。 23 | 24 | 【关于后台服务数据】:①:自己开发服务后台,对接你自己的后台,②:购买 才风智慧 平台能力,8000元/年(可联系 18086495676购买) 25 | 26 | #### 版权声明 27 | 28 | 【研发公司】:才风智慧科技(武汉)有限公司,公司官网(https://www.cfeng.wang) 29 | 30 | 【代码版权】:才风智慧科技(武汉)有限公司100%原创研发,免费开源给大家使用,若您使用在商业领域,请勿申请软著,否则可能会影响到其它爱好者合法使用,我方也会追求您的法律责任 31 | 32 | 【加密情况】:本项目代码100%源代码开放,不存在任何加密和缺失,不存在任何后门,请放心使用 33 | 34 | -------------------------------------------------------------------------------- /src/api/verification.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | 4 | export function cfSmsGet(params: any) { 5 | return axios.get( 6 | '/validationAdmin/cfSms/getListByQuery', 7 | params 8 | ); 9 | } 10 | 11 | export function getThirdPartyPlatformListByQuery(params: any) { 12 | return axios.get( 13 | '/validationAdmin/cfFaceVerifyController/getThirdPartyPlatformListByQuery', 14 | params 15 | ); 16 | } 17 | 18 | export function getSmsConfigListByQuery(params: any) { 19 | return axios.get( 20 | '/validationAdmin/cfSms/getSmsConfigListByQuery', 21 | params 22 | ); 23 | } 24 | 25 | export function addSmsConfig(data: any) { 26 | return axios.post('/validationAdmin/cfSms/addSmsConfig', data); 27 | } 28 | 29 | export function deleteSmsConfig(params: any) { 30 | return axios.delete( 31 | '/validationAdmin/cfSms/deleteSmsConfig', 32 | params 33 | ); 34 | } 35 | 36 | export function updateSmsConfig(data: any) { 37 | return axios.put( 38 | '/validationAdmin/cfSms/updateSmsConfig', 39 | data 40 | ); 41 | } -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router'; 2 | import NProgress from 'nprogress'; // progress bar 3 | import 'nprogress/nprogress.css'; 4 | 5 | import { appRoutes } from './routes'; 6 | import { REDIRECT_MAIN, NOT_FOUND_ROUTE } from './routes/base'; 7 | import createRouteGuard from './guard'; 8 | 9 | NProgress.configure({ showSpinner: false }); // NProgress Configuration 10 | 11 | const router = createRouter({ 12 | history: createWebHistory(), 13 | routes: [ 14 | { 15 | path: '/', 16 | redirect: 'login', 17 | }, 18 | { 19 | path: '/login', 20 | name: 'login', 21 | component: () => import('@/views/login/index.vue'), 22 | meta: { 23 | requiresAuth: false, 24 | }, 25 | }, 26 | // @ts-ignore 27 | ...appRoutes, 28 | // @ts-ignore 29 | REDIRECT_MAIN, 30 | // @ts-ignore 31 | NOT_FOUND_ROUTE, 32 | ], 33 | scrollBehavior() { 34 | return { top: 0 }; 35 | }, 36 | }); 37 | 38 | createRouteGuard(router); 39 | 40 | export default router; 41 | -------------------------------------------------------------------------------- /src/router/routes/modules/files.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/files', 6 | name: 'Files', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.file', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'fileManageList', 17 | name: 'FileManageList', 18 | component: () => import('@/views/files/fileManageList/index.vue'), 19 | meta: { 20 | locale: 'menu.file.manage.list', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'filePlatformList', 27 | name: 'FilePlatformList', 28 | component: () => import('@/views/files/filePlatformList/index.vue'), 29 | meta: { 30 | locale: 'menu.file.platformList', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | } 35 | ], 36 | }; 37 | 38 | export default DASHBOARD; 39 | -------------------------------------------------------------------------------- /src/views/visualization/multi-dimension-data-analysis/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.multiDimensionDataAnalysis': 'Multi-D Analysis', 3 | 'multiDAnalysis.card.title.dataOverview': 'Overview', 4 | 'multiDAnalysis.dataOverview.contentProduction': 'Content Production', 5 | 'multiDAnalysis.dataOverview.contentClick': 'Content Click', 6 | 'multiDAnalysis.dataOverview.contentExposure': 'Content Exposure', 7 | 'multiDAnalysis.dataOverview.activeUsers': 'Active Users', 8 | 'multiDAnalysis.card.title.userActions': 'User Actions', 9 | 'multiDAnalysis.card.title.contentTypeDistribution': 10 | 'Content Type Distribution', 11 | 'multiDAnalysis.card.title.retentionTrends': 'Retention Trends', 12 | 'multiDAnalysis.card.title.userRetention': 'User Retention', 13 | 'multiDAnalysis.card.title.contentConsumptionTrends': 14 | 'Content Consumption Trends', 15 | 'multiDAnalysis.card.title.contentConsumption': 'Content Consumption', 16 | 'multiDAnalysis.card.title.contentPublishingSource': 17 | 'Content Publishing Source', 18 | }; 19 | -------------------------------------------------------------------------------- /src/router/routes/modules/chatRoute.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/chat', 6 | name: 'Chat', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.chat', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'messageList', 17 | name: 'MessageList', 18 | component: () => import('@/views/chatView/messageView/index.vue'), 19 | meta: { 20 | locale: 'menu.chat.message', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'notcieConfigList', 27 | name: 'NotcieConfigList', 28 | component: () => import('@/views/chatView/notcieConfigList/index.vue'), 29 | meta: { 30 | locale: 'menu.chat.message.NotcieConfigList', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | }, 35 | ], 36 | }; 37 | 38 | export default DASHBOARD; 39 | -------------------------------------------------------------------------------- /src/hooks/chart-option.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { EChartsOption } from 'echarts'; 3 | import { useAppStore } from '@/store'; 4 | 5 | // for code hints 6 | // import { SeriesOption } from 'echarts'; 7 | // Because there are so many configuration items, this provides a relatively convenient code hint. 8 | // When using vue, pay attention to the reactive issues. It is necessary to ensure that corresponding functions can be triggered, TypeScript does not report errors, and code writing is convenient. 9 | interface optionsFn { 10 | (isDark: boolean): EChartsOption; 11 | } 12 | 13 | export default function useChartOption(sourceOption: optionsFn) { 14 | const appStore = useAppStore(); 15 | const isDark = computed(() => { 16 | return appStore.theme === 'dark'; 17 | }); 18 | // echarts support https://echarts.apache.org/zh/theme-builder.html 19 | // It's not used here 20 | // TODO echarts themes 21 | const chartOption = computed(() => { 22 | return sourceOption(isDark.value); 23 | }); 24 | return { 25 | chartOption, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/locale/zh-CN/settings.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'settings.title': '页面配置', 3 | 'settings.themeColor': '主题色', 4 | 'settings.content': '内容区域', 5 | 'settings.search': '搜索', 6 | 'settings.language': '语言', 7 | 'settings.navbar': '导航栏', 8 | 'settings.menuWidth': '菜单宽度 (px)', 9 | 'settings.navbar.theme.toLight': '点击切换为亮色模式', 10 | 'settings.navbar.theme.toDark': '点击切换为暗黑模式', 11 | 'settings.navbar.screen.toFull': '点击切换全屏模式', 12 | 'settings.navbar.screen.toExit': '点击退出全屏模式', 13 | 'settings.navbar.alerts': '消息通知', 14 | 'settings.menu': '菜单栏', 15 | 'settings.tabBar': '多页签', 16 | 'settings.footer': '底部', 17 | 'settings.otherSettings': '其他设置', 18 | 'settings.colorWeak': '色弱模式', 19 | 'settings.alertContent': 20 | '配置之后仅是临时生效,要想真正作用于项目,点击下方的 "复制配置" 按钮,将配置替换到 settings.json 中即可。', 21 | 'settings.copySettings': '复制配置', 22 | 'settings.copySettings.message': 23 | '复制成功,请粘贴到 src/settings.json 文件中', 24 | 'settings.close': '关闭', 25 | 'settings.color.tooltip': 26 | '根据主题颜色生成的 10 个梯度色(将配置复制到项目中,主题色才能对亮色 / 暗黑模式同时生效)', 27 | 'settings.menuFromServer': '菜单来源于后台', 28 | }; 29 | -------------------------------------------------------------------------------- /src/views/visualization/villageDataCount/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.visualization.dataAnalysis': 'Analysis', 3 | 'dataAnalysis.title.publicOpinion': 'Public Opinion Analysis', 4 | 'dataAnalysis.card.title.allVisitors': 'All Visitors', 5 | 'dataAnalysis.card.title.contentPublished': 'Content Published', 6 | 'dataAnalysis.card.title.totalComment': 'Total Comment', 7 | 'dataAnalysis.card.title.totalShare': 'Total Share', 8 | 'dataAnalysis.card.yesterday': 'Yesterday', 9 | 'dataAnalysis.contentPublishRatio': 'Content Publishing Ratio', 10 | 'dataAnalysis.popularAuthor': 'Popular Author', 11 | 'dataAnalysis.popularAuthor.column.ranking': 'ranking', 12 | 'dataAnalysis.popularAuthor.column.author': 'author', 13 | 'dataAnalysis.popularAuthor.column.content': 'Content Number', 14 | 'dataAnalysis.popularAuthor.column.click': 'Click Number', 15 | 'dataAnalysis.contentPeriodAnalysis': 'Content Period Analysis', 16 | 'dataAnalysis.contentChargingPeriodAnalysis': 'Content Period Analysis', 17 | 'dataAnalysis.contentVillagePeriodAnalysis': 'Content Period Analysis', 18 | }; 19 | -------------------------------------------------------------------------------- /config/vite.config.prod.ts: -------------------------------------------------------------------------------- 1 | import { mergeConfig } from 'vite'; 2 | import baseConfig from './vite.config.base'; 3 | import configCompressPlugin from './plugin/compress'; 4 | import configVisualizerPlugin from './plugin/visualizer'; 5 | import configArcoResolverPlugin from './plugin/arcoResolver'; 6 | import configStyleImportPlugin from './plugin/styleImport'; 7 | import configImageminPlugin from './plugin/imagemin'; 8 | 9 | export default mergeConfig( 10 | { 11 | mode: 'production', 12 | plugins: [ 13 | configCompressPlugin('gzip'), 14 | configVisualizerPlugin(), 15 | configArcoResolverPlugin(), 16 | configStyleImportPlugin(), 17 | configImageminPlugin(), 18 | ], 19 | build: { 20 | rollupOptions: { 21 | output: { 22 | manualChunks: { 23 | arco: ['@arco-design/web-vue'], 24 | chart: ['echarts', 'vue-echarts'], 25 | vue: ['vue', 'vue-router', 'pinia', '@vueuse/core', 'vue-i18n'], 26 | }, 27 | }, 28 | }, 29 | chunkSizeWarningLimit: 2000, 30 | }, 31 | }, 32 | baseConfig 33 | ); 34 | -------------------------------------------------------------------------------- /src/api/chatApi.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | 4 | export function getUserMessageListByQuery(params: any) { 5 | return axios.get( 6 | '/chatAdmin/cfUserMessage/getUserMessageListByQuery', 7 | params 8 | ); 9 | } 10 | 11 | 12 | export function deleteUserMessage(params: any) { 13 | return axios.delete( 14 | '/chatAdmin/cfUserMessage/deleteUserMessage', 15 | params 16 | ); 17 | } 18 | 19 | export function getNoticeSettingListByQuery(params: any) { 20 | return axios.get( 21 | '/chatAdmin/cfUserMessage/getNoticeSettingListByQuery', 22 | params 23 | ); 24 | } 25 | export function addNoticeSetting(data: any) { 26 | return axios.post( 27 | '/chatAdmin/cfUserMessage/addNoticeSetting', 28 | data 29 | ); 30 | } 31 | 32 | export function deleteNoticeSetting(params: any) { 33 | return axios.delete( 34 | '​/chatAdmin​/cfUserMessage​/deleteNoticeSetting', 35 | params 36 | ); 37 | } 38 | export function updateNoticeSetting(data: any) { 39 | return axios.put( 40 | '/chatAdmin/cfUserMessage/updateNoticeSetting', 41 | data 42 | ); 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/carousel.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | -------------------------------------------------------------------------------- /src/components/chart/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/hooks/responsive.ts: -------------------------------------------------------------------------------- 1 | import { onMounted, onBeforeMount, onBeforeUnmount } from 'vue'; 2 | import { useDebounceFn } from '@vueuse/core'; 3 | import { useAppStore } from '@/store'; 4 | import { addEventListen, removeEventListen } from '@/utils/event'; 5 | 6 | const WIDTH = 992; // https://arco.design/vue/component/grid#responsivevalue 7 | 8 | function queryDevice() { 9 | const rect = document.body.getBoundingClientRect(); 10 | return rect.width - 1 < WIDTH; 11 | } 12 | 13 | export default function useResponsive(immediate?: boolean) { 14 | const appStore = useAppStore(); 15 | function resizeHandler() { 16 | if (!document.hidden) { 17 | const isMobile = queryDevice(); 18 | appStore.toggleDevice(isMobile ? 'mobile' : 'desktop'); 19 | appStore.toggleMenu(isMobile); 20 | } 21 | } 22 | const debounceFn = useDebounceFn(resizeHandler, 100); 23 | onMounted(() => { 24 | if (immediate) debounceFn(); 25 | }); 26 | onBeforeMount(() => { 27 | addEventListen(window, 'resize', debounceFn); 28 | }); 29 | onBeforeUnmount(() => { 30 | removeEventListen(window, 'resize', debounceFn); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/docs.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 43 | -------------------------------------------------------------------------------- /src/views/visualization/multi-dimension-data-analysis/components/data-chain-growth.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /src/hooks/permission.ts: -------------------------------------------------------------------------------- 1 | import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'; 2 | import { useUserStore } from '@/store'; 3 | 4 | export default function usePermission() { 5 | const userStore = useUserStore(); 6 | return { 7 | accessRouter(route: RouteLocationNormalized | RouteRecordRaw) { 8 | return ( 9 | !route.meta?.requiresAuth || 10 | !route.meta?.roles || 11 | route.meta?.roles?.includes('*') || 12 | route.meta?.roles?.includes(userStore.role) 13 | ); 14 | }, 15 | findFirstPermissionRoute(_routers: any, role = 'admin') { 16 | const cloneRouters = [..._routers]; 17 | while (cloneRouters.length) { 18 | const firstElement = cloneRouters.shift(); 19 | if ( 20 | firstElement?.meta?.roles?.find((el: string[]) => { 21 | return el.includes('*') || el.includes(role); 22 | }) 23 | ) 24 | return { name: firstElement.name }; 25 | if (firstElement?.children) { 26 | cloneRouters.push(...firstElement.children); 27 | } 28 | } 29 | return null; 30 | }, 31 | // You can add any rules you want 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/router/guard/userLoginInfo.ts: -------------------------------------------------------------------------------- 1 | import type { Router, LocationQueryRaw } from 'vue-router'; 2 | import NProgress from 'nprogress'; // progress bar 3 | 4 | import { useUserStore } from '@/store'; 5 | import { isLogin } from '@/utils/auth'; 6 | 7 | export default function setupUserLoginInfoGuard(router: Router) { 8 | router.beforeEach(async (to, from, next) => { 9 | NProgress.start(); 10 | const userStore = useUserStore(); 11 | if (isLogin()) { 12 | if (userStore.role) { 13 | next(); 14 | } else { 15 | try { 16 | await userStore.info(); 17 | next(); 18 | } catch (error) { 19 | await userStore.logout(); 20 | next({ 21 | name: 'login', 22 | query: { 23 | redirect: to.name, 24 | ...to.query, 25 | } as LocationQueryRaw, 26 | }); 27 | } 28 | } 29 | } else { 30 | if (to.name === 'login') { 31 | next(); 32 | return; 33 | } 34 | next({ 35 | name: 'login', 36 | query: { 37 | redirect: to.name, 38 | ...to.query, 39 | } as LocationQueryRaw, 40 | }); 41 | } 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/recently-visited.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 39 | 40 | 45 | -------------------------------------------------------------------------------- /config/vite.config.base.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { defineConfig } from 'vite'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import vueJsx from '@vitejs/plugin-vue-jsx'; 5 | import svgLoader from 'vite-svg-loader'; 6 | 7 | export default defineConfig({ 8 | plugins: [vue(), vueJsx(), svgLoader({ svgoConfig: {} })], 9 | resolve: { 10 | alias: [ 11 | { 12 | find: '@', 13 | replacement: resolve(__dirname, '../src'), 14 | }, 15 | { 16 | find: 'assets', 17 | replacement: resolve(__dirname, '../src/assets'), 18 | }, 19 | { 20 | find: 'vue-i18n', 21 | replacement: 'vue-i18n/dist/vue-i18n.cjs.js', // Resolve the i18n warning issue 22 | }, 23 | { 24 | find: 'vue', 25 | replacement: 'vue/dist/vue.esm-bundler.js', // compile template 26 | }, 27 | ], 28 | extensions: ['.ts', '.js'], 29 | }, 30 | define: { 31 | 'process.env': {}, 32 | }, 33 | css: { 34 | preprocessorOptions: { 35 | less: { 36 | modifyVars: { 37 | hack: `true; @import (reference) "${resolve( 38 | 'src/assets/style/breakpoint.less' 39 | )}";`, 40 | }, 41 | javascriptEnabled: true, 42 | }, 43 | }, 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /src/utils/jsonp.ts: -------------------------------------------------------------------------------- 1 | interface JsonpOptions { 2 | url: string; 3 | callbackParam?: string; 4 | timeout?: number; 5 | } 6 | 7 | export function jsonp(options: JsonpOptions): Promise { 8 | const { url, callbackParam = 'callback', timeout = 5000 } = options; 9 | 10 | let timeoutId: NodeJS.Timeout; 11 | 12 | return new Promise((resolve, reject) => { 13 | const callbackName = `jsonp_${Date.now()}`; 14 | 15 | // Attach the callback function to the global object 16 | (window as any)[callbackName] = (responseData: any) => { 17 | clearTimeout(timeoutId); 18 | delete (window as any)[callbackName]; 19 | document.body.removeChild(script); 20 | resolve(responseData); 21 | }; 22 | 23 | // Create the script element and set its source 24 | const script = document.createElement('script'); 25 | const fullUrl = `${url}${ 26 | url.includes('?') ? '&' : '?' 27 | }${callbackParam}=${callbackName}`; 28 | 29 | script.src = fullUrl; 30 | document.body.appendChild(script); 31 | 32 | // Set up a timeout to handle errors 33 | timeoutId = setTimeout(() => { 34 | delete (window as any)[callbackName]; 35 | document.body.removeChild(script); 36 | reject(new Error('JSONP request timed out')); 37 | }, timeout); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /src/router/routes/modules/verification.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/verification', 6 | name: 'Verification', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.validation.sms', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'sms', 17 | name: 'Sms', 18 | component: () => import('@/views/verification/sms/index.vue'), 19 | meta: { 20 | locale: 'menu.validation.sms.list', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'smsConfig', 27 | name: 'SmsConfig', 28 | component: () => import('@/views/verification/smsConfig/index.vue'), 29 | meta: { 30 | locale: 'menu.validation.sms.config', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | }, 35 | { 36 | path: 'faceVerifyList', 37 | name: 'FaceVerifyList', 38 | component: () => import('@/views/verification/faceList/index.vue'), 39 | meta: { 40 | locale: 'menu.validation.faceverify', 41 | requiresAuth: true, 42 | roles: ['*'], 43 | }, 44 | }, 45 | ], 46 | }; 47 | 48 | export default DASHBOARD; 49 | -------------------------------------------------------------------------------- /src/views/user/setting/components/certification.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/locale/en-US/settings.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'settings.title': 'Settings', 3 | 'settings.themeColor': 'Theme Color', 4 | 'settings.content': 'Content Setting', 5 | 'settings.search': 'Search', 6 | 'settings.language': 'Language', 7 | 'settings.navbar': 'Navbar', 8 | 'settings.menuWidth': 'Menu Width (px)', 9 | 'settings.navbar.theme.toLight': 'Click to use light mode', 10 | 'settings.navbar.theme.toDark': 'Click to use dark mode', 11 | 'settings.navbar.screen.toFull': 'Click to switch to full screen mode', 12 | 'settings.navbar.screen.toExit': 'Click to exit the full screen mode', 13 | 'settings.navbar.alerts': 'alerts', 14 | 'settings.menu': 'Menu', 15 | 'settings.tabBar': 'Tab Bar', 16 | 'settings.footer': 'Footer', 17 | 'settings.otherSettings': 'Other Settings', 18 | 'settings.colorWeak': 'Color Weak', 19 | 'settings.alertContent': 20 | 'After the configuration is only temporarily effective, if you want to really affect the project, click the "Copy Settings" button below and replace the configuration in settings.json.', 21 | 'settings.copySettings': 'Copy Settings', 22 | 'settings.copySettings.message': 23 | 'Copy succeeded, please paste to file src/settings.json.', 24 | 'settings.close': 'Close', 25 | 'settings.color.tooltip': 26 | '10 gradient colors generated according to the theme color', 27 | 'settings.menuFromServer': 'Menu From Server', 28 | }; 29 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/quick-operation.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | import localeMessageBox from '@/components/message-box/locale/en-US'; 2 | import localeLogin from '@/views/login/locale/en-US'; 3 | 4 | import localeWorkplace from '@/views/dashboard/workplace/locale/en-US'; 5 | 6 | import localPark from '@/views/park/locale/en-US'; 7 | import localParkVip from '@/views/parkingVip/locale/en-US'; 8 | import localUser from '@/views/user/locale/en-US'; 9 | import localeSettings from './en-US/settings'; 10 | import analysis from '@/views/visualization/multi-dimension-data-analysis/locale/en-US' 11 | 12 | export default { 13 | 'menu.dashboard': 'Dashboard', 14 | 'menu.server.dashboard': 'Dashboard-Server', 15 | 'menu.server.workplace': 'Workplace-Server', 16 | 'menu.server.monitor': 'Monitor-Server', 17 | 'menu.list': 'List', 18 | 'menu.result': 'Result', 19 | 'menu.exception': 'Exception', 20 | 'menu.form': 'Form', 21 | 'menu.profile': 'Profile', 22 | 'menu.visualization': 'Data Visualization', 23 | 'menu.user': 'User Center', 24 | 'menu.arcoWebsite': 'Arco Design', 25 | 'menu.faq': 'FAQ', 26 | 'navbar.docs': 'Docs', 27 | 'navbar.action.locale': 'Switch to English', 28 | 29 | 'menu.park': 'Park', 30 | 'menu.park.list': 'ParkList', 31 | 'menu.parkVip': 'Set meal', 32 | 'menu.park.title': 'parking chang', 33 | 'menu.parkVip.list': 'Set meal List', 34 | ...localeSettings, 35 | ...localeMessageBox, 36 | ...localeLogin, 37 | ...localeWorkplace, 38 | ...localPark, 39 | ...localParkVip, 40 | ...localUser, 41 | ...analysis, 42 | }; 43 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.dashboard.workplace': '工作台', 3 | 'workplace.welcome': '欢迎回来!', 4 | 'workplace.balance': '余额(元)', 5 | 'workplace.order.pending': '待支付', 6 | 'workplace.order.pendingRenewal': '待续费订单', 7 | 'workplace.onlineContent': '线上总内容', 8 | 'workplace.putIn': '投放中内容', 9 | 'workplace.newDay': '日新增评论', 10 | 'workplace.newFromYesterday': '较昨日新增', 11 | 'workplace.minute': '分钟', 12 | 'workplace.docs': '帮助文档', 13 | 'workplace.docs.productOverview': '产品概要', 14 | 'workplace.docs.userGuide': '使用指南', 15 | 'workplace.docs.workflow': '接入流程', 16 | 'workplace.docs.interfaceDocs': '接口文档', 17 | 'workplace.contentManagement': '内容管理', 18 | 'workplace.contentStatistical': '内容分析', 19 | 'workplace.advanced': '高级管理', 20 | 'workplace.onlinePromotion': '线上推广', 21 | 'workplace.contentPutIn': '内容投放', 22 | 'workplace.announcement': '公告', 23 | 'workplace.recently.visited': '最近访问', 24 | 'workplace.record.nodata': '暂无数据', 25 | 'workplace.quick.operation': '快捷操作', 26 | 'workplace.quickOperation.setup': '管理', 27 | 'workplace.allProject': '所有项目', 28 | 'workplace.loadMore': '加载更多', 29 | 'workplace.viewMore': '查看更多', 30 | 'workplace.contentData': '内容数据', 31 | 'workplace.popularContent': '线上热门内容', 32 | 'workplace.popularContent.text': '文本', 33 | 'workplace.popularContent.image': '图片', 34 | 'workplace.popularContent.video': '视频', 35 | 'workplace.categoriesPercent': '内容类型占比', 36 | 'workplace.paymentChannel': '支付渠道占比', 37 | 'workplace.pecs': '个', 38 | }; 39 | -------------------------------------------------------------------------------- /src/utils/is.ts: -------------------------------------------------------------------------------- 1 | const opt = Object.prototype.toString; 2 | 3 | export function isArray(obj: any): obj is any[] { 4 | return opt.call(obj) === '[object Array]'; 5 | } 6 | 7 | export function isObject(obj: any): obj is { [key: string]: any } { 8 | return opt.call(obj) === '[object Object]'; 9 | } 10 | 11 | export function isString(obj: any): obj is string { 12 | return opt.call(obj) === '[object String]'; 13 | } 14 | 15 | export function isNumber(obj: any): obj is number { 16 | return opt.call(obj) === '[object Number]' && obj === obj; // eslint-disable-line 17 | } 18 | 19 | export function isRegExp(obj: any) { 20 | return opt.call(obj) === '[object RegExp]'; 21 | } 22 | 23 | export function isFile(obj: any): obj is File { 24 | return opt.call(obj) === '[object File]'; 25 | } 26 | 27 | export function isBlob(obj: any): obj is Blob { 28 | return opt.call(obj) === '[object Blob]'; 29 | } 30 | 31 | export function isUndefined(obj: any): obj is undefined { 32 | return obj === undefined; 33 | } 34 | 35 | export function isNull(obj: any): obj is null { 36 | return obj === null; 37 | } 38 | 39 | export function isFunction(obj: any): obj is (...args: any[]) => any { 40 | return typeof obj === 'function'; 41 | } 42 | 43 | export function isEmptyObject(obj: any): boolean { 44 | return isObject(obj) && Object.keys(obj).length === 0; 45 | } 46 | 47 | export function isExist(obj: any): boolean { 48 | return obj || obj === 0; 49 | } 50 | 51 | export function isWindow(el: any): el is Window { 52 | return el === window; 53 | } 54 | -------------------------------------------------------------------------------- /src/views/files/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.file': '文件平台', 3 | 'menu.file.manage': '管理', 4 | 'menu.file.manage.list': '文件', 5 | 'menu.file.platformList': '平台', 6 | 7 | 8 | 'searchTable.form.search': '查询', 9 | 'searchTable.form.reset': '重置', 10 | 'searchTable.form.selectDefault': '全部', 11 | 'searchTable.operation.create': '新建', 12 | 'searchTable.operation.import': '批量导入', 13 | 'searchTable.operation.download': '下载', 14 | 15 | 'searchTable.form.nickName': '用户名', 16 | 'searchTable.form.nickName.placeholder': '请输入用户名', 17 | 'searchTable.form.userName': '账号', 18 | 'searchTable.form.userName.placeholder': '请输入账号', 19 | 'searchTable.form.phone': '手机号', 20 | 'searchTable.form.phone.placeholder': '请输入手机号', 21 | 'searchTable.form.sex': '性别', 22 | 'searchTable.form.sex.placeholder': '请选择性别', 23 | // columns 24 | 'searchTable.columns.index': '#', 25 | 'searchTable.columns.number': '集合编号', 26 | 'searchTable.columns.name': '集合名称', 27 | 'searchTable.columns.contentType': '内容体裁', 28 | 'searchTable.columns.filterType': '筛选方式', 29 | 'searchTable.columns.count': '内容量', 30 | 'searchTable.columns.createdTime': '创建时间', 31 | 'searchTable.columns.status': '状态', 32 | 'searchTable.columns.operations': '操作', 33 | 'searchTable.columns.operations.view': '查看', 34 | 35 | // size 36 | 'searchTable.size.mini': '迷你', 37 | 'searchTable.size.small': '偏小', 38 | 'searchTable.size.medium': '中等', 39 | 'searchTable.size.large': '偏大', 40 | // actions 41 | 'searchTable.actions.refresh': '刷新', 42 | 'searchTable.actions.density': '密度', 43 | 'searchTable.actions.columnSetting': '列设置', 44 | }; 45 | -------------------------------------------------------------------------------- /src/views/user/setting/index.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 37 | 38 | 56 | -------------------------------------------------------------------------------- /src/views/visualization/multi-dimension-data-analysis/mock.ts: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import setupMock, { successResponseWrap } from '@/utils/setup-mock'; 3 | import { PostData } from '@/types/global'; 4 | 5 | setupMock({ 6 | setup() { 7 | Mock.mock(new RegExp('/api/data-chain-growth'), (params: PostData) => { 8 | const { quota } = JSON.parse(params.body); 9 | const getLineData = () => { 10 | return { 11 | xAxis: new Array(12).fill(0).map((_item, index) => `${index + 1}日`), 12 | data: { 13 | name: quota, 14 | value: new Array(12) 15 | .fill(0) 16 | .map(() => Mock.Random.natural(1000, 3000)), 17 | }, 18 | }; 19 | }; 20 | return successResponseWrap({ 21 | count: Mock.Random.natural(1000, 3000), 22 | growth: Mock.Random.float(20, 100, 2, 2), 23 | chartData: getLineData(), 24 | }); 25 | }); 26 | // v2 27 | Mock.mock(new RegExp('/api/data-overview'), () => { 28 | const generateLineData = (name: string) => { 29 | return { 30 | name, 31 | count: Mock.Random.natural(20, 2000), 32 | value: new Array(8).fill(0).map(() => Mock.Random.natural(800, 4000)), 33 | }; 34 | }; 35 | const xAxis = new Array(8).fill(0).map((_item, index) => { 36 | return `12.1${index}`; 37 | }); 38 | return successResponseWrap({ 39 | xAxis, 40 | data: [ 41 | generateLineData('停车次数'), 42 | generateLineData('充电度数'), 43 | generateLineData('到访次数'), 44 | generateLineData('物业缴费'), 45 | ], 46 | }); 47 | }); 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /src/views/internet_of_things/carParkList/components/rules-preset.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/views/internet_of_things/chargingStation/components/rules-preset.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/views/visualization/multi-dimension-data-analysis/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 34 | 35 | 40 | 41 | 56 | -------------------------------------------------------------------------------- /src/router/routes/modules/dashboard.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_LAYOUT } from '../base'; 2 | import { AppRouteRecordRaw } from '../types'; 3 | 4 | const DASHBOARD: AppRouteRecordRaw = { 5 | path: '/dashboard', 6 | name: 'dashboard', 7 | component: DEFAULT_LAYOUT, 8 | meta: { 9 | locale: 'menu.dashboard', 10 | requiresAuth: true, 11 | icon: 'icon-dashboard', 12 | order: 0, 13 | }, 14 | children: [ 15 | { 16 | path: 'workplace', 17 | name: 'Workplace', 18 | component: () => import('@/views/visualization/multi-dimension-data-analysis/index.vue'), 19 | meta: { 20 | locale: 'menu.dashboard.workplace', 21 | requiresAuth: true, 22 | roles: ['*'], 23 | }, 24 | }, 25 | { 26 | path: 'parkingDataCount', 27 | name: 'ParkingDataCount', 28 | component: () => import('@/views/visualization/parkingDataCount/index.vue'), 29 | meta: { 30 | locale: 'menu.dashboard.parkingDataCount', 31 | requiresAuth: true, 32 | roles: ['*'], 33 | }, 34 | }, 35 | { 36 | path: 'chargingDataCount', 37 | name: 'ChargingDataCount', 38 | component: () => import('@/views/visualization/chargingDataCount/index.vue'), 39 | meta: { 40 | locale: 'menu.dashboard.chargingDataCount', 41 | requiresAuth: true, 42 | roles: ['*'], 43 | }, 44 | }, 45 | { 46 | path: 'villageDataCount', 47 | name: 'VillageDataCount', 48 | component: () => import('@/views/visualization/villageDataCount/index.vue'), 49 | meta: { 50 | locale: 'menu.dashboard.villageDataCount', 51 | requiresAuth: true, 52 | roles: ['*'], 53 | }, 54 | }, 55 | ], 56 | }; 57 | 58 | export default DASHBOARD; 59 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.dashboard.workplace': 'Workplace', 3 | 'workplace.welcome': 'Welcome!', 4 | 'workplace.balance': 'Balance (CNY)', 5 | 'workplace.order.pending': 'Pending', 6 | 'workplace.order.pendingRenewal': 'Renewal Order', 7 | 'workplace.onlineContent': 'Online Content', 8 | 'workplace.putIn': 'Put In', 9 | 'workplace.newDay': 'Daily Additional Comments', 10 | 'workplace.newFromYesterday': 'New From Yesterday', 11 | 'workplace.minute': 'Min', 12 | 'workplace.docs': 'Documents', 13 | 'workplace.docs.productOverview': 'Product Overview', 14 | 'workplace.docs.userGuide': 'User Guide', 15 | 'workplace.docs.workflow': 'Workflow', 16 | 'workplace.docs.interfaceDocs': 'Interface Docs', 17 | // 18 | 'workplace.contentManagement': 'Content Management', 19 | 'workplace.contentStatistical': 'Content Statistical', 20 | 'workplace.advanced': 'Advanced', 21 | 'workplace.onlinePromotion': 'Online Promotion', 22 | 'workplace.contentPutIn': 'Put In', 23 | 'workplace.announcement': 'Announcement', 24 | 'workplace.recently.visited': 'Recently Visited', 25 | 'workplace.record.nodata': 'No data', 26 | 'workplace.quick.operation': 'Quick Operation', 27 | 'workplace.quickOperation.setup': 'Setup', 28 | 'workplace.allProject': 'All', 29 | 'workplace.loadMore': 'More', 30 | 'workplace.viewMore': 'More', 31 | 'workplace.contentData': 'Content Data', 32 | 'workplace.popularContent': 'Popular Content', 33 | 'workplace.popularContent.text': 'text', 34 | 'workplace.popularContent.image': 'image', 35 | 'workplace.popularContent.video': 'video', 36 | 'workplace.categoriesPercent': 'Categories Percent', 37 | 'workplace.paymentChannel': 'The proportion of payment channels', 38 | 'workplace.pecs': 'pecs', 39 | }; 40 | -------------------------------------------------------------------------------- /src/views/dashboard/workplace/components/announcement.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 51 | 52 | 72 | -------------------------------------------------------------------------------- /src/components/global-setting/block.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 56 | 57 | 75 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/career/index.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 61 | 62 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/society/index.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 61 | 62 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/enterprise/index.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 61 | 62 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/government/index.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 61 | 62 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/individual/index.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 61 | 62 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount - 副本/index.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 39 | 40 | 45 | 46 | 66 | -------------------------------------------------------------------------------- /src/views/park/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.list.searchTable1': '停车场列表', 3 | 'menu.park.parkingRecord': '停车记录', 4 | 'menu.parkingRecord.searchTable': '停车记录列表', 5 | 'searchTable.form.parkName': '名称', 6 | 'searchTable.form.parkName.placeholder': '请输入停车场名名称', 7 | 'searchTable.form.name': '集合名称', 8 | 'searchTable.form.name.placeholder': '请输入集合名称', 9 | 'searchTable.form.contentType': '内容体裁', 10 | 'searchTable.form.contentType.img': '图文', 11 | 'searchTable.form.contentType.horizontalVideo': '横版短视频', 12 | 'searchTable.form.contentType.verticalVideo': '竖版小视频', 13 | 'searchTable.form.filterType': '筛选方式', 14 | 'searchTable.form.filterType.artificial': '人工筛选', 15 | 'searchTable.form.filterType.rules': '规则筛选', 16 | 'searchTable.form.createdTime': '创建时间', 17 | 'searchTable.form.status': '状态', 18 | 'searchTable.form.status.online': '已上线', 19 | 'searchTable.form.status.offline': '已下线', 20 | 'searchTable.form.search': '查询', 21 | 'searchTable.form.reset': '重置', 22 | 'searchTable.form.selectDefault': '全部', 23 | 'searchTable.operation.create': '新建', 24 | 'searchTable.operation.import': '批量导入', 25 | 'searchTable.operation.download': '下载', 26 | // columns 27 | 'searchTable.columns.index': '#', 28 | 'searchTable.columns.number': '集合编号', 29 | 'searchTable.columns.name': '集合名称', 30 | 'searchTable.columns.contentType': '内容体裁', 31 | 'searchTable.columns.filterType': '筛选方式', 32 | 'searchTable.columns.count': '内容量', 33 | 'searchTable.columns.createdTime': '创建时间', 34 | 'searchTable.columns.status': '状态', 35 | 'searchTable.columns.operations': '操作', 36 | 'searchTable.columns.operations.view': '查看', 37 | 38 | // size 39 | 'searchTable.size.mini': '迷你', 40 | 'searchTable.size.small': '偏小', 41 | 'searchTable.size.medium': '中等', 42 | 'searchTable.size.large': '偏大', 43 | // actions 44 | 'searchTable.actions.refresh': '刷新', 45 | 'searchTable.actions.density': '密度', 46 | 'searchTable.actions.columnSetting': '列设置', 47 | }; 48 | -------------------------------------------------------------------------------- /src/views/parkingVip/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.list.searchTable': '套餐列表', 3 | 'menu.park.parkingRecord': '停车记录', 4 | 'menu.parkingRecord.searchTable': '停车记录列表', 5 | 'searchTable.form.parkName': '名称', 6 | 'searchTable.form.parkName.placeholder': '请输入停车场名名称', 7 | 'searchTable.form.name': '集合名称', 8 | 'searchTable.form.name.placeholder': '请输入集合名称', 9 | 'searchTable.form.contentType': '内容体裁', 10 | 'searchTable.form.contentType.img': '图文', 11 | 'searchTable.form.contentType.horizontalVideo': '横版短视频', 12 | 'searchTable.form.contentType.verticalVideo': '竖版小视频', 13 | 'searchTable.form.filterType': '筛选方式', 14 | 'searchTable.form.filterType.artificial': '人工筛选', 15 | 'searchTable.form.filterType.rules': '规则筛选', 16 | 'searchTable.form.createdTime': '创建时间', 17 | 'searchTable.form.status': '状态', 18 | 'searchTable.form.status.online': '已上线', 19 | 'searchTable.form.status.offline': '已下线', 20 | 'searchTable.form.search': '查询', 21 | 'searchTable.form.reset': '重置', 22 | 'searchTable.form.selectDefault': '全部', 23 | 'searchTable.operation.create': '新建', 24 | 'searchTable.operation.import': '批量导入', 25 | 'searchTable.operation.download': '下载', 26 | // columns 27 | 'searchTable.columns.index': '#', 28 | 'searchTable.columns.number': '集合编号', 29 | 'searchTable.columns.name': '集合名称', 30 | 'searchTable.columns.contentType': '内容体裁', 31 | 'searchTable.columns.filterType': '筛选方式', 32 | 'searchTable.columns.count': '内容量', 33 | 'searchTable.columns.createdTime': '创建时间', 34 | 'searchTable.columns.status': '状态', 35 | 'searchTable.columns.operations': '操作', 36 | 'searchTable.columns.operations.view': '查看', 37 | 38 | // size 39 | 'searchTable.size.mini': '迷你', 40 | 'searchTable.size.small': '偏小', 41 | 'searchTable.size.medium': '中等', 42 | 'searchTable.size.large': '偏大', 43 | // actions 44 | 'searchTable.actions.refresh': '刷新', 45 | 'searchTable.actions.density': '密度', 46 | 'searchTable.actions.columnSetting': '列设置', 47 | }; 48 | -------------------------------------------------------------------------------- /src/views/visualization/chargingDataCount/index.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 40 | 41 | 46 | 47 | 67 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount/index.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 40 | 41 | 46 | 47 | 67 | -------------------------------------------------------------------------------- /src/views/visualization/villageDataCount/index.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 40 | 41 | 46 | 47 | 67 | -------------------------------------------------------------------------------- /src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import localeMessageBox from '@/components/message-box/locale/zh-CN'; 2 | import localeLogin from '@/views/login/locale/zh-CN'; 3 | import localeWorkplace from '@/views/dashboard/workplace/locale/zh-CN'; 4 | 5 | import localPark from '@/views/park/locale/zh-CN'; 6 | import localParkVip from '@/views/parkingVip/locale/zh-CN'; 7 | import localUser from '@/views/user/locale/zh-CN'; 8 | import localPay from '@/views/pay/locale/zh-CN'; 9 | import verification from '@/views/verification/locale/zh-CN'; 10 | import files from '@/views/files/locale/zh-CN'; 11 | import wisdomCommunity from '@/views/wisdomCommunity/locale/zh-CN'; 12 | import localInternetOfThings from '@/views/internet_of_things/locale/zh-CN'; 13 | import localChat from '@/views/chatView/locale/zh-CN'; 14 | import localeSettings from './zh-CN/settings'; 15 | import analysis from '@/views/visualization/multi-dimension-data-analysis/locale/zh-CN' 16 | import parkingDataCount from '@/views/visualization/parkingDataCount/locale/zh-CN' 17 | 18 | export default { 19 | 'menu.dashboard': '仪表盘', 20 | 'menu.server.dashboard': '仪表盘-服务端', 21 | 'menu.server.workplace': '工作台-服务端', 22 | 'menu.server.monitor': '实时监控-服务端', 23 | 'menu.list': '列表页', 24 | 'menu.result': '结果页', 25 | 'menu.exception': '异常页', 26 | 'menu.form': '表单页', 27 | 'menu.profile': '详情页', 28 | 'menu.visualization': '数据可视化', 29 | 'menu.user': '个人中心', 30 | 'menu.arcoWebsite': 'Arco Design', 31 | 'menu.faq': '常见问题', 32 | 'navbar.docs': '文档中心', 33 | 'navbar.action.locale': '切换为中文', 34 | 'menu.park': '停车', 35 | 'menu.park.list': '列表', 36 | 'menu.parkVip': '套餐', 37 | 'menu.parkVip.list': '列表', 38 | 'menu.park.title': '停车场', 39 | 'menu.parkVip.packageType': '产品', 40 | 'menu.ucenter.systemConfig.list': '系统配置管理', 41 | ...localeSettings, 42 | ...localeMessageBox, 43 | ...localeLogin, 44 | ...localeWorkplace, 45 | ...localPark, 46 | ...localParkVip, 47 | ...localUser, 48 | ...localPay, 49 | ...localInternetOfThings, 50 | ...verification, 51 | ...wisdomCommunity, 52 | ...analysis, 53 | ...localChat, 54 | ...parkingDataCount, 55 | ...files, 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/menu/use-menu-tree.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { RouteRecordRaw, RouteRecordNormalized } from 'vue-router'; 3 | import usePermission from '@/hooks/permission'; 4 | import { useAppStore } from '@/store'; 5 | import appClientMenus from '@/router/app-menus'; 6 | import { cloneDeep } from 'lodash'; 7 | 8 | export default function useMenuTree() { 9 | const permission = usePermission(); 10 | const appStore = useAppStore(); 11 | const appRoute = computed(() => { 12 | if (appStore.menuFromServer) { 13 | return appStore.appAsyncMenus; 14 | } 15 | return appClientMenus; 16 | }); 17 | const menuTree = computed(() => { 18 | const copyRouter = cloneDeep(appRoute.value) as RouteRecordNormalized[]; 19 | 20 | copyRouter.sort((a: RouteRecordNormalized, b: RouteRecordNormalized) => { 21 | return (a.meta.order || 0) - (b.meta.order || 0); 22 | }); 23 | function travel(_routes: RouteRecordRaw[], layer: number) { 24 | if (!_routes) return null; 25 | 26 | const collector: any = _routes.map((element) => { 27 | if (!permission.accessRouter(element)) { 28 | return null; 29 | } 30 | 31 | // leaf node 32 | if (element.meta?.hideChildrenInMenu || !element.children) { 33 | element.children = []; 34 | return element; 35 | } 36 | 37 | // route filter hideInMenu true 38 | element.children = element.children.filter( 39 | (x) => x.meta?.hideInMenu !== true 40 | ); 41 | 42 | // Associated child node 43 | const subItem = travel(element.children, layer + 1); 44 | 45 | if (subItem.length) { 46 | element.children = subItem; 47 | return element; 48 | } 49 | // the else logic 50 | if (layer > 1) { 51 | element.children = subItem; 52 | return element; 53 | } 54 | 55 | if (element.meta?.hideInMenu === false) { 56 | return element; 57 | } 58 | return null; 59 | }); 60 | return collector.filter(Boolean); 61 | } 62 | 63 | return travel(copyRouter, 0); 64 | }); 65 | return { 66 | menuTree, 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | root: true, 6 | parser: 'vue-eslint-parser', 7 | parserOptions: { 8 | // Parser that checks the content of the 41 | 42 | 85 | -------------------------------------------------------------------------------- /src/store/modules/tab-bar/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteLocationNormalized } from 'vue-router'; 2 | import { defineStore } from 'pinia'; 3 | import { 4 | DEFAULT_ROUTE, 5 | DEFAULT_ROUTE_NAME, 6 | REDIRECT_ROUTE_NAME, 7 | } from '@/router/constants'; 8 | import { isString } from '@/utils/is'; 9 | import { TabBarState, TagProps } from './types'; 10 | 11 | const formatTag = (route: RouteLocationNormalized): TagProps => { 12 | const { name, meta, fullPath, query } = route; 13 | return { 14 | title: meta.locale || '', 15 | name: String(name), 16 | fullPath, 17 | query, 18 | ignoreCache: meta.ignoreCache, 19 | }; 20 | }; 21 | 22 | const BAN_LIST = [REDIRECT_ROUTE_NAME]; 23 | 24 | const useAppStore = defineStore('tabBar', { 25 | state: (): TabBarState => ({ 26 | cacheTabList: new Set([DEFAULT_ROUTE_NAME]), 27 | tagList: [DEFAULT_ROUTE], 28 | }), 29 | 30 | getters: { 31 | getTabList(): TagProps[] { 32 | return this.tagList; 33 | }, 34 | getCacheList(): string[] { 35 | return Array.from(this.cacheTabList); 36 | }, 37 | }, 38 | 39 | actions: { 40 | updateTabList(route: RouteLocationNormalized) { 41 | if (BAN_LIST.includes(route.name as string)) return; 42 | this.tagList.push(formatTag(route)); 43 | if (!route.meta.ignoreCache) { 44 | this.cacheTabList.add(route.name as string); 45 | } 46 | }, 47 | deleteTag(idx: number, tag: TagProps) { 48 | this.tagList.splice(idx, 1); 49 | this.cacheTabList.delete(tag.name); 50 | }, 51 | addCache(name: string) { 52 | if (isString(name) && name !== '') this.cacheTabList.add(name); 53 | }, 54 | deleteCache(tag: TagProps) { 55 | this.cacheTabList.delete(tag.name); 56 | }, 57 | freshTabList(tags: TagProps[]) { 58 | this.tagList = tags; 59 | this.cacheTabList.clear(); 60 | // 要先判断ignoreCache 61 | this.tagList 62 | .filter((el) => !el.ignoreCache) 63 | .map((el) => el.name) 64 | .forEach((x) => this.cacheTabList.add(x)); 65 | }, 66 | resetTabList() { 67 | this.tagList = [DEFAULT_ROUTE]; 68 | this.cacheTabList.clear(); 69 | this.cacheTabList.add(DEFAULT_ROUTE_NAME); 70 | }, 71 | }, 72 | }); 73 | 74 | export default useAppStore; 75 | -------------------------------------------------------------------------------- /src/views/pay/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.list.searchTable1': 'ParkList', 3 | 'menu.park.parkingRecord': 'Parking Record', 4 | 'menu.parkingRecord.searchTable': 'Parking Record List', 5 | 'searchTable.form.parkName': 'Park Name', 6 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 7 | 'searchTable.form.number': 'Set Number', 8 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 9 | 'searchTable.form.name': 'Set Name', 10 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 11 | 'searchTable.form.contentType': 'Content Type', 12 | 'searchTable.form.contentType.img': 'image-text', 13 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 14 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 15 | 'searchTable.form.filterType': 'Filter Type', 16 | 'searchTable.form.filterType.artificial': 'artificial', 17 | 'searchTable.form.filterType.rules': 'Rules', 18 | 'searchTable.form.createdTime': 'Create Date', 19 | 'searchTable.form.status': 'Status', 20 | 'searchTable.form.status.online': 'Online', 21 | 'searchTable.form.status.offline': 'Offline', 22 | 'searchTable.form.search': 'Search', 23 | 'searchTable.form.reset': 'Reset', 24 | 'searchTable.form.selectDefault': 'All', 25 | 'searchTable.operation.create': 'Create', 26 | 'searchTable.operation.import': 'Import', 27 | 'searchTable.operation.download': 'Download', 28 | // columns 29 | 'searchTable.columns.index': '#', 30 | 'searchTable.columns.number': 'Set Number', 31 | 'searchTable.columns.name': 'Set Name', 32 | 'searchTable.columns.contentType': 'Content Type', 33 | 'searchTable.columns.filterType': 'Filter Type', 34 | 'searchTable.columns.count': 'Count', 35 | 'searchTable.columns.createdTime': 'CreatedTime', 36 | 'searchTable.columns.status': 'Status', 37 | 'searchTable.columns.operations': 'Operations', 38 | 'searchTable.columns.operations.view': 'View', 39 | // size 40 | 'searchTable.size.mini': 'mini', 41 | 'searchTable.size.small': 'small', 42 | 'searchTable.size.medium': 'middle', 43 | 'searchTable.size.large': 'large', 44 | // actions 45 | 'searchTable.actions.refresh': 'refresh', 46 | 'searchTable.actions.density': 'density', 47 | 'searchTable.actions.columnSetting': 'columnSetting', 48 | }; 49 | -------------------------------------------------------------------------------- /src/views/login/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 40 | 41 | 84 | 85 | 95 | -------------------------------------------------------------------------------- /src/views/park/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.list.searchTable1': 'ParkList', 3 | 'menu.park.parkingRecord': 'Parking Record', 4 | 'menu.parkingRecord.searchTable': 'Parking Record List', 5 | 'searchTable.form.parkName': 'Park Name', 6 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 7 | 'searchTable.form.number': 'Set Number', 8 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 9 | 'searchTable.form.name': 'Set Name', 10 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 11 | 'searchTable.form.contentType': 'Content Type', 12 | 'searchTable.form.contentType.img': 'image-text', 13 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 14 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 15 | 'searchTable.form.filterType': 'Filter Type', 16 | 'searchTable.form.filterType.artificial': 'artificial', 17 | 'searchTable.form.filterType.rules': 'Rules', 18 | 'searchTable.form.createdTime': 'Create Date', 19 | 'searchTable.form.status': 'Status', 20 | 'searchTable.form.status.online': 'Online', 21 | 'searchTable.form.status.offline': 'Offline', 22 | 'searchTable.form.search': 'Search', 23 | 'searchTable.form.reset': 'Reset', 24 | 'searchTable.form.selectDefault': 'All', 25 | 'searchTable.operation.create': 'Create', 26 | 'searchTable.operation.import': 'Import', 27 | 'searchTable.operation.download': 'Download', 28 | // columns 29 | 'searchTable.columns.index': '#', 30 | 'searchTable.columns.number': 'Set Number', 31 | 'searchTable.columns.name': 'Set Name', 32 | 'searchTable.columns.contentType': 'Content Type', 33 | 'searchTable.columns.filterType': 'Filter Type', 34 | 'searchTable.columns.count': 'Count', 35 | 'searchTable.columns.createdTime': 'CreatedTime', 36 | 'searchTable.columns.status': 'Status', 37 | 'searchTable.columns.operations': 'Operations', 38 | 'searchTable.columns.operations.view': 'View', 39 | // size 40 | 'searchTable.size.mini': 'mini', 41 | 'searchTable.size.small': 'small', 42 | 'searchTable.size.medium': 'middle', 43 | 'searchTable.size.large': 'large', 44 | // actions 45 | 'searchTable.actions.refresh': 'refresh', 46 | 'searchTable.actions.density': 'density', 47 | 'searchTable.actions.columnSetting': 'columnSetting', 48 | }; 49 | -------------------------------------------------------------------------------- /src/views/parkingVip/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.list.searchTable': 'Set meal List', 3 | 'menu.park.parkingRecord': 'Parking Record', 4 | 'menu.parkingRecord.searchTable': 'Parking Record List', 5 | 'searchTable.form.parkName': 'Park Name', 6 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 7 | 'searchTable.form.number': 'Set Number', 8 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 9 | 'searchTable.form.name': 'Set Name', 10 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 11 | 'searchTable.form.contentType': 'Content Type', 12 | 'searchTable.form.contentType.img': 'image-text', 13 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 14 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 15 | 'searchTable.form.filterType': 'Filter Type', 16 | 'searchTable.form.filterType.artificial': 'artificial', 17 | 'searchTable.form.filterType.rules': 'Rules', 18 | 'searchTable.form.createdTime': 'Create Date', 19 | 'searchTable.form.status': 'Status', 20 | 'searchTable.form.status.online': 'Online', 21 | 'searchTable.form.status.offline': 'Offline', 22 | 'searchTable.form.search': 'Search', 23 | 'searchTable.form.reset': 'Reset', 24 | 'searchTable.form.selectDefault': 'All', 25 | 'searchTable.operation.create': 'Create', 26 | 'searchTable.operation.import': 'Import', 27 | 'searchTable.operation.download': 'Download', 28 | // columns 29 | 'searchTable.columns.index': '#', 30 | 'searchTable.columns.number': 'Set Number', 31 | 'searchTable.columns.name': 'Set Name', 32 | 'searchTable.columns.contentType': 'Content Type', 33 | 'searchTable.columns.filterType': 'Filter Type', 34 | 'searchTable.columns.count': 'Count', 35 | 'searchTable.columns.createdTime': 'CreatedTime', 36 | 'searchTable.columns.status': 'Status', 37 | 'searchTable.columns.operations': 'Operations', 38 | 'searchTable.columns.operations.view': 'View', 39 | // size 40 | 'searchTable.size.mini': 'mini', 41 | 'searchTable.size.small': 'small', 42 | 'searchTable.size.medium': 'middle', 43 | 'searchTable.size.large': 'large', 44 | // actions 45 | 'searchTable.actions.refresh': 'refresh', 46 | 'searchTable.actions.density': 'density', 47 | 'searchTable.actions.columnSetting': 'columnSetting', 48 | }; 49 | -------------------------------------------------------------------------------- /src/assets/style/global.less: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body { 7 | width: 100%; 8 | height: 100%; 9 | margin: 0; 10 | padding: 0; 11 | font-size: 14px; 12 | background-color: var(--color-bg-1); 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-font-smoothing: antialiased; 15 | } 16 | 17 | .echarts-tooltip-diy { 18 | background: linear-gradient( 19 | 304.17deg, 20 | rgb(253 254 255 / 60%) -6.04%, 21 | rgb(244 247 252 / 60%) 85.2% 22 | ) !important; 23 | border: none !important; 24 | 25 | /* Note: backdrop-filter has minimal browser support */ 26 | 27 | border-radius: 6px !important; 28 | backdrop-filter: blur(10px) !important; 29 | 30 | .content-panel { 31 | display: flex; 32 | justify-content: space-between; 33 | width: 164px; 34 | height: 32px; 35 | margin-bottom: 4px; 36 | padding: 0 9px; 37 | line-height: 32px; 38 | background: rgb(255 255 255 / 80%); 39 | border-radius: 4px; 40 | box-shadow: 6px 0 20px rgb(34 87 188 / 10%); 41 | } 42 | 43 | .tooltip-title { 44 | margin: 0 0 10px; 45 | } 46 | 47 | p { 48 | margin: 0; 49 | } 50 | 51 | .tooltip-title, 52 | .tooltip-value { 53 | display: flex; 54 | align-items: center; 55 | color: #1d2129; 56 | font-weight: bold; 57 | font-size: 13px; 58 | line-height: 15px; 59 | text-align: right; 60 | } 61 | 62 | .tooltip-item-icon { 63 | display: inline-block; 64 | width: 10px; 65 | height: 10px; 66 | margin-right: 8px; 67 | border-radius: 50%; 68 | } 69 | } 70 | 71 | .general-card { 72 | border: none; 73 | border-radius: 4px; 74 | 75 | & > .arco-card-header { 76 | height: auto; 77 | padding: 20px; 78 | border: none; 79 | } 80 | 81 | & > .arco-card-body { 82 | padding: 0 20px 20px; 83 | } 84 | } 85 | 86 | .split-line { 87 | border-color: rgb(var(--gray-2)); 88 | } 89 | 90 | .arco-table-cell { 91 | .circle { 92 | display: inline-block; 93 | width: 6px; 94 | height: 6px; 95 | margin-right: 4px; 96 | background-color: rgb(var(--blue-6)); 97 | border-radius: 50%; 98 | 99 | &.pass { 100 | background-color: rgb(var(--green-6)); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/views/pay/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.pay': '支付', 3 | 'menu.pay.coupon': '优惠券', 4 | 'menu.pay.coupon.couponlist': '使用记录', 5 | 'menu.pay.coupon.activitylis': '活动列表', 6 | 'menu.pay.userPaymentAgency.wechatmerchantapplicationlist': '收款账号申请', 7 | 'menu.pay.order': '订单', 8 | 'menu.pay.order.list': '订单列表', 9 | 'menu.account': '资金', 10 | 'menu.pay.bank':'银行', 11 | 'menu.pay.bank.list':'银行列表', 12 | 'menu.pay.bank.bankBranchList': '支行列表', 13 | 'menu.account.list': '资金账户', 14 | 'menu.scoretype': '积分', 15 | 'menu.scoretype.list': '积分类型', 16 | 'menu.pay.userPaymentAgency': '收款账号', 17 | 'menu.pay.userPaymentAgency.list': '收款账号列表', 18 | 'searchTable.form.parkName': '名称', 19 | 'searchTable.form.name': '集合名称', 20 | 'searchTable.form.name.placeholder': '请输入集合名称', 21 | 'searchTable.form.contentType': '内容体裁', 22 | 'searchTable.form.contentType.img': '图文', 23 | 'searchTable.form.contentType.horizontalVideo': '横版短视频', 24 | 'searchTable.form.contentType.verticalVideo': '竖版小视频', 25 | 'searchTable.form.filterType': '筛选方式', 26 | 'searchTable.form.filterType.artificial': '人工筛选', 27 | 'searchTable.form.filterType.rules': '规则筛选', 28 | 'searchTable.form.createdTime': '创建时间', 29 | 'searchTable.form.status': '状态', 30 | 'searchTable.form.status.online': '已上线', 31 | 'searchTable.form.status.offline': '已下线', 32 | 'searchTable.form.search': '查询', 33 | 'searchTable.form.reset': '重置', 34 | 'searchTable.form.selectDefault': '全部', 35 | 'searchTable.operation.create': '新建', 36 | 'searchTable.operation.import': '批量导入', 37 | 'searchTable.operation.download': '下载', 38 | // columns 39 | 'searchTable.columns.index': '#', 40 | 'searchTable.columns.number': '集合编号', 41 | 'searchTable.columns.name': '集合名称', 42 | 'searchTable.columns.contentType': '内容体裁', 43 | 'searchTable.columns.filterType': '筛选方式', 44 | 'searchTable.columns.count': '内容量', 45 | 'searchTable.columns.createdTime': '创建时间', 46 | 'searchTable.columns.status': '状态', 47 | 'searchTable.columns.operations': '操作', 48 | 'searchTable.columns.operations.view': '查看', 49 | 50 | // size 51 | 'searchTable.size.mini': '迷你', 52 | 'searchTable.size.small': '偏小', 53 | 'searchTable.size.medium': '中等', 54 | 'searchTable.size.large': '偏大', 55 | // actions 56 | 'searchTable.actions.refresh': '刷新', 57 | 'searchTable.actions.density': '密度', 58 | 'searchTable.actions.columnSetting': '列设置', 59 | }; 60 | -------------------------------------------------------------------------------- /src/views/chatView/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.chat': '聊天', 3 | 'menu.chat.message': '消息', 4 | 'menu.chat.message.list': '消息列表', 5 | 'menu.chat.message.NotcieConfigList': '配置', 6 | 'menu.validation.faceverify.thirdpartyplatform': '记录', 7 | 'searchTable.form.parkName': '名称', 8 | 'searchTable.form.parkName.placeholder': '请输入停车场名名称', 9 | 'searchTable.form.name': '集合名称', 10 | 'searchTable.form.name.placeholder': '请输入集合名称', 11 | 'searchTable.form.contentType': '内容体裁', 12 | 'searchTable.form.contentType.img': '图文', 13 | 'searchTable.form.contentType.horizontalVideo': '横版短视频', 14 | 'searchTable.form.contentType.verticalVideo': '竖版小视频', 15 | 'searchTable.form.filterType': '筛选方式', 16 | 'searchTable.form.filterType.artificial': '人工筛选', 17 | 'searchTable.form.filterType.rules': '规则筛选', 18 | 'searchTable.form.createdTime': '创建时间', 19 | 'searchTable.form.status': '状态', 20 | 'searchTable.form.status.online': '已上线', 21 | 'searchTable.form.status.offline': '已下线', 22 | 'searchTable.form.search': '查询', 23 | 'searchTable.form.reset': '重置', 24 | 'searchTable.form.selectDefault': '全部', 25 | 'searchTable.operation.create': '新建', 26 | 'searchTable.operation.import': '批量导入', 27 | 'searchTable.operation.download': '下载', 28 | 29 | 'searchTable.form.nickName': '用户名', 30 | 'searchTable.form.nickName.placeholder': '请输入用户名', 31 | 'searchTable.form.userName': '账号', 32 | 'searchTable.form.userName.placeholder': '请输入账号', 33 | 'searchTable.form.phone': '手机号', 34 | 'searchTable.form.phone.placeholder': '请输入手机号', 35 | 'searchTable.form.sex': '性别', 36 | 'searchTable.form.sex.placeholder': '请选择性别', 37 | // columns 38 | 'searchTable.columns.index': '#', 39 | 'searchTable.columns.number': '集合编号', 40 | 'searchTable.columns.name': '集合名称', 41 | 'searchTable.columns.contentType': '内容体裁', 42 | 'searchTable.columns.filterType': '筛选方式', 43 | 'searchTable.columns.count': '内容量', 44 | 'searchTable.columns.createdTime': '创建时间', 45 | 'searchTable.columns.status': '状态', 46 | 'searchTable.columns.operations': '操作', 47 | 'searchTable.columns.operations.view': '查看', 48 | 49 | // size 50 | 'searchTable.size.mini': '迷你', 51 | 'searchTable.size.small': '偏小', 52 | 'searchTable.size.medium': '中等', 53 | 'searchTable.size.large': '偏大', 54 | // actions 55 | 'searchTable.actions.refresh': '刷新', 56 | 'searchTable.actions.density': '密度', 57 | 'searchTable.actions.columnSetting': '列设置', 58 | }; 59 | -------------------------------------------------------------------------------- /src/views/chatView/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 'searchTable.form.parkName': 'Park Name', 9 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 10 | 'searchTable.form.number': 'Set Number', 11 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 12 | 'searchTable.form.name': 'Set Name', 13 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 14 | 'searchTable.form.contentType': 'Content Type', 15 | 'searchTable.form.contentType.img': 'image-text', 16 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 17 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 18 | 'searchTable.form.filterType': 'Filter Type', 19 | 'searchTable.form.filterType.artificial': 'artificial', 20 | 'searchTable.form.filterType.rules': 'Rules', 21 | 'searchTable.form.createdTime': 'Create Date', 22 | 'searchTable.form.status': 'Status', 23 | 'searchTable.form.status.online': 'Online', 24 | 'searchTable.form.status.offline': 'Offline', 25 | 'searchTable.form.search': 'Search', 26 | 'searchTable.form.reset': 'Reset', 27 | 'searchTable.form.selectDefault': 'All', 28 | 'searchTable.operation.create': 'Create', 29 | 'searchTable.operation.import': 'Import', 30 | 'searchTable.operation.download': 'Download', 31 | // columns 32 | 'searchTable.columns.index': '#', 33 | 'searchTable.columns.number': 'Set Number', 34 | 'searchTable.columns.name': 'Set Name', 35 | 'searchTable.columns.contentType': 'Content Type', 36 | 'searchTable.columns.filterType': 'Filter Type', 37 | 'searchTable.columns.count': 'Count', 38 | 'searchTable.columns.createdTime': 'CreatedTime', 39 | 'searchTable.columns.status': 'Status', 40 | 'searchTable.columns.operations': 'Operations', 41 | 'searchTable.columns.operations.view': 'View', 42 | // size 43 | 'searchTable.size.mini': 'mini', 44 | 'searchTable.size.small': 'small', 45 | 'searchTable.size.medium': 'middle', 46 | 'searchTable.size.large': 'large', 47 | // actions 48 | 'searchTable.actions.refresh': 'refresh', 49 | 'searchTable.actions.density': 'density', 50 | 'searchTable.actions.columnSetting': 'columnSetting', 51 | }; 52 | -------------------------------------------------------------------------------- /src/views/files/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 'searchTable.form.parkName': 'Park Name', 9 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 10 | 'searchTable.form.number': 'Set Number', 11 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 12 | 'searchTable.form.name': 'Set Name', 13 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 14 | 'searchTable.form.contentType': 'Content Type', 15 | 'searchTable.form.contentType.img': 'image-text', 16 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 17 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 18 | 'searchTable.form.filterType': 'Filter Type', 19 | 'searchTable.form.filterType.artificial': 'artificial', 20 | 'searchTable.form.filterType.rules': 'Rules', 21 | 'searchTable.form.createdTime': 'Create Date', 22 | 'searchTable.form.status': 'Status', 23 | 'searchTable.form.status.online': 'Online', 24 | 'searchTable.form.status.offline': 'Offline', 25 | 'searchTable.form.search': 'Search', 26 | 'searchTable.form.reset': 'Reset', 27 | 'searchTable.form.selectDefault': 'All', 28 | 'searchTable.operation.create': 'Create', 29 | 'searchTable.operation.import': 'Import', 30 | 'searchTable.operation.download': 'Download', 31 | // columns 32 | 'searchTable.columns.index': '#', 33 | 'searchTable.columns.number': 'Set Number', 34 | 'searchTable.columns.name': 'Set Name', 35 | 'searchTable.columns.contentType': 'Content Type', 36 | 'searchTable.columns.filterType': 'Filter Type', 37 | 'searchTable.columns.count': 'Count', 38 | 'searchTable.columns.createdTime': 'CreatedTime', 39 | 'searchTable.columns.status': 'Status', 40 | 'searchTable.columns.operations': 'Operations', 41 | 'searchTable.columns.operations.view': 'View', 42 | // size 43 | 'searchTable.size.mini': 'mini', 44 | 'searchTable.size.small': 'small', 45 | 'searchTable.size.medium': 'middle', 46 | 'searchTable.size.large': 'large', 47 | // actions 48 | 'searchTable.actions.refresh': 'refresh', 49 | 'searchTable.actions.density': 'density', 50 | 'searchTable.actions.columnSetting': 'columnSetting', 51 | }; 52 | -------------------------------------------------------------------------------- /src/views/verification/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 'searchTable.form.parkName': 'Park Name', 9 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 10 | 'searchTable.form.number': 'Set Number', 11 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 12 | 'searchTable.form.name': 'Set Name', 13 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 14 | 'searchTable.form.contentType': 'Content Type', 15 | 'searchTable.form.contentType.img': 'image-text', 16 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 17 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 18 | 'searchTable.form.filterType': 'Filter Type', 19 | 'searchTable.form.filterType.artificial': 'artificial', 20 | 'searchTable.form.filterType.rules': 'Rules', 21 | 'searchTable.form.createdTime': 'Create Date', 22 | 'searchTable.form.status': 'Status', 23 | 'searchTable.form.status.online': 'Online', 24 | 'searchTable.form.status.offline': 'Offline', 25 | 'searchTable.form.search': 'Search', 26 | 'searchTable.form.reset': 'Reset', 27 | 'searchTable.form.selectDefault': 'All', 28 | 'searchTable.operation.create': 'Create', 29 | 'searchTable.operation.import': 'Import', 30 | 'searchTable.operation.download': 'Download', 31 | // columns 32 | 'searchTable.columns.index': '#', 33 | 'searchTable.columns.number': 'Set Number', 34 | 'searchTable.columns.name': 'Set Name', 35 | 'searchTable.columns.contentType': 'Content Type', 36 | 'searchTable.columns.filterType': 'Filter Type', 37 | 'searchTable.columns.count': 'Count', 38 | 'searchTable.columns.createdTime': 'CreatedTime', 39 | 'searchTable.columns.status': 'Status', 40 | 'searchTable.columns.operations': 'Operations', 41 | 'searchTable.columns.operations.view': 'View', 42 | // size 43 | 'searchTable.size.mini': 'mini', 44 | 'searchTable.size.small': 'small', 45 | 'searchTable.size.medium': 'middle', 46 | 'searchTable.size.large': 'large', 47 | // actions 48 | 'searchTable.actions.refresh': 'refresh', 49 | 'searchTable.actions.density': 'density', 50 | 'searchTable.actions.columnSetting': 'columnSetting', 51 | }; 52 | -------------------------------------------------------------------------------- /src/views/internet_of_things/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 'searchTable.form.parkName': 'Park Name', 9 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 10 | 'searchTable.form.number': 'Set Number', 11 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 12 | 'searchTable.form.name': 'Set Name', 13 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 14 | 'searchTable.form.contentType': 'Content Type', 15 | 'searchTable.form.contentType.img': 'image-text', 16 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 17 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 18 | 'searchTable.form.filterType': 'Filter Type', 19 | 'searchTable.form.filterType.artificial': 'artificial', 20 | 'searchTable.form.filterType.rules': 'Rules', 21 | 'searchTable.form.createdTime': 'Create Date', 22 | 'searchTable.form.status': 'Status', 23 | 'searchTable.form.status.online': 'Online', 24 | 'searchTable.form.status.offline': 'Offline', 25 | 'searchTable.form.search': 'Search', 26 | 'searchTable.form.reset': 'Reset', 27 | 'searchTable.form.selectDefault': 'All', 28 | 'searchTable.operation.create': 'Create', 29 | 'searchTable.operation.import': 'Import', 30 | 'searchTable.operation.download': 'Download', 31 | // columns 32 | 'searchTable.columns.index': '#', 33 | 'searchTable.columns.number': 'Set Number', 34 | 'searchTable.columns.name': 'Set Name', 35 | 'searchTable.columns.contentType': 'Content Type', 36 | 'searchTable.columns.filterType': 'Filter Type', 37 | 'searchTable.columns.count': 'Count', 38 | 'searchTable.columns.createdTime': 'CreatedTime', 39 | 'searchTable.columns.status': 'Status', 40 | 'searchTable.columns.operations': 'Operations', 41 | 'searchTable.columns.operations.view': 'View', 42 | // size 43 | 'searchTable.size.mini': 'mini', 44 | 'searchTable.size.small': 'small', 45 | 'searchTable.size.medium': 'middle', 46 | 'searchTable.size.large': 'large', 47 | // actions 48 | 'searchTable.actions.refresh': 'refresh', 49 | 'searchTable.actions.density': 'density', 50 | 'searchTable.actions.columnSetting': 'columnSetting', 51 | }; 52 | -------------------------------------------------------------------------------- /src/views/wisdomCommunity/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 'searchTable.form.parkName': 'Park Name', 9 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 10 | 'searchTable.form.number': 'Set Number', 11 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 12 | 'searchTable.form.name': 'Set Name', 13 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 14 | 'searchTable.form.contentType': 'Content Type', 15 | 'searchTable.form.contentType.img': 'image-text', 16 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 17 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 18 | 'searchTable.form.filterType': 'Filter Type', 19 | 'searchTable.form.filterType.artificial': 'artificial', 20 | 'searchTable.form.filterType.rules': 'Rules', 21 | 'searchTable.form.createdTime': 'Create Date', 22 | 'searchTable.form.status': 'Status', 23 | 'searchTable.form.status.online': 'Online', 24 | 'searchTable.form.status.offline': 'Offline', 25 | 'searchTable.form.search': 'Search', 26 | 'searchTable.form.reset': 'Reset', 27 | 'searchTable.form.selectDefault': 'All', 28 | 'searchTable.operation.create': 'Create', 29 | 'searchTable.operation.import': 'Import', 30 | 'searchTable.operation.download': 'Download', 31 | // columns 32 | 'searchTable.columns.index': '#', 33 | 'searchTable.columns.number': 'Set Number', 34 | 'searchTable.columns.name': 'Set Name', 35 | 'searchTable.columns.contentType': 'Content Type', 36 | 'searchTable.columns.filterType': 'Filter Type', 37 | 'searchTable.columns.count': 'Count', 38 | 'searchTable.columns.createdTime': 'CreatedTime', 39 | 'searchTable.columns.status': 'Status', 40 | 'searchTable.columns.operations': 'Operations', 41 | 'searchTable.columns.operations.view': 'View', 42 | // size 43 | 'searchTable.size.mini': 'mini', 44 | 'searchTable.size.small': 'small', 45 | 'searchTable.size.medium': 'middle', 46 | 'searchTable.size.large': 'large', 47 | // actions 48 | 'searchTable.actions.refresh': 'refresh', 49 | 'searchTable.actions.density': 'density', 50 | 'searchTable.actions.columnSetting': 'columnSetting', 51 | }; 52 | -------------------------------------------------------------------------------- /src/router/guard/permission.ts: -------------------------------------------------------------------------------- 1 | import type { Router, RouteRecordNormalized } from 'vue-router'; 2 | import NProgress from 'nprogress'; // progress bar 3 | import usePermission from '@/hooks/permission'; 4 | import { useUserStore, useAppStore } from '@/store'; 5 | import { appRoutes } from '../routes'; 6 | import { WHITE_LIST, NOT_FOUND } from '../constants'; 7 | 8 | export default function setupPermissionGuard(router: Router) { 9 | router.beforeEach(async (to, from, next) => { 10 | const appStore = useAppStore(); 11 | const userStore = useUserStore(); 12 | const Permission = usePermission(); 13 | const permissionsAllow = Permission.accessRouter(to); 14 | if (appStore.menuFromServer) { 15 | // 针对来自服务端的菜单配置进行处理 16 | // Handle routing configuration from the server 17 | 18 | // 根据需要自行完善来源于服务端的菜单配置的permission逻辑 19 | // Refine the permission logic from the server's menu configuration as needed 20 | if ( 21 | !appStore.appAsyncMenus.length && 22 | !WHITE_LIST.find((el) => el.name === to.name) 23 | ) { 24 | await appStore.fetchServerMenuConfig(); 25 | } 26 | // eslint-disable-next-line no-console 27 | // console.log(router.options.routes, 999); 28 | // console.log(appStore.appAsyncMenus,999); 29 | // console.log(router, 'router'); 30 | // appStore.appAsyncMenus.forEach(element => { 31 | // router.addRoute(element) 32 | // }); 33 | // @ts-ignore 34 | // router.addRoute(appStore.appAsyncMenus) 35 | 36 | const serverMenuConfig = [...appStore.appAsyncMenus, ...WHITE_LIST]; 37 | 38 | let exist = false; 39 | while (serverMenuConfig.length && !exist) { 40 | const element = serverMenuConfig.shift(); 41 | if (element?.name === to.name) exist = true; 42 | 43 | if (element?.children) { 44 | serverMenuConfig.push( 45 | ...(element.children as unknown as RouteRecordNormalized[]) 46 | ); 47 | } 48 | } 49 | 50 | if (exist && permissionsAllow) { 51 | next(); 52 | } else next(NOT_FOUND); 53 | } else { 54 | // eslint-disable-next-line no-lonely-if 55 | if (permissionsAllow) next(); 56 | else { 57 | const destination = 58 | Permission.findFirstPermissionRoute(appRoutes, userStore.role) || 59 | NOT_FOUND; 60 | next(destination); 61 | } 62 | } 63 | NProgress.done(); 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /src/mock/message-box.ts: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs'; 2 | import setupMock, { successResponseWrap } from '@/utils/setup-mock'; 3 | 4 | const haveReadIds: number[] = []; 5 | const getMessageList = () => { 6 | return [ 7 | { 8 | id: 1, 9 | type: 'message', 10 | title: '郑曦月', 11 | subTitle: '的私信', 12 | avatar: 13 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/8361eeb82904210b4f55fab888fe8416.png~tplv-uwbnlip3yd-webp.webp', 14 | content: '审批请求已发送,请查收', 15 | time: '今天 12:30:01', 16 | }, 17 | { 18 | id: 2, 19 | type: 'message', 20 | title: '宁波', 21 | subTitle: '的回复', 22 | avatar: 23 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp', 24 | content: '此处 bug 已经修复', 25 | time: '今天 12:30:01', 26 | }, 27 | { 28 | id: 3, 29 | type: 'message', 30 | title: '宁波', 31 | subTitle: '的回复', 32 | avatar: 33 | '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp', 34 | content: '此处 bug 已经修复', 35 | time: '今天 12:20:01', 36 | }, 37 | { 38 | id: 4, 39 | type: 'notice', 40 | title: '续费通知', 41 | subTitle: '', 42 | avatar: '', 43 | content: '您的产品使用期限即将截止,如需继续使用产品请前往购…', 44 | time: '今天 12:20:01', 45 | messageType: 3, 46 | }, 47 | { 48 | id: 5, 49 | type: 'notice', 50 | title: '规则开通成功', 51 | subTitle: '', 52 | avatar: '', 53 | content: '内容屏蔽规则于 2021-12-01 开通成功并生效', 54 | time: '今天 12:20:01', 55 | messageType: 1, 56 | }, 57 | { 58 | id: 6, 59 | type: 'todo', 60 | title: '质检队列变更', 61 | subTitle: '', 62 | avatar: '', 63 | content: '内容质检队列于 2021-12-01 19:50:23 进行变更,请重新…', 64 | time: '今天 12:20:01', 65 | messageType: 0, 66 | }, 67 | ].map((item) => ({ 68 | ...item, 69 | status: haveReadIds.indexOf(item.id) === -1 ? 0 : 1, 70 | })); 71 | }; 72 | 73 | setupMock({ 74 | mock: false, 75 | setup: () => { 76 | Mock.mock(new RegExp('/api/message/list'), () => { 77 | return successResponseWrap(getMessageList()); 78 | }); 79 | 80 | Mock.mock(new RegExp('/api/message/read'), (params: { body: string }) => { 81 | const { ids } = JSON.parse(params.body); 82 | haveReadIds.push(...(ids || [])); 83 | return successResponseWrap(true); 84 | }); 85 | }, 86 | }); 87 | -------------------------------------------------------------------------------- /src/views/verification/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.validation': '验证', 3 | 'menu.validation.sms': '短信', 4 | 'menu.validation.sms.list': '短信列表', 5 | 'menu.validation.sms.config':'短信配置', 6 | 'menu.validation.faceverify': '人脸识别', 7 | 'menu.validation.faceverify.thirdpartyplatform': '记录', 8 | 'searchTable.form.parkName': '名称', 9 | 'searchTable.form.parkName.placeholder': '请输入停车场名名称', 10 | 'searchTable.form.name': '集合名称', 11 | 'searchTable.form.name.placeholder': '请输入集合名称', 12 | 'searchTable.form.contentType': '内容体裁', 13 | 'searchTable.form.contentType.img': '图文', 14 | 'searchTable.form.contentType.horizontalVideo': '横版短视频', 15 | 'searchTable.form.contentType.verticalVideo': '竖版小视频', 16 | 'searchTable.form.filterType': '筛选方式', 17 | 'searchTable.form.filterType.artificial': '人工筛选', 18 | 'searchTable.form.filterType.rules': '规则筛选', 19 | 'searchTable.form.createdTime': '创建时间', 20 | 'searchTable.form.status': '状态', 21 | 'searchTable.form.status.online': '已上线', 22 | 'searchTable.form.status.offline': '已下线', 23 | 'searchTable.form.search': '查询', 24 | 'searchTable.form.reset': '重置', 25 | 'searchTable.form.selectDefault': '全部', 26 | 'searchTable.operation.create': '新建', 27 | 'searchTable.operation.import': '批量导入', 28 | 'searchTable.operation.download': '下载', 29 | 30 | 'searchTable.form.nickName': '用户名', 31 | 'searchTable.form.nickName.placeholder': '请输入用户名', 32 | 'searchTable.form.userName': '账号', 33 | 'searchTable.form.userName.placeholder': '请输入账号', 34 | 'searchTable.form.phone': '手机号', 35 | 'searchTable.form.phone.placeholder': '请输入手机号', 36 | 'searchTable.form.sex': '性别', 37 | 'searchTable.form.sex.placeholder': '请选择性别', 38 | // columns 39 | 'searchTable.columns.index': '#', 40 | 'searchTable.columns.number': '集合编号', 41 | 'searchTable.columns.name': '集合名称', 42 | 'searchTable.columns.contentType': '内容体裁', 43 | 'searchTable.columns.filterType': '筛选方式', 44 | 'searchTable.columns.count': '内容量', 45 | 'searchTable.columns.createdTime': '创建时间', 46 | 'searchTable.columns.status': '状态', 47 | 'searchTable.columns.operations': '操作', 48 | 'searchTable.columns.operations.view': '查看', 49 | 50 | // size 51 | 'searchTable.size.mini': '迷你', 52 | 'searchTable.size.small': '偏小', 53 | 'searchTable.size.medium': '中等', 54 | 'searchTable.size.large': '偏大', 55 | // actions 56 | 'searchTable.actions.refresh': '刷新', 57 | 'searchTable.actions.density': '密度', 58 | 'searchTable.actions.columnSetting': '列设置', 59 | }; 60 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount - 副本/components/popular-author.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 70 | 71 | 76 | -------------------------------------------------------------------------------- /src/views/visualization/chargingDataCount/components/public-opinion - 副本.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount - 副本/components/public-opinion.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /src/views/visualization/parkingDataCount/components/public-opinion - 副本.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /src/views/visualization/villageDataCount/components/public-opinion - 副本.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /src/views/user/locale/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.ucenter': 'User Center', 3 | 'menu.ucenter.user': 'User', 4 | 'menu.ucenter.user.list': 'User List', 5 | 'menu.list.searchTable': 'Set meal List', 6 | 'menu.park.parkingRecord': 'Parking Record', 7 | 'menu.parkingRecord.searchTable': 'Parking Record List', 8 | 9 | 'menu.ucenter.ad': 'Advertisement Management', 10 | 'menu.ucenter.ad.adlist.': 'Advertising List', 11 | 12 | 'searchTable.form.parkName': 'Park Name', 13 | 'searchTable.form.parkName.placeholder': 'Please enter Park Name', 14 | 'searchTable.form.number': 'Set Number', 15 | 'searchTable.form.number.placeholder': 'Please enter Set Number', 16 | 'searchTable.form.name': 'Set Name', 17 | 'searchTable.form.name.placeholder': 'Please enter Set Name', 18 | 'searchTable.form.contentType': 'Content Type', 19 | 'searchTable.form.contentType.img': 'image-text', 20 | 'searchTable.form.contentType.horizontalVideo': 'Horizontal short video', 21 | 'searchTable.form.contentType.verticalVideo': 'Vertical short video', 22 | 'searchTable.form.filterType': 'Filter Type', 23 | 'searchTable.form.filterType.artificial': 'artificial', 24 | 'searchTable.form.filterType.rules': 'Rules', 25 | 'searchTable.form.createdTime': 'Create Date', 26 | 'searchTable.form.status': 'Status', 27 | 'searchTable.form.status.online': 'Online', 28 | 'searchTable.form.status.offline': 'Offline', 29 | 'searchTable.form.search': 'Search', 30 | 'searchTable.form.reset': 'Reset', 31 | 'searchTable.form.selectDefault': 'All', 32 | 'searchTable.operation.create': 'Create', 33 | 'searchTable.operation.import': 'Import', 34 | 'searchTable.operation.download': 'Download', 35 | // columns 36 | 'searchTable.columns.index': '#', 37 | 'searchTable.columns.number': 'Set Number', 38 | 'searchTable.columns.name': 'Set Name', 39 | 'searchTable.columns.contentType': 'Content Type', 40 | 'searchTable.columns.filterType': 'Filter Type', 41 | 'searchTable.columns.count': 'Count', 42 | 'searchTable.columns.createdTime': 'CreatedTime', 43 | 'searchTable.columns.status': 'Status', 44 | 'searchTable.columns.operations': 'Operations', 45 | 'searchTable.columns.operations.view': 'View', 46 | // size 47 | 'searchTable.size.mini': 'mini', 48 | 'searchTable.size.small': 'small', 49 | 'searchTable.size.medium': 'middle', 50 | 'searchTable.size.large': 'large', 51 | // actions 52 | 'searchTable.actions.refresh': 'refresh', 53 | 'searchTable.actions.density': 'density', 54 | 'searchTable.actions.columnSetting': 'columnSetting', 55 | }; 56 | -------------------------------------------------------------------------------- /src/store/modules/user/index.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia'; 2 | import { 3 | login as userLogin, 4 | // logout as userLogout, 5 | // getUserInfo, 6 | logout, 7 | LoginData, 8 | } from '@/api/user'; 9 | import { setToken, clearToken } from '@/utils/auth'; 10 | import { removeRouteListener } from '@/utils/route-listener'; 11 | import { UserState } from './types'; 12 | import useAppStore from '../app'; 13 | import { S } from 'mockjs'; 14 | 15 | const useUserStore = defineStore('user', { 16 | state: (): UserState => ({ 17 | name: undefined, 18 | avatar: undefined, 19 | job: undefined, 20 | organization: undefined, 21 | location: undefined, 22 | email: undefined, 23 | introduction: undefined, 24 | personalWebsite: undefined, 25 | jobName: undefined, 26 | organizationName: undefined, 27 | locationName: undefined, 28 | phone: undefined, 29 | registrationDate: undefined, 30 | accountId: undefined, 31 | certification: undefined, 32 | role: '', 33 | }), 34 | 35 | getters: { 36 | userInfo(state: UserState): UserState { 37 | return { ...state }; 38 | }, 39 | }, 40 | 41 | actions: { 42 | switchRoles() { 43 | return new Promise((resolve) => { 44 | this.role = this.role === 'user' ? 'admin' : 'user'; 45 | resolve(this.role); 46 | }); 47 | }, 48 | // Set user's information 49 | setInfo(partial: Partial) { 50 | this.$patch(partial); 51 | }, 52 | setAvatar(url: string) { 53 | this.avatar = url; 54 | }, 55 | 56 | // Reset user's information 57 | resetInfo() { 58 | this.$reset(); 59 | }, 60 | 61 | // Get user's information 62 | async info() { 63 | // const res = await getUserInfo(); 64 | // this.setInfo(res.data); 65 | }, 66 | 67 | // Login 68 | async login(loginForm: LoginData) { 69 | try { 70 | const res = await userLogin(loginForm); 71 | setToken(res.data.authToken.access_token); 72 | this.setInfo(res.data); 73 | this.setAvatar(res.data.avatar) 74 | } catch (err) { 75 | clearToken(); 76 | throw err; 77 | } 78 | }, 79 | logoutCallBack() { 80 | const appStore = useAppStore(); 81 | this.resetInfo(); 82 | clearToken(); 83 | removeRouteListener(); 84 | appStore.clearServerMenu(); 85 | }, 86 | // Logout 87 | async logout() { 88 | // await logout(); 89 | this.logoutCallBack(); 90 | }, 91 | }, 92 | }); 93 | 94 | export default useUserStore; 95 | -------------------------------------------------------------------------------- /beizhu.txt: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arco-design-pro-vue", 3 | "description": "Arco Design Pro for Vue", 4 | "version": "1.0.0", 5 | "private": true, 6 | "author": "ArcoDesign Team", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "vite --config ./config/vite.config.dev.ts", 10 | "build": "vue-tsc --noEmit && vite build --config ./config/vite.config.prod.ts", 11 | "build-r": "vite build --config ./config/vite.config.prod.ts", 12 | "report": "cross-env REPORT=true npm run build", 13 | "preview": "npm run build && vite preview --host", 14 | "type:check": "vue-tsc --noEmit --skipLibCheck", 15 | "lint-staged": "npx lint-staged", 16 | "prepare": "husky install" 17 | }, 18 | "dependencies": { 19 | "@arco-design/web-vue": "^2.37.4", 20 | "@vueuse/core": "^9.3.0", 21 | "axios": "^0.24.0", 22 | "dayjs": "^1.11.5", 23 | "echarts": "^5.4.0", 24 | "lodash": "^4.17.21", 25 | "mitt": "^3.0.0", 26 | "nprogress": "^0.2.0", 27 | "pinia": "^2.0.23", 28 | "query-string": "^7.1.1", 29 | "sortablejs": "^1.15.0", 30 | "vue": "^3.2.40", 31 | "vue-clipboard3": "^2.0.0", 32 | "vue-echarts": "^6.2.3", 33 | "vue-i18n": "^9.2.2", 34 | "vue-router": "^4.0.14" 35 | }, 36 | "devDependencies": { 37 | "@commitlint/cli": "^17.1.2", 38 | "@commitlint/config-conventional": "^17.1.0", 39 | "@types/lodash": "^4.14.186", 40 | "@types/mockjs": "^1.0.7", 41 | "@types/nprogress": "^0.2.0", 42 | "@types/sortablejs": "^1.15.0", 43 | "@vitejs/plugin-vue": "^3.1.2", 44 | "@vitejs/plugin-vue-jsx": "^2.0.1", 45 | "@vue/babel-plugin-jsx": "^1.1.1", 46 | "cross-env": "^7.0.3", 47 | "husky": "^8.0.1", 48 | "less": "^4.1.3", 49 | "lint-staged": "^13.0.3", 50 | "mockjs": "^1.1.0", 51 | "prettier": "^2.7.1", 52 | "rollup": "^2.79.1", 53 | "rollup-plugin-visualizer": "^5.8.2", 54 | "stylelint": "^14.13.0", 55 | "stylelint-config-prettier": "^9.0.3", 56 | "stylelint-config-rational-order": "^0.1.2", 57 | "stylelint-config-standard": "^28.0.0", 58 | "stylelint-order": "^5.0.0", 59 | "typescript": "^4.8.4", 60 | "unplugin-vue-components": "^0.22.8", 61 | "vite": "^3.1.7", 62 | "vite-plugin-compression": "^0.5.1", 63 | "vite-plugin-imagemin": "^0.6.1", 64 | "vite-plugin-style-import": "1.4.1", 65 | "vite-svg-loader": "^3.6.0", 66 | "vue-tsc": "^1.0.3" 67 | }, 68 | "engines": { 69 | "node": ">=14.0.0" 70 | }, 71 | "resolutions": { 72 | "bin-wrapper": "npm:bin-wrapper-china", 73 | "rollup": "^2.56.3", 74 | "gifsicle": "5.2.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/views/internet_of_things/packageList/packageBuyImport.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 73 | 74 | 87 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/career/Settlement.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 73 | -------------------------------------------------------------------------------- /src/views/user/setting/components/certification-records.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 72 | 73 | 82 | -------------------------------------------------------------------------------- /src/views/pay/serviceProvider/components/government/Settlement.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 73 | --------------------------------------------------------------------------------