创建项目

This commit is contained in:
浅念
2025-11-19 18:01:09 +08:00
commit 228a444ed0
371 changed files with 105839 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
# 【开发】环境变量
# 网站地址前缀
VITE_BASE_URL = /
# API 地址前缀
# VITE_API_URL = https://m1.apifoxmock.com/m1/6400575-6097373-default
# VITE_API_URL = https://bsh.yw.server.hnzhwlkj.cn
VITE_API_URL = http://219.157.255.213:25832
# VITE_API_URL = https://fdesk.hnxinyouhe.com
# VITE_API_URL = https://x-server.hnxinyouhe.com
# VITE_API_URL_WSS = wss://mzl.dev.hnxinyouhe.com
# VITE_API_URL_WSS = wss://fdesk.hnxinyouhe.com
# VITE_API_URL_WSS = wss://x-server.hnxinyouhe.com
# Delete console
VITE_DROP_CONSOLE = false
+13
View File
@@ -0,0 +1,13 @@
# 【生产】环境变量
# 网站地址前缀
VITE_BASE_URL = /
# API 地址前缀
# VITE_API_URL = https://fdesk.hnxinyouhe.com
# VITE_API_URL = https://mzl.dev.hnxinyouhe.com
VITE_API_URL = https://bsh.yw.server.hnzhwlkj.cn
# VITE_API_URL_WSS = wss://fdesk.hnxinyouhe.com
# VITE_API_URL_WSS = wss://x-server.hnxinyouhe.com
# Delete console
VITE_DROP_CONSOLE = true
+2
View File
@@ -0,0 +1,2 @@
*.html linguist-detectable=false
*.vue linguist-detectable=true
+11
View File
@@ -0,0 +1,11 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
*.env
.cursorrules
src/types/components.d.ts
src/types/auto-imports.d.ts
.vscode
.auto-import.json
+3
View File
@@ -0,0 +1,3 @@
/node_modules/*
/dist/*
/src/main.ts
+20
View File
@@ -0,0 +1,20 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"vueIndentScriptAndStyle": true,
"singleQuote": true,
"quoteProps": "as-needed",
"bracketSpacing": true,
"trailingComma": "none",
"bracketSameLine": false,
"jsxSingleQuote": false,
"arrowParens": "always",
"insertPragma": false,
"requirePragma": false,
"proseWrap": "never",
"htmlWhitespaceSensitivity": "strict",
"endOfLine": "auto",
"rangeStart": 0
}
+9
View File
@@ -0,0 +1,9 @@
dist
node_modules
public
.husky
.vscode
src/components/Layout/MenuLeft/index.vue
src/assets
stats.html
+62
View File
@@ -0,0 +1,62 @@
module.exports = {
// 继承推荐规范配置
extends: [
'stylelint-config-standard',
'stylelint-config-recommended-scss',
'stylelint-config-recommended-vue/scss',
'stylelint-config-html/vue',
'stylelint-config-recess-order'
],
// 指定不同文件对应的解析器
overrides: [
{
files: ['**/*.{vue,html}'],
customSyntax: 'postcss-html'
},
{
files: ['**/*.{css,scss}'],
customSyntax: 'postcss-scss'
}
],
// 自定义规则
rules: {
'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url")
'selector-class-pattern': null, // 选择器类名命名规则
'custom-property-pattern': null, // 自定义属性命名规则
'keyframes-name-pattern': null, // 动画帧节点样式命名规则
'no-descending-specificity': null, // 允许无降序特异性
'no-empty-source': null, // 允许空样式
// 允许 global 、export 、deep伪类
'selector-pseudo-class-no-unknown': [
true,
{
ignorePseudoClasses: ['global', 'export', 'deep']
}
],
// 允许未知属性
'property-no-unknown': [
true,
{
ignoreProperties: []
}
],
// 允许未知规则
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'apply',
'use',
'mixin',
'include',
'extend',
'each',
'if',
'else',
'for',
'while'
]
}
]
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 SuperManTT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+77
View File
@@ -0,0 +1,77 @@
# 菜单权限控制问题修复方案
## 问题描述
在后端控制模式下,当普通用户登录后再退出登录管理员时,管理员特有的菜单会出现404错误。
## 问题原因
1. **路由注册状态未正确重置**:`isRouteRegistered` 标志位在用户切换时没有正确重置
2. **动态路由清理不完整**:`resetRouterState` 函数只清理了带有 `meta.dynamic` 标记的路由
3. **工作台标签页验证时机问题**:`validateWorktabs` 在路由重新注册后执行,但可能没有正确清理无效的标签页
4. **用户信息变化检测缺失**:没有检测用户切换事件,导致路由状态没有及时更新
## 修复方案
### 1. 改进路由状态重置 (`src/router/guards/beforeEach.ts`)
- 修改 `resetRouterState` 函数,清理所有动态注册的路由(不仅仅是带有dynamic标记的)
- 添加工作台标签页的清理
- 使用菜单store的 `clearMenuList` 方法
### 2. 添加用户切换检测 (`src/router/guards/beforeEach.ts`)
- 在 `handleRouteGuard` 函数中添加用户信息变化检测
- 使用 `sessionStorage` 缓存用户信息,检测用户切换
- 当检测到用户信息变化时,强制重置路由状态
### 3. 改进菜单API (`src/api/menuApi.ts`)
- 添加用户登录状态验证
- 改进菜单数据验证逻辑
- 添加更详细的错误处理和日志
### 4. 完善用户登出逻辑 (`src/store/modules/user.ts`)
- 在 `logOut` 方法中添加更完整的状态清理
- 清理用户信息缓存
- 确保工作台标签页被正确清理
### 5. 增强菜单Store (`src/store/modules/menu.ts`)
- 添加 `clearMenuList` 方法用于清理菜单数据
- 提供更完整的状态管理
### 6. 改进错误处理 (`src/router/guards/beforeEach.ts`)
- 修改 `handleMenuError` 函数,确保在菜单处理失败时正确清理所有状态
- 添加更详细的状态清理逻辑
## 测试工具
创建了 `src/utils/menuPermissionTest.ts` 测试工具,包含:
- `testMenuPermissionSwitch()`: 测试菜单权限切换的正确性
- `simulateUserSwitch()`: 模拟用户切换过程
## 使用方法
1. 在浏览器控制台中调用 `testMenuPermissionSwitch()` 检查当前状态
2. 在用户切换后调用 `simulateUserSwitch()` 模拟切换过程
3. 观察控制台输出,确认路由和菜单状态正确
## 预期效果
修复后,当用户切换时:
1. 所有动态路由会被正确清理
2. 菜单数据会被重新加载
3. 工作台标签页会被验证和清理
4. 不会出现404错误
5. 用户权限会正确应用
## 注意事项
- 确保后端返回的菜单数据与用户权限匹配
- 在开发环境中可以使用测试工具验证修复效果
- 建议在生产环境中添加更多的日志记录用于问题排查
+79
View File
@@ -0,0 +1,79 @@
English | [简体中文](./README.zh-CN.md)
## About Art Design Pro
As a developer, I needed to build admin management systems for multiple projects but found that traditional systems couldn't fully meet the requirements for user experience and visual design. Therefore, I created Art Design Pro, an open-source admin management solution focused on user experience and rapid development. Based on the ElementPlus design specifications, it has been visually optimized to provide a more beautiful and practical front-end interface, helping you easily build high-quality admin systems.
## Demo Images
### Light Theme
![Light Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover1.png)
![Light Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover2.png)
### Dark Theme
![Dark Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover3.png)
![Dark Theme](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover4.png)
## Features
- Uses the latest technology stack
- Built-in common business component templates
- Provides multiple theme modes and customizable themes
- Beautiful UI design, excellent user experience, and attention to detail
- System fully supports customization, meeting your personalized needs
## Functionality
- Rich theme switching
- Global search
- Lock screen
- Multi-tabs
- Global breadcrumbs
- Multi-language support
- Icon library
- Rich text editor
- Echarts charts
- Utils toolkit
- Network exception handling
- Route-level authentication
- Sidebar menu authentication
- Authentication directives
- Mobile adaptation
- Excellent persistent storage solution
- Local data storage validation
- Code commit validation and formatting
- Code commit standardization
## Compatibility
- Supports modern mainstream browsers such as Chrome, Safari, Firefox, etc.
## Installation and Running
```bash
# Install dependencies
pnpm install
# If pnpm install fails, try using the following command to install dependencies
pnpm install --ignore-scripts
# Start local development environment
pnpm dev
# Build for production
pnpm build
```
## Technical Support
QQ Group: <a href="https://qm.qq.com/cgi-bin/qm/qr?k=Gg6yzZLFaNgmRhK0T5Qcjf7-XcAFWWXm&jump_from=webapi&authKey=YpRKVJQyFKYbGTiKw0GJ/YQXnNF+GdXNZC5beQQqnGZTvuLlXoMO7nw5fNXvmVhA">821834289</a> (Click the link to join the group chat)
## Donation
If my project has been helpful to you, donations are welcome! Your support will be used to purchase tools like ChatGPT, Cursor, etc., to improve development efficiency and make the project even better. Thank you for your encouragement and support!
![Donation QR Code](https://www.qiniu.lingchen.kim/%E7%BB%84%202%402x%202.png)
+84
View File
@@ -0,0 +1,84 @@
简体中文 | [English](./README.md)
## 关于 Art Design Pro
作为一名开发者,我在多个项目中需要搭建后台管理系统,但发现传统系统在用户体验和视觉设计上不能完全满足需求。因此,我创建了 Art Design Pro,一款专注于用户体验和快速开发的开源后台管理解决方案。基于 ElementPlus 设计规范,进行了视觉上的精心优化,提供更美观、更实用的前端界面,帮助你轻松构建高质量的后台系统。
## 演示图
### 浅色主题
![浅色主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover1.png)
![浅色主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover2.png)
### 暗黑主题
![暗黑主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover3.png)
![暗黑主题](https://www.qiniu.lingchen.kim/art_design_pro_readme_cover4.png)
## 特点
- 使用最新技术栈
- 内置常用业务组件模版
- 提供多种主题模式,可以自定义主题
- 漂亮的 UI设计、极致的用户体验和细节处理
- 系统全面支持自定义设置,满足您的个性化需求
## 技术栈
- 开发框架:Vue3、TypeScript、Vite、Element-Plus
- 代码规范:Eslint、Prettier、Stylelint、Husky、Lint-staged、cz-git
## 功能
- 丰富主题切换
- 全局搜索
- 锁屏
- 多标签页
- 全局面包屑
- 多语言
- 图标库
- 富文本编辑器
- Echarts 图表
- Utils工具包
- 网络异常处理
- 路由级别鉴权
- 侧边栏菜单鉴权
- 鉴权指令
- 移动端适配
- 优秀的持久化存储方案
- 本地数据存储校验
- 代码提交校验与格式化
- 代码提交规范化
## 兼容性
- 支持 Chrome、Safari、Firefox 等现代主流浏览器。
## 安装运行
```bash
# 安装依赖
pnpm install
# 如果 pnpm install 安装失败,尝试使用下面的命令安装依赖
pnpm install --ignore-scripts
# 本地开发环境启动
pnpm dev
# 生产环境打包
pnpm build
```
## 技术支持
QQ群:<a href="https://qm.qq.com/cgi-bin/qm/qr?k=Gg6yzZLFaNgmRhK0T5Qcjf7-XcAFWWXm&jump_from=webapi&authKey=YpRKVJQyFKYbGTiKw0GJ/YQXnNF+GdXNZC5beQQqnGZTvuLlXoMO7nw5fNXvmVhA">821834289</a>(点击链接加入群聊)
## 捐赠
如果我的项目对你有所帮助,欢迎捐赠支持!你的支持将用于购买 ChatGPT、Cursor 等工具,以提升开发效率,让项目变得更好。感谢你的鼓励与支持!
![捐赠二维码](https://www.qiniu.lingchen.kim/%E7%BB%84%202%402x%202.png)
+97
View File
@@ -0,0 +1,97 @@
/**
* commitlint 配置文件
* 文档
* https://commitlint.js.org/#/reference-rules
* https://cz-git.qbb.sh/zh/guide/
*/
module.exports = {
// 继承的规则
extends: ['@commitlint/config-conventional'],
// 自定义规则
rules: {
// 提交类型枚举,git提交type必须是以下类型
'type-enum': [
2,
'always',
[
'feat', // 新增功能
'fix', // 修复缺陷
'docs', // 文档变更
'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
'refactor', // 代码重构(不包括 bug 修复、功能新增)
'perf', // 性能优化
'test', // 添加疏漏测试或已有测试改动
'build', // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
'ci', // 修改 CI 配置、脚本
'revert', // 回滚 commit
'chore', // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
'wip' // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
]
],
'subject-case': [0] // subject大小写不做校验
},
prompt: {
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围(可选):',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
footerPrefixesSelect: '选择关联issue前缀(可选):',
customFooterPrefix: '输入自定义issue前缀 :',
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
generatingByAI: '正在通过 AI 生成你的提交简短描述...',
generatedSelectByAI: '选择一个 AI 生成的简短描述:',
confirmCommit: '是否提交或修改commit ?'
},
// prettier-ignore
types: [
{ value: "feat", name: "特性: 新增功能" },
{ value: "fix", name: "修复: 修复缺陷" },
{ value: "docs", name: "文档: 文档变更(更新README文件,或者注释)" },
{ value: "style", name: "格式: 代码格式(空格、格式化、缺失的分号等)" },
{ value: "refactor", name: "重构: 代码重构(不修复错误也不添加特性的代码更改)" },
{ value: "perf", name: "性能: 性能优化" },
{ value: "test", name: "测试: 添加疏漏测试或已有测试改动" },
{ value: "build", name: "构建: 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)" },
{ value: "ci", name: "集成: 修改 CI 配置、脚本" },
{ value: "revert", name: "回退: 回滚 commit" },
{ value: "chore", name: "其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)" },
],
useEmoji: true,
emojiAlign: 'center',
useAI: false,
aiNumber: 1,
themeColorCode: '',
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: 'bottom',
customScopesAlias: 'custom',
emptyScopesAlias: 'empty',
upperCaseSubject: false,
markBreakingChangeMode: false,
allowBreakingChanges: ['feat', 'fix'],
breaklineNumber: 100,
breaklineChar: '|',
skipQuestions: ['breaking', 'footerPrefix', 'footer'], // 跳过的步骤
issuePrefixes: [{ value: 'closed', name: 'closed: ISSUES has been processed' }],
customIssuePrefixAlign: 'top',
emptyIssuePrefixAlias: 'skip',
customIssuePrefixAlias: 'custom',
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: '',
defaultIssues: '',
defaultScope: '',
defaultSubject: ''
}
}
+70
View File
@@ -0,0 +1,70 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ArtBackToTop: typeof import('./src/components/core/base/ArtBackToTop.vue')['default']
ArtBarChart: typeof import('./src/components/core/charts/ArtBarChart.vue')['default']
ArtBarChartCard: typeof import('./src/components/core/cards/ArtBarChartCard.vue')['default']
ArtBasicBanner: typeof import('./src/components/core/banners/ArtBasicBanner.vue')['default']
ArtBreadcrumb: typeof import('./src/components/core/layouts/art-breadcrumb/index.vue')['default']
ArtButtonMore: typeof import('./src/components/core/forms/ArtButtonMore.vue')['default']
ArtButtonTable: typeof import('./src/components/core/forms/ArtButtonTable.vue')['default']
ArtCardBanner: typeof import('./src/components/core/banners/ArtCardBanner.vue')['default']
ArtChatWindow: typeof import('./src/components/core/layouts/art-chat-window/index.vue')['default']
ArtCutterImg: typeof import('./src/components/core/media/ArtCutterImg.vue')['default']
ArtDataListCard: typeof import('./src/components/core/cards/ArtDataListCard.vue')['default']
ArtDonutChartCard: typeof import('./src/components/core/cards/ArtDonutChartCard.vue')['default']
ArtDragVerify: typeof import('./src/components/core/forms/ArtDragVerify.vue')['default']
ArtDualBarCompareChart: typeof import('./src/components/core/charts/ArtDualBarCompareChart.vue')['default']
ArtExcelExport: typeof import('./src/components/core/forms/ArtExcelExport.vue')['default']
ArtExcelImport: typeof import('./src/components/core/forms/ArtExcelImport.vue')['default']
ArtException: typeof import('./src/components/core/views/exception/ArtException.vue')['default']
ArtFastEnter: typeof import('./src/components/core/layouts/art-fast-enter/index.vue')['default']
ArtFestivalTextScroll: typeof import('./src/components/core/text-effect/ArtFestivalTextScroll.vue')['default']
ArtFireworksEffect: typeof import('./src/components/core/layouts/art-fireworks-effect/index.vue')['default']
ArtFormInput: typeof import('./src/components/core/forms/ArtFormInput.vue')['default']
ArtFormSelect: typeof import('./src/components/core/forms/ArtFormSelect.vue')['default']
ArtGlobalSearch: typeof import('./src/components/core/layouts/art-global-search/index.vue')['default']
ArtHBarChart: typeof import('./src/components/core/charts/ArtHBarChart.vue')['default']
ArtHeaderBar: typeof import('./src/components/core/layouts/art-header-bar/index.vue')['default']
ArtHorizontalMenu: typeof import('./src/components/core/layouts/art-menus/art-horizontal-menu/index.vue')['default']
ArtIconSelector: typeof import('./src/components/core/base/ArtIconSelector.vue')['default']
ArtImageCard: typeof import('./src/components/core/cards/ArtImageCard.vue')['default']
ArtKLineChart: typeof import('./src/components/core/charts/ArtKLineChart.vue')['default']
ArtLineChart: typeof import('./src/components/core/charts/ArtLineChart.vue')['default']
ArtLineChartCard: typeof import('./src/components/core/cards/ArtLineChartCard.vue')['default']
ArtMapChart: typeof import('./src/components/core/charts/ArtMapChart.vue')['default']
ArtMenuRight: typeof import('./src/components/core/others/ArtMenuRight.vue')['default']
ArtMixedMenu: typeof import('./src/components/core/layouts/art-menus/art-mixed-menu/index.vue')['default']
ArtNetwork: typeof import('./src/components/core/base/ArtNetwork.vue')['default']
ArtNotification: typeof import('./src/components/core/layouts/art-notification/index.vue')['default']
ArtPageContent: typeof import('./src/components/core/layouts/art-page-content/index.vue')['default']
ArtProgressCard: typeof import('./src/components/core/cards/ArtProgressCard.vue')['default']
ArtRadarChart: typeof import('./src/components/core/charts/ArtRadarChart.vue')['default']
ArtRingChart: typeof import('./src/components/core/charts/ArtRingChart.vue')['default']
ArtScatterChart: typeof import('./src/components/core/charts/ArtScatterChart.vue')['default']
ArtScreenLock: typeof import('./src/components/core/layouts/art-screen-lock/index.vue')['default']
ArtSettingsPanel: typeof import('./src/components/core/layouts/art-settings-panel/index.vue')['default']
ArtSidebarMenu: typeof import('./src/components/core/layouts/art-menus/art-sidebar-menu/index.vue')['default']
ArtStatsCard: typeof import('./src/components/core/cards/ArtStatsCard.vue')['default']
ArtTable: typeof import('./src/components/core/tables/ArtTable.vue')['default']
ArtTableBar: typeof import('./src/components/core/tables/ArtTableBar.vue')['default']
ArtTextScroll: typeof import('./src/components/core/text-effect/ArtTextScroll.vue')['default']
ArtTimelineListCard: typeof import('./src/components/core/cards/ArtTimelineListCard.vue')['default']
ArtVideoPlayer: typeof import('./src/components/core/media/ArtVideoPlayer.vue')['default']
ArtWangEditor: typeof import('./src/components/core/forms/ArtWangEditor.vue')['default']
ArtWatermark: typeof import('./src/components/core/others/ArtWatermark.vue')['default']
ArtWorkTab: typeof import('./src/components/core/layouts/art-work-tab/index.vue')['default']
BannerWidget: typeof import('./src/components/core/BannerWidget.vue')['default']
HorizontalSubmenu: typeof import('./src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue')['default']
LoginLeftView: typeof import('./src/components/core/views/login/LoginLeftView.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SidebarSubmenu: typeof import('./src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue')['default']
}
}
+81
View File
@@ -0,0 +1,81 @@
// 从 URL 和路径模块中导入必要的功能
import fs from 'fs'
import path, { dirname } from 'path'
import { fileURLToPath } from 'url'
// 从 ESLint 插件中导入推荐配置
import pluginJs from '@eslint/js'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import pluginVue from 'eslint-plugin-vue'
import globals from 'globals'
import tseslint from 'typescript-eslint'
// 使用 import.meta.url 获取当前模块的路径
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
// 读取 .auto-import.json 文件的内容,并将其解析为 JSON 对象
const autoImportConfig = JSON.parse(
fs.readFileSync(path.resolve(__dirname, '.auto-import.json'), 'utf-8')
)
export default [
// 指定文件匹配规则
{
files: ['**/*.{js,mjs,cjs,ts,vue}']
},
// 指定全局变量和环境
{
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
},
// 扩展配置
pluginJs.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs['flat/essential'],
// 自定义规则
{
// 针对所有 JavaScript、TypeScript 和 Vue 文件应用以下配置
files: ['**/*.{js,mjs,cjs,ts,vue}'],
languageOptions: {
globals: {
// 合并从 autoImportConfig 中读取的全局变量配置
...autoImportConfig.globals
}
},
rules: {
quotes: ['error', 'single'], // 使用单引号
semi: ['error', 'never'], // 语句末尾不加分号
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'@typescript-eslint/no-explicit-any': 'off', // 禁用 any 检查
'vue/multi-word-component-names': 'off', // 禁用对 Vue 组件名称的多词要求检查
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-unexpected-multiline': 'error' // 禁止空余的多行
}
},
// vue 规则
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: { parser: tseslint.parser }
}
},
// 忽略文件
{
ignores: [
'node_modules',
'dist',
'public',
'.vscode/**',
'src/assets/**',
'src/utils/console.ts'
]
},
// prettier 配置
eslintPluginPrettierRecommended
]
+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<title>系统管理</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<link rel="shortcut icon" type="image/x-icon" href="src/assets/img/favicon.ico" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script src="https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js"></script>
</body>
</html>
+205
View File
@@ -0,0 +1,205 @@
{
root: '/Users/tt/Downloads/art-design-pro',
registry: 'https://registry.npmmirror.com',
pkgs: [
{
name: '',
version: '/Users/tt/Downloads/art-design-pro/@types/vite/client',
type: 'directory',
alias: undefined,
arg: [Result]
}
],
production: false,
cacheStrict: false,
cacheDir: '/Users/tt/.npminstall_tarball',
env: {
npm_config_registry: 'https://registry.npmmirror.com',
npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=/Users/tt/.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","--save-dev","@types/vite/client"],"original":["--fix-bug-versions","--china","--userconfig=/Users/tt/.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npmmirror.com","--save-dev","@types/vite/client"]}',
npm_config_user_agent: 'npminstall/7.12.0 npm/? node/v18.20.4 darwin x64',
npm_config_cache: '/Users/tt/.npminstall_tarball',
NODE: '/Users/tt/.nvm/versions/node/v18.20.4/bin/node',
npm_node_execpath: '/Users/tt/.nvm/versions/node/v18.20.4/bin/node',
npm_execpath: '/usr/local/lib/node_modules/cnpm/node_modules/npminstall/bin/install.js',
npm_config_userconfig: '/Users/tt/.cnpmrc',
npm_config_disturl: 'https://cdn.npmmirror.com/binaries/node',
npm_config_r: 'https://registry.npmmirror.com',
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver',
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
RE2_DOWNLOAD_SKIP_PATH: 'true',
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs',
npm_rootpath: '/Users/tt/Downloads/art-design-pro',
INIT_CWD: '/Users/tt/Downloads/art-design-pro'
},
binaryMirrors: {
ENVS: {
COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com',
EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver',
NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node',
PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs',
CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver',
OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver',
CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip',
ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/',
ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/',
SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass',
SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc',
NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v',
PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing',
PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright',
SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli',
SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl',
RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2',
RE2_DOWNLOAD_SKIP_PATH: 'true',
PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma',
npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3',
npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar',
npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp',
npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips',
npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs'
},
'@ali/s2': { host: 'https://cdn.npmmirror.com/binaries/looksgood-s2' },
sharp: { replaceHostFiles: [Array], replaceHostMap: [Object] },
'@tensorflow/tfjs-node': {
replaceHostFiles: [Array],
replaceHostRegExpMap: [Object],
replaceHostMap: [Object]
},
cypress: {
host: 'https://cdn.npmmirror.com/binaries/cypress',
newPlatforms: [Object]
},
'utf-8-validate': {
host: 'https://cdn.npmmirror.com/binaries/utf-8-validate/v{version}'
},
xprofiler: {
remote_path: './xprofiler/v{version}/',
host: 'https://cdn.npmmirror.com/binaries'
},
leveldown: { host: 'https://cdn.npmmirror.com/binaries/leveldown/v{version}' },
couchbase: { host: 'https://cdn.npmmirror.com/binaries/couchbase/v{version}' },
gl: { host: 'https://cdn.npmmirror.com/binaries/gl/v{version}' },
sqlite3: {
host: 'https://cdn.npmmirror.com/binaries/sqlite3',
remote_path: 'v{version}'
},
'@journeyapps/sqlcipher': { host: 'https://cdn.npmmirror.com/binaries' },
grpc: {
host: 'https://cdn.npmmirror.com/binaries',
remote_path: '{name}/v{version}'
},
'grpc-tools': { host: 'https://cdn.npmmirror.com/binaries' },
wrtc: {
host: 'https://cdn.npmmirror.com/binaries',
remote_path: '{name}/v{version}'
},
fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' },
nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' },
canvas: { host: 'https://cdn.npmmirror.com/binaries/canvas' },
'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' },
'flow-bin': {
replaceHost: 'https://github.com/facebook/flow/releases/download/v',
host: 'https://cdn.npmmirror.com/binaries/flow/v'
},
'jpegtran-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpegtran-bin'
},
'cwebp-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/cwebp-bin'
},
'zopflipng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/zopflipng-bin'
},
'optipng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/optipng-bin'
},
mozjpeg: {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/mozjpeg-bin'
},
gifsicle: {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/gifsicle-bin'
},
'pngquant-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngquant-bin',
replaceHostMap: [Object]
},
'pngcrush-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngcrush-bin'
},
'jpeg-recompress-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpeg-recompress-bin'
},
'advpng-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/advpng-bin'
},
'pngout-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/pngout-bin'
},
'jpegoptim-bin': {
replaceHost: [Array],
host: 'https://cdn.npmmirror.com/binaries/jpegoptim-bin'
},
argon2: { host: 'https://cdn.npmmirror.com/binaries/argon2' },
'ali-zeromq': { host: 'https://cdn.npmmirror.com/binaries/ali-zeromq' },
'ali-usb_ctl': { host: 'https://cdn.npmmirror.com/binaries/ali-usb_ctl' },
'gdal-async': { host: 'https://cdn.npmmirror.com/binaries/node-gdal-async' },
'libpg-query': { host: 'https://cdn.npmmirror.com/binaries' }
},
forbiddenLicenses: null,
flatten: false,
proxy: undefined,
prune: false,
disableFallbackStore: false,
workspacesMap: Map(0) {},
enableWorkspace: false,
workspaceRoot: '/Users/tt/Downloads/art-design-pro',
isWorkspaceRoot: true,
isWorkspacePackage: false,
offline: false,
strictSSL: true,
ignoreScripts: false,
foregroundScripts: false,
ignoreOptionalDependencies: false,
detail: false,
forceLinkLatest: false,
trace: false,
engineStrict: false,
registryOnly: false,
client: false,
autoFixVersion: [Function: autoFixVersion]
}
+16227
View File
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
{
"name": "art-design-pro",
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --open",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview",
"lint": "eslint",
"fix": "eslint --fix",
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix",
"lint:lint-staged": "lint-staged",
"prepare": "husky",
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix --quiet",
"prettier --write"
],
"*.{js,ts,mjs,mts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{cjs,json,jsonc}": [
"prettier --write"
],
"*.vue": [
"eslint --fix",
"stylelint --fix --allow-empty-input",
"prettier --write"
],
"*.{html,htm}": [
"prettier --write"
],
"*.{scss,css,less}": [
"stylelint --fix --allow-empty-input",
"prettier --write"
],
"*.{md,mdx}": [
"prettier --write"
],
"*.{yaml,yml}": [
"prettier --write"
]
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@types/echarts": "^4.9.22",
"@vue/reactivity": "^3.4.35",
"@vueuse/core": "^11.0.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "next",
"axios": "^1.7.5",
"crypto-js": "^4.2.0",
"echarts": "^5.4.0",
"echarts-gl": "^2.0.9",
"element-plus": "^2.8.0",
"file-saver": "^2.0.5",
"highlight.js": "^11.10.0",
"md-editor-v3": "^4.17.0",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.2",
"pinia-plugin-persistedstate": "^4.3.0",
"qrcode.vue": "^3.6.0",
"vue": "^3.5.12",
"vue-draggable-plus": "^0.6.0",
"vue-i18n": "^9.14.0",
"vue-router": "^4.4.2",
"vue3-count-to": "^1.1.2",
"xgplayer": "^3.0.20",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^19.4.1",
"@commitlint/config-conventional": "^19.4.1",
"@eslint/js": "^9.9.1",
"@types/node": "^22.1.0",
"@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/compiler-sfc": "^3.0.5",
"commitizen": "^4.3.0",
"cz-git": "^1.11.1",
"eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.27.0",
"globals": "^15.9.0",
"husky": "^9.1.5",
"lint-staged": "^15.5.2",
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.81.0",
"stylelint": "^16.20.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^4.6.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^36.0.1",
"terser": "^5.36.0",
"typescript": "~5.6.3",
"typescript-eslint": "^8.9.0",
"unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4",
"vite": "^6.1.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-vue-devtools": "^7.7.6",
"vue-demi": "^0.14.9",
"vue-img-cutter": "^3.0.5",
"vue-tsc": "~2.1.6"
}
}
+13801
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+248
View File
@@ -0,0 +1,248 @@
<template>
<ElConfigProvider size="default" :locale="locales[language]" :z-index="3000">
<RouterView></RouterView>
</ElConfigProvider>
</template>
<script setup lang="ts">
import { useUserStore } from './store/modules/user'
import zh from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import { systemUpgrade } from './utils/sys'
import { UserService } from './api/usersApi'
import { setThemeTransitionClass } from './utils/theme/animation'
import { checkStorageCompatibility } from './utils/storage'
import { mittBus } from '@/utils/sys'
import appLogo from '@/assets/img/common/logox.png'
const router = useRouter()
const userStore = useUserStore()
const { language, accessToken } = storeToRefs(userStore)
function setCompanyFromUrl() {
const userStore = useUserStore()
const params = new URLSearchParams(window.location.search)
const companyid = params.get('corp_id')
const companyabbr = params.get('corp_abbr')
// const systemid = params.get('system_id')
// const system_code = params.get('system_code')
if (companyid) {
userStore.setCompany(companyid, companyabbr || '')
// userStore.setSystems(systemid || '', system_code || '')
// 你也可以加 localStorage/sessionStorage 备份
}
}
const locales = {
zh: zh,
en: en
}
const isSupported = ref(false)
const permissionStatus = ref('default')
// 检查浏览器支持情况
const checkSupport = () => {
if ('Notification' in window) {
isSupported.value = true
console.log('浏览器支持原生Notification API')
} else {
isSupported.value = false
console.log('⚠️ 浏览器不支持原生Notification API')
}
}
// 请求通知权限
const requestPermission = async () => {
if (!('Notification' in window)) {
console.log('浏览器不支持原生Notification API')
return
}
try {
const permission = await Notification.requestPermission()
permissionStatus.value = permission
if (permission === 'granted') {
console.log('用户已授予通知权限')
} else if (permission === 'denied') {
console.log('用户拒绝了通知权限')
} else {
console.log('用户暂时未授予通知权限')
}
} catch (error) {
console.log(`请求权限时出错:`)
}
}
// 显示基本通知(支持自定义标题与内容)
const showBasicNotification = (
title: string = '基本通知',
body: string = '这是一个使用浏览器原生API的系统通知'
) => {
if (!('Notification' in window)) {
ElMessage({
message: '浏览器不支持原生Notification API',
type: 'warning'
})
return
}
if (Notification.permission !== 'granted') {
ElMessage({
message: '请先授予通知权限',
type: 'warning'
})
requestPermission()
return
}
try {
const iconUrl = appLogo || '/favicon.ico'
const notification = new Notification(title, {
body,
requireInteraction: true,
icon: iconUrl
})
notification.onclick = () => {
notification.close()
}
} catch (error) {}
}
onBeforeMount(() => {
setThemeTransitionClass(true)
setCompanyFromUrl()
})
// 页面刷新时重置WebSocket重连次数,同时清理事件监听
onBeforeUnmount(() => {
import('@/utils/sys/wsClient').then(({ resetWebSocketReconnect }) => {
resetWebSocketReconnect()
})
mittBus.off('ws:message')
})
const handleWsMessageNotification = (data: any) => {
if (data && data.event === 'notify.receive') {
const notice = data?.data?.notice_data
const title = notice?.message?.title || '新通知'
const rawContent = notice?.message?.content || ''
const body = typeof rawContent === 'string' ? rawContent.replace(/<[^>]+>/g, '') : ''
showBasicNotification(title, body)
}
}
onMounted(() => {
// 检查存储兼容性
checkStorageCompatibility()
checkSupport()
requestPermission()
// 提升暗黑主题下页面刷新视觉体验
setThemeTransitionClass(false)
// 系统升级
systemUpgrade()
// 获取用户信息
getUserInfo()
// 初始化 WebSocket
// showEventNotification()
// if (accessToken.value) {
// import('@/utils/sys/wsClient').then(
// ({ initWebSocket, resetWebSocketReconnect, getWebSocketStatus }) => {
// // 页面刷新时重置重连次数
// resetWebSocketReconnect()
// initWebSocket(accessToken.value)
// // 添加调试功能,可以在控制台查看WebSocket状态
// // @ts-ignore
// window.getWebSocketStatus = getWebSocketStatus
// // console.log('WebSocket状态查看: window.getWebSocketStatus()')
// }
// )
// }
// // 监听ws消息,用于系统级通知
// mittBus.on('ws:message', handleWsMessageNotification)
})
// 登录后,accessToken 变更时立即初始化 WebSocket(无需刷新)
// watch(accessToken, async (token) => {
// if (token) {
// const { initWebSocket, getWebSocketStatus } = await import('@/utils/sys/wsClient')
// const status = getWebSocketStatus?.()
// // 避免重复初始化:已连接或正在连接时不再初始化
// if (
// !status?.readyState ||
// (status.readyState !== WebSocket.OPEN && status.readyState !== WebSocket.CONNECTING)
// ) {
// initWebSocket(token)
// }
// } else {
// // 退出登录时,关闭并重置
// const { closeWebSocket, resetWebSocketReconnect } = await import('@/utils/sys/wsClient')
// closeWebSocket()
// resetWebSocketReconnect()
// }
// })
// 获取用户信息
const getUserInfo = async () => {
if (userStore.isLogin) {
try {
const data = await UserService.getUserInfo()
userStore.setUserInfo(data)
} catch (error) {
console.error('获取用户信息失败', error)
}
}
}
</script>
<style>
.boxshadow {
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 10, 118, 0.1);
background: var(--art-main-bg-color);
padding: 10px 20px;
margin-bottom: 10px;
}
.border {
width: 6px;
height: 22px;
border-radius: 3px;
background: #3471FF;
display: inline-block;
vertical-align: bottom;
}
.el-dialog {
position: relative;
overflow: hidden;
}
.el-dialog::before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(180deg, #E4ECFF 0%, #FFFFFF 50%);
pointer-events: none;
}
.el-dialog__header,
.el-dialog__body,
.el-dialog__footer {
background: transparent !important;
position: relative;
z-index: 1;
}
.el-dialog__header {
display: flex;
align-items: center;
justify-content: center;
position: relative;
padding-right: 40px;
}
.el-dialog__title {
flex: 1;
text-align: center;
font-size: 18px;
font-weight: bold;
}
.el-dialog__headerbtn {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
}
.item-row-wrap {
margin-bottom: 12px;
}
</style>
+337
View File
@@ -0,0 +1,337 @@
import request from '@/utils/http'
export class manageService {
//仪表盘 总
static statisticswhole() {
return request.get<any>({
// url: '/admin/inquiry/statistics/whole'
url: 'admin/crm/statistics/whole'
})
}
//各渠道统计
static channelcount() {
return request.get<any>({
// url: '/admin/inquiry/statistics/channel/count'
url: '/admin/crm/statistics/channel/count'
})
}
//各国家统计
static countrycount() {
return request.get<any>({
// url: '/admin/inquiry/statistics/country/count'
url: '/admin/crm/statistics/country/count'
})
}
//跟单人统计
static trackcount() {
return request.get<any>({
// url: '/admin/inquiry/statistics/track/count'
url: '/admin/crm/statistics/track/count'
})
}
//每日录单统计
static daycount() {
return request.get<any>({
// url: '/admin/inquiry/statistics/day/count'
url: '/admin/crm/statistics/day/count'
})
}
//每日录单统计
static inquirycount(params: any) {
return request.get<any>({
// url: '/admin/inquiry/statistics/inquiry/count',
url: '/admin/crm/statistics/customer/count',
params
})
}
//询单列表
static getinquiryList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/inquiry/list',
params
})
}
// 获取详情
static inquirydetail(params: any) {
return request.get<any>({
url: '/admin/inquiry/show',
params
})
}
//添加询单
static inquiryAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/inquiry/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//修改询单
static inquiryedit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/inquiry/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//删除询单
static inquirydelete(params: any) {
return request.get<Api.Common.AddResponse>({
url: '/admin/inquiry/destroy',
params
})
}
//分配询单
static inquiryallocation(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/inquiry/allocation',
params
// showErrorMessage: false // 不显示错误消息
})
}
//重新分配询单
static inquiryreallocation(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/inquiry/reallocation',
params
// showErrorMessage: false // 不显示错误消息
})
}
//发布询单
static inquiryrelease(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/inquiry/release',
params
// showErrorMessage: false // 不显示错误消息
})
}
//获取用户下拉框
static presetusers() {
return request.get<any>({
url: '/common/preset/users'
})
}
//crm 客户管理
//客户列表
static getcrmCustomerList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListDatad>({
url: '/admin/crm/customer/list',
params
})
}
//客户导出
static crmCustomerExport(params: any) {
return request.get<any>({
url: '/admin/crm/customer/export',
params,
responseType: 'blob' // 设置响应类型为 blob
})
}
//客户审核
static crmCustomerAudit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/crm/customer/audit',
params
// showErrorMessage: false // 不显示错误消息
})
}
//客户转移
static crmCustomerTransfer(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/crm/customer/transfer',
params
// showErrorMessage: false // 不显示错误消息
})
}
//用户列表
static getUserList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/user/list',
params
})
}
//用户编辑
static userEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/user/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//用户新增
static userAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/user/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//用户设置角色
static userSetRole(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/user/authorize',
params
// showErrorMessage: false // 不显示错误消息
})
}
//用户菜单权限设置
static userMenuAuth(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/user/set/resources',
params
// showErrorMessage: false // 不显示错误消息
})
}
//清除缓存
static clearCache() {
return request.get<any>({
url: '/common/preset/cache/clear'
})
}
//公海客户分配
static crmCustomerAllocation(params: any) {
return request.get<Api.Common.AddResponse>({
url: '/admin/crm/customer/cede',
params
// showErrorMessage: false // 不显示错误消息
})
}
//公海客户跟进记录
static crmCustomerFollow(params: any) {
return request.get<any>({
url: '/admin/crm/customer/follow',
params: params
})
}
//公海客户删除
static crmCustomerDelete(params: any) {
return request.get<Api.Common.AddResponse>({
url: '/admin/crm/customer/delete',
params
// showErrorMessage: false // 不显示错误消息
})
}
//回收站 恢复
static customerRestore(params: any) {
return request.get<any>({
url: '/admin/crm/customer/restore',
params
})
}
//备货单审核列表
static getstocklist(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/approval/list',
params
})
}
//备货单审核
static stockapproval(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/approval/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
// 审核更新
static stockapprovalupdate(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/approval/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//审核详情
static stockapprovaldetail(params: any) {
return request.get<any>({
url: '/admin/approval/show',
params
})
}
//审核删除
static stockapprovaldelete(params: any) {
return request.get<Api.Common.AddResponse>({
url: '/admin/approval/destroy',
params
})
}
//审批记录
static stockapprovalrecord(params: any) {
return request.get<any>({
url: '/admin/approval/records/todo',
params
})
}
//审批通过/拒绝
static stockapprovalpass(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/approval/records/action',
params
})
}
//审批记录
static stockapprovallogs(params: any) {
return request.get<any>({
url: '/admin/approval/records/logs',
params
})
}
//备货单
static getStockList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/stock/order/list',
params
})
}
//添加备货单
static addStock(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/stock/order/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//详情备货单
static getStockDetail(params: any) {
return request.get<any>({
url: '/admin/stock/order/show',
params
})
}
//备货单查看
static checkStock(params: any) {
return request.get<any>({
url: '/admin/stock/order/detail',
params
})
}
//打印
static printStock(params: any) {
return request.get<any>({
url: '/admin/stock/order/print',
params
})
}
//审核详情
static stockapprovaldetailborder(params: any) {
return request.get<any>({
url: '/admin/approval/records/border',
params
})
}
//审批转交
static stockapprovaltransfer(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/approval/records/transfer',
params
})
}
//审批时间轴
static stockapprovaltimeline(params: any) {
return request.get<any>({
url: '/admin/approval/records/timeline',
params
})
}
}
+82
View File
@@ -0,0 +1,82 @@
import request from '@/utils/http'
export class classifyService {
//分类树列表 admin/nav/categories/tree
static getclassifytreeList(params: any) {
return request.get<any>({
url: '/admin/nav/categories/tree',
params
})
}
//分类列表
static getclassifyList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/nav/categories/list',
params
})
}
//分类添加
static addclassify(params: any) {
return request.post<any>({
url: '/admin/nav/categories/store',
params
})
}
//分类编辑
static editclassify(params: any) {
return request.post<any>({
url: '/admin/nav/categories/update',
params
})
}
//分类删除
static deleteclassify(params: any) {
return request.post<any>({
url: '/admin/nav/categories/destroy',
params
})
}
//分类详情
static classifydetail(params: any) {
return request.get<any>({
url: '/admin/nav/categories/show',
params
})
}
//分类内容列表
static getclassifycontentList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/nav/item/list',
params
})
}
//分类内容添加
static addclassifycontent(params: any) {
return request.post<any>({
url: '/admin/nav/item/store',
params
})
}
//分类内容编辑
static editclassifycontent(params: any) {
return request.post<any>({
url: '/admin/nav/item/update',
params
})
}
//分类内容删除
static deleteclassifycontent(params: any) {
return request.post<any>({
url: '/admin/nav/item/destroy',
params
})
}
//分类内容详情
static classifycontentdetail(params: any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/nav/item/show',
params
})
}
}
+82
View File
@@ -0,0 +1,82 @@
import request from '@/utils/http'
export class commonService {
//通知列表
static getNoticeList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/common/notice/list',
params
})
}
//通知详情
static getNoticeDetail(params: any) {
return request.get<Api.Common.CommonListData>({
url: '/common/notice/show',
params
})
}
//通知已读
static readNotice(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/common/notice/read',
params
})
}
//通知删除
static delNotice(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/common/notice/destroy',
params
})
}
//通知未读列表
static getUnReadNoticeList() {
return request.get<any>({
url: '/common/notice/unread'
})
}
//账户下拉框
static getAccountSelect() {
return request.get<any>({
url: '/common/preset/account'
})
}
//名下客户下拉框
static getCustomerSelect() {
return request.get<any>({
url: '/crm/customer/preset'
})
}
//角色下拉框
static getRoleSelect() {
return request.get<any>({
url: '/common/preset/roles'
})
}
//用户下拉框
static getUserSelect() {
return request.get<any>({
url: '/common/preset/users'
})
}
//分类下拉
static getClassifySelect() {
return request.get<any>({
url: '/common/nav/categories/preset'
})
}
//签名 编辑
static signatureEdit(params: any) {
return request.post<any>({
url: '/admin/user/update/sign',
params
})
}
//获取设置
static getSetting(params: any) {
return request.get<any>({
url: '/common/config/find',
params: params
})
}
}
+43
View File
@@ -0,0 +1,43 @@
import { menuDataToRouter } from '@/router/utils/menuToRouter'
import { AppRouteRecord } from '@/types/router'
import { useUserStore } from '@/store/modules/user'
import { UserService } from '@/api/usersApi'
interface MenuResponse {
menuList: AppRouteRecord[]
}
// 菜单接口
export const menuService = {
async getMenuList(delay = 300): Promise<MenuResponse> {
try {
const userStore = useUserStore()
// 验证用户登录状态
if (!userStore.isLogin) {
throw new Error('用户未登录')
}
const { menu } = await UserService.getMenuList()
const menuData = menu
// const userStore = useUserStore()
// 模拟接口返回的菜单数据
// 验证菜单数据
if (!menuData || !Array.isArray(menuData) || menuData.length === 0) {
ElMessage.error('暂无系统菜单权限')
return { menuList: [] }
}
// console.log('menuData', menuData)
// 处理菜单数据
const menuList = menuData.map((route: any) => menuDataToRouter(route))
// 验证处理后的菜单列表
if (!menuList || menuList.length === 0) {
ElMessage.error('菜单数据处理失败')
return { menuList: [] }
}
// 模拟接口延迟
await new Promise((resolve) => setTimeout(resolve, delay))
return { menuList }
} catch (error) {
console.error('获取菜单失败:', error)
throw error instanceof Error ? error : new Error('获取菜单失败')
}
}
}
+348
View File
@@ -0,0 +1,348 @@
import request from '@/utils/http'
export class systemService {
//系统列表
static getSystemList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/systems/list',
params
})
}
//系统添加
static systemAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/systems/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//系统详情
static systemDetail(params: any) {
return request.get<any>({
url: '/admin/systems/show',
params
})
}
//系统编辑
static systemEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/systems/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//系统删除
static systemDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/systems/destroy',
params
// showErrorMessage: false // 不显示错误消息
})
}
//飞书应用列表
static getFeishuAppList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/corp/feishu/list',
params
})
}
//飞书应用添加
static feishuAppAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/feishu/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//飞书应用详情
static feishuAppDetail(params: any) {
return request.get<any>({
url: '/admin/corp/feishu/show',
params
})
}
//飞书应用编辑
static feishuAppEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/feishu/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//飞书应用删除
static feishuAppDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/feishu/destroy',
params
// showErrorMessage: false // 不显示错误消息
})
}
//公司列表
static getCompanyList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/corp/list',
params
})
}
//公司添加
static companyAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//公司详情
static companyDetail(params: any) {
return request.get<any>({
url: '/admin/corp/show',
params
})
}
//公司编辑
static companyEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//公司删除
static companyDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/corp/destroy',
params
// showErrorMessage: false // 不显示错误消息
})
}
//角色列表
static getRoleList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/role/list',
params
})
}
//角色添加
static roleAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/role/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//角色详情
static roleDetail(params: any) {
return request.get<any>({
url: '/admin/role/show',
params
})
}
//角色编辑
static roleEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/role/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//角色删除
static roleDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/role/destroy',
params
// showErrorMessage: false // 不显示错误消息
})
}
//角色权限设置
static roleAuth(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/role/menu/resource',
params
// showErrorMessage: false // 不显示错误消息
})
}
//角色下拉框
static getRoleSelectList() {
return request.get<Api.Common.CommonListData>({
url: '/common/preset/roles'
})
}
//菜单列表
static getMenutreeList(params: any) {
return request.get<any>({
url: '/admin/resources/list/tree',
params
})
}
static getMenuList() {
return request.get<Api.Common.CommonListData>({
url: '/admin/resources/list/menu'
})
}
//菜单添加
static menuAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/resources/store',
params
// showErrorMessage: false // 不显示错误消息
})
}
//菜单详情
static menuDetail(params: any) {
return request.get<any>({
url: '/admin/resources/show',
params
})
}
//菜单编辑
static menuEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/resources/update',
params
// showErrorMessage: false // 不显示错误消息
})
}
//菜单删除
static menuDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/resources/destroy',
params
// showErrorMessage: false // 不显示错误消息
})
}
//权限菜单
static getPermissionMenuList(params: any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/resources/list/menu/tree',
params
})
}
//通知列表
static getNoticeList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/notice/list',
params
})
}
//通知详情
static getNoticeDetail(params: any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/notice/show',
params
})
}
//通知删除
static delNotice(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/notice/destroy',
params
})
}
//通知推送
static sendNotice(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/notice/push',
params
})
}
// 字典类型列表
static getDictTypeList(params: Api.Common.PaginatingParams & any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/dict/list',
params
})
}
// 字典类型新增/详情/编辑/删除
static dictTypeAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/store',
params
})
}
static dictTypeDetail(params: any) {
return request.get<any>({
url: '/admin/dict/show',
params
})
}
static dictTypeEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/update',
params
})
}
static dictTypeDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/destroy',
params
})
}
// 字典项列表
static getDictItemList(params: Api.Common.PaginatingParams & any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/dict/item/list',
params
})
}
// 字典项新增/详情/编辑/删除
static dictItemAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/item/store',
params
})
}
static dictItemDetail(params: any) {
return request.get<any>({
url: '/admin/dict/item/show',
params
})
}
static dictItemEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/item/update',
params
})
}
static dictItemDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/dict/item/destroy',
params
})
}
//系统设置
static getconfigList(params: Api.Common.PaginatingParams) {
return request.get<Api.Common.CommonListData>({
url: '/admin/config/list',
params
})
}
//系统设置添加
static configAdd(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/config/store',
params
})
}
//系统设置详情
static configDetail(params: any) {
return request.get<Api.Common.CommonListData>({
url: '/admin/config/show',
params
})
}
//系统设置删除
static configDelete(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/config/destroy',
params
})
}
//系统设置编辑
static configEdit(params: any) {
return request.post<Api.Common.AddResponse>({
url: '/admin/config/update',
params
})
}
}
+96
View File
@@ -0,0 +1,96 @@
import request from '@/utils/http'
export class UserService {
//获取公司
static getCompanyList() {
return request.get<Api.Brand.BrandInfo>({
url: '/common/preset/corps'
})
}
//获取系统
static getsystemsList() {
return request.get<Api.Brand.BrandInfo>({
url: '/common/preset/systems'
})
}
//注册
static register(params: any) {
return request.post<Api.Auth.registerResponse>({
url: '/common/auth/register',
params
// showErrorMessage: false // 不显示错误消息
})
}
//获取 飞书信息
static getfeishuAppList(params: any) {
return request.get<Api.Brand.BrandInfo>({
url: '/common/preset/feishu/app',
params
})
}
// 登录
static login(params: Api.Auth.LoginParams) {
return request.post<Api.Auth.LoginResponse>({
url: '/common/auth/login',
params
// showErrorMessage: false // 不显示错误消息
})
}
// 刷新token
static refreshToken(params: { refresh_token: string }) {
return request.post<any>({
url: '/common/auth/refresh/token',
params
})
}
//飞书凭证
static getfeishuscope() {
return request.get<Api.Auth.Authfeishuscope>({
url: '/common/auth/feishu/scope'
})
}
// 获取用户信息
static getUserInfo() {
return request.get<Api.User.UserInfo>({
url: '/common/user/info'
})
}
// 获取用户列表
static getUserList(params: Api.Common.PaginatingParams) {
return request.get<Api.User.UserListData>({
url: '/api/user/list',
params
})
}
//角色 列表
static getRoleList(params: Api.Common.PaginatingParams) {
return request.get<Api.Role.RoleListData>({
url: '/admin/role/list',
params
})
}
//获取菜单
static getMenuList() {
return request.get<Api.User.UserInfo>({
url: '/common/preset/menus'
})
}
//个人信息编辑
static editUserInfo(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/user/edit',
params
})
}
//修改密码 crm/user/savePassword
static savePassword(params: any) {
return request.post<Api.Work.AddResponse>({
url: '/admin/user/update/password',
params
// showErrorMessage: false // 不显示错误消息
})
}
}
Binary file not shown.
Binary file not shown.
+426
View File
@@ -0,0 +1,426 @@
{
"wordGeoCoordMap":{
"阿富汗": [67.709953, 33.93911],
"安哥拉": [17.873887, -11.202692],
"阿尔巴尼亚": [20.168331, 41.153332],
"阿拉伯联合酋长国": [53.847818, 23.424076],
"阿根廷": [-63.61667199999999, -38.416097],
"亚美尼亚": [45.038189, 40.069099],
"法属南半球和南极领地": [69.348557, -49.280366],
"澳大利亚": [133.775136, -25.274398],
"奥地利": [14.550072, 47.516231],
"阿塞拜疆": [47.576927, 40.143105],
"布隆迪": [29.918886, -3.373056],
"比利时": [4.469936, 50.503887],
"贝宁": [2.315834, 9.30769],
"布基纳法索": [-1.561593, 12.238333],
"孟加拉人民共和国": [90.356331, 23.684994],
"保加利亚": [25.48583, 42.733883],
"巴哈马": [-77.39627999999999, 25.03428],
"波斯尼亚和黑塞哥维那": [17.679076, 43.915886],
"白俄罗斯": [27.953389, 53.709807],
"伯利兹": [-88.49765, 17.189877],
"百慕大": [-64.7505, 32.3078],
"玻利维亚": [-63.58865299999999, -16.290154],
"巴西": [-51.92528, -14.235004],
"文莱": [114.727669, 4.535277],
"不丹": [90.433601, 27.514162],
"博茨瓦纳": [24.684866, -22.328474],
"中非共和国": [20.939444, 6.611110999999999],
"加拿大": [-106.346771, 56.130366],
"瑞士": [8.227511999999999, 46.818188],
"智利": [-71.542969, -35.675147],
"中华人民共和国": [104.195397, 35.86166],
"象牙海岸": [-5.547079999999999, 7.539988999999999],
"喀麦隆": [12.354722, 7.369721999999999],
"刚果民主共和国": [21.758664, -4.038333],
"刚果共和国": [15.827659, -0.228021],
"哥伦比亚": [-74.297333, 4.570868],
"哥斯达黎加共和国": [-83.753428, 9.748916999999999],
"古巴": [-77.781167, 21.521757],
"北塞浦路斯": [33.429859, 35.126413],
"塞浦路斯": [33.429859, 35.126413],
"捷克共和国": [15.472962, 49.81749199999999],
"德国": [10.451526, 51.165691],
"吉布提": [42.590275, 11.825138],
"丹麦": [9.501785, 56.26392],
"多明尼加共和国": [-70.162651, 18.735693],
"阿尔及利亚": [1.659626, 28.033886],
"厄瓜多尔": [-78.18340599999999, -1.831239],
"埃及": [30.802498, 26.820553],
"厄立特里亚": [39.782334, 15.179384],
"西班牙": [-3.74922, 40.46366700000001],
"爱沙尼亚": [25.013607, 58.595272],
"埃塞俄比亚": [40.489673, 9.145000000000001],
"芬兰": [25.748151, 61.92410999999999],
"斐": [178.065032, -17.713371],
"福克兰群岛": [-59.523613, -51.796253],
"法国": [2.213749, 46.227638],
"加蓬共和国": [11.609444, -0.803689],
"英国": [-3.435973, 55.378051],
"格鲁吉亚": [-82.9000751, 32.1656221],
"加纳": [-1.023194, 7.946527],
"几内亚": [-9.696645, 9.945587],
"冈比亚": [-15.310139, 13.443182],
"几内亚比绍": [-15.180413, 11.803749],
"赤道几内亚": [10.267895, 1.650801],
"希腊": [21.824312, 39.074208],
"格陵兰": [-42.604303, 71.706936],
"危地马拉": [-90.23075899999999, 15.783471],
"法属圭亚那": [-53.125782, 3.933889],
"圭亚那": [-58.93018, 4.860416],
"洪都拉斯": [-86.241905, 15.199999],
"克罗地亚": [15.2, 45.1],
"海地": [-72.285215, 18.971187],
"匈牙利共和国": [19.503304, 47.162494],
"印尼": [113.921327, -0.789275],
"爱尔兰": [-8.24389, 53.41291],
"伊朗": [53.688046, 32.427908],
"伊拉克": [43.679291, 33.223191],
"冰岛": [-19.020835, 64.963051],
"以色列": [34.851612, 31.046051],
"意大利": [12.56738, 41.87194],
"牙买加": [-77.297508, 18.109581],
"约旦": [36.238414, 30.585164],
"日本": [138.252924, 36.204824],
"哈萨克斯坦": [66.923684, 48.019573],
"肯尼亚": [37.906193, -0.023559],
"吉尔吉斯斯坦": [74.766098, 41.20438],
"柬埔寨": [104.990963, 12.565679],
"韩国": [127.766922, 35.907757],
"科索沃": [20.902977, 42.6026359],
"科威特": [47.481766, 29.31166],
"老挝": [102.495496, 19.85627],
"黎巴嫩": [35.862285, 33.854721],
"利比里亚共和国": [-9.429499000000002, 6.428055],
"利比亚": [17.228331, 26.3351],
"斯里兰卡": [80.77179699999999, 7.873053999999999],
"莱索托": [28.233608, -29.609988],
"立陶宛": [23.881275, 55.169438],
"巴林": [50.30, 26.10],
"卢森堡": [6.129582999999999, 49.815273],
"拉脱维亚共和国": [24.603189, 56.879635],
"摩洛哥": [-7.092619999999999, 31.791702],
"摩尔多瓦": [28.369885, 47.411631],
"马达加斯加": [46.869107, -18.766947],
"墨西哥": [-102.552784, 23.634501],
"马其顿": [21.745275, 41.608635],
"马里": [-3.996166, 17.570692],
"缅甸": [95.956223, 21.913965],
"黑山共和国": [19.37439, 42.708678],
"蒙古": [103.846656, 46.862496],
"莫桑比克": [35.529562, -18.665695],
"毛里塔尼亚": [-10.940835, 21.00789],
"马拉维": [34.301525, -13.254308],
"马来西亚": [101.975766, 4.210484],
"纳米比亚": [18.49041, -22.95764],
"新喀里多尼亚": [165.618042, -20.904305],
"尼日尔": [8.081666, 17.607789],
"尼日利亚": [8.675277, 9.081999],
"尼加拉瓜": [-85.207229, 12.865416],
"荷兰": [5.291265999999999, 52.132633],
"挪威": [8.468945999999999, 60.47202399999999],
"尼泊尔": [84.12400799999999, 28.394857],
"新西兰": [174.885971, -40.900557],
"阿曼": [55.923255, 21.512583],
"巴基斯坦": [69.34511599999999, 30.375321],
"巴拿马共和国": [-80.782127, 8.537981],
"秘鲁": [-75.015152, -9.189967],
"菲律宾": [121.774017, 12.879721],
"巴布亚新几内亚": [143.95555, -6.314992999999999],
"波兰": [19.145136, 51.919438],
"波多黎各": [-66.590149, 18.220833],
"北朝鲜": [127.510093, 40.339852],
"葡萄牙": [-8.224454, 39.39987199999999],
"巴拉圭": [-58.443832, -23.442503],
"卡塔尔": [51.183884, 25.354826],
"罗马尼亚": [24.96676, 45.943161],
"俄罗斯": [105.318756, 61.52401],
"俄罗斯联邦": [105.318756, 61.52401],
"卢旺达": [29.873888, -1.940278],
"西撒哈拉": [-12.885834, 24.215527],
"沙特阿拉伯": [45.079162, 23.885942],
"苏丹": [30.217636, 12.862807],
"南苏丹": [31.3069788, 6.876991899999999],
"塞内加尔": [-14.452362, 14.497401],
"所罗门群岛": [160.156194, -9.64571],
"塞拉利昂": [-11.779889, 8.460555],
"萨尔瓦多": [-88.89653, 13.794185],
"索马里兰": [46.8252838, 9.411743399999999],
"索马里": [46.199616, 5.152149],
"塞尔维亚": [21.005859, 44.016521],
"苏里南": [-56.027783, 3.919305],
"斯洛伐克共和国": [19.699024, 48.669026],
"斯洛文尼亚": [14.995463, 46.151241],
"瑞典": [18.643501, 60.12816100000001],
"斯威士兰": [31.465866, -26.522503],
"叙利亚": [38.996815, 34.80207499999999],
"乍得": [18.732207, 15.454166],
"多哥": [0.824782, 8.619543],
"泰国": [100.992541, 15.870032],
"塔吉克斯坦共和国": [71.276093, 38.861034],
"土库曼斯坦": [59.556278, 38.969719],
"东帝汶": [125.727539, -8.874217],
"特里尼达和多巴哥": [-61.222503, 10.691803],
"突尼斯": [9.537499, 33.886917],
"土耳其": [35.243322, 38.963745],
"坦桑尼亚": [34.888822, -6.369028],
"乌干达": [32.290275, 1.373333],
"乌克兰": [31.16558, 48.379433],
"乌拉圭": [-55.765835, -32.522779],
"美国": [-95.712891, 37.09024],
"乌兹别克斯坦": [64.585262, 41.377491],
"委内瑞拉": [-66.58973, 6.42375],
"越南": [108.277199, 14.058324],
"瓦努阿图": [166.959158, -15.376706],
"西岸": [35.3027226, 31.9465703],
"也门": [48.516388, 15.552727],
"南非": [22.937506, -30.559482],
"赞比亚": [27.849332, -13.133897],
"津巴布韦": [29.154857, -19.015438],
"科摩罗": [43.872219, -11.875001],
"印度尼西亚": [106.515414, -6.103040],
"印度": [78.96288, 20.593684],
"刚果": [15.12, -4.09],
"萨摩亚独立国": [-171.46, 13.5],
"朝鲜": [125.30, 39.09],
"新加坡": [103.87546, 1.30243],
"中非": [18.33, 4.21],
"巴勒斯坦": [35.25, 31.79],
"圣卢西亚": [-60.58, 14.02],
"安提瓜和巴布达": [-61.48, 17.20],
"巴巴多斯": [-59.30, 13.05],
"开曼群岛": [-81.24, 19.20],
"法罗群岛": [-6.56, 62.05],
"圣文森特和格林纳丁斯": [-61.10, 13.10],
"特立尼达和多巴哥": [-60.32, 11.18],
"台澎金马单独关税区": [121.21, 25.02],
"中国香港": [114.12, 22.26],
"中国澳门": [113.5, 22.2],
"格林纳达": [-61.4, 12.7],
"塞舌尔共和国": [55.28, -4.4],
"多米尼克": [61.23, 15.18],
"斐济": [178.30, -18.06],
"科特迪瓦": [-5.17, 6.49],
"欧盟": [4.47, 50.50]
},
"nameMap":{
"Afghanistan": "阿富汗",
"Singapore": "新加坡",
"Angola": "安哥拉",
"Albania": "阿尔巴尼亚",
"United Arab Emirates": "阿拉伯联合酋长国",
"Argentina": "阿根廷",
"Armenia": "亚美尼亚",
"French Southern and Antarctic Lands": "法属南半球和南极领地",
"Australia": "澳大利亚",
"Austria": "奥地利",
"Azerbaijan": "阿塞拜疆",
"Seychelles": "塞舌尔共和国",
"Burundi": "布隆迪",
"Belgium": "比利时",
"Benin": "贝宁",
"Burkina Faso": "布基纳法索",
"Côte d Ivoire": "科特迪瓦",
"Bangladesh": "孟加拉人民共和国",
"Bulgaria": "保加利亚",
"The Bahamas": "巴哈马",
"Bosnia and Herzegovina": "波斯尼亚和黑塞哥维那",
"Belarus": "白俄罗斯",
"Belize": "伯利兹",
"Bermuda": "百慕大",
"Bolivia": "玻利维亚",
"Brazil": "巴西",
"Brunei": "文莱",
"Bhutan": "不丹",
"Botswana": "博茨瓦纳",
"Central African Republic": "中非共和国",
"Canada": "加拿大",
"Switzerland": "瑞士",
"Chile": "智利",
"China": "中华人民共和国",
"Ivory Coast": "象牙海岸",
"Cameroon": "喀麦隆",
"Dem. Rep. Congo": "刚果民主共和国",
"Republic of the Congo": "刚果共和国",
"Colombia": "哥伦比亚",
"Costa Rica": "哥斯达黎加共和国",
"Cuba": "古巴",
"Northern Cyprus": "北塞浦路斯",
"Cyprus": "塞浦路斯",
"Czech Republic": "捷克共和国",
"Germany": "德国",
"Djibouti": "吉布提",
"Denmark": "丹麦",
"Dominican Republic": "多明尼加共和国",
"Algeria": "阿尔及利亚",
"Ecuador": "厄瓜多尔",
"Egypt": "埃及",
"Eritrea": "厄立特里亚",
"Spain": "西班牙",
"Estonia": "爱沙尼亚",
"Ethiopia": "埃塞俄比亚",
"Bahrain": "巴林",
"Finland": "芬兰",
"Fiji": "斐济",
"Falkland Islands": "福克兰群岛",
"France": "法国",
"Gabon": "加蓬共和国",
"United Kingdom": "英国",
"Georgia": "格鲁吉亚",
"Ghana": "加纳",
"Guinea": "几内亚",
"Gambia": "冈比亚",
"Guinea Bissau": "几内亚比绍",
"Greece": "希腊",
"Greenland": "格陵兰",
"Guatemala": "危地马拉",
"French Guiana": "法属圭亚那",
"Guyana": "圭亚那",
"Honduras": "洪都拉斯",
"Croatia": "克罗地亚",
"Haiti": "海地",
"Hungary": "匈牙利共和国",
"Indonesia": "印度尼西亚",
"India": "印度",
"Ireland": "爱尔兰",
"Iran": "伊朗",
"Iraq": "伊拉克",
"Iceland": "冰岛",
"Israel": "以色列",
"Italy": "意大利",
"Jamaica": "牙买加",
"Jordan": "约旦",
"Japan": "日本",
"Kazakhstan": "哈萨克斯坦",
"Kenya": "肯尼亚",
"Kyrgyzstan": "吉尔吉斯斯坦",
"Cambodia": "柬埔寨",
"Kosovo": "科索沃",
"Kuwait": "科威特",
"Laos": "老挝",
"Lebanon": "黎巴嫩",
"Liberia": "利比里亚共和国",
"Libya": "利比亚",
"Sri Lanka": "斯里兰卡",
"Lesotho": "莱索托",
"Lithuania": "立陶宛",
"Luxembourg": "卢森堡",
"Latvia": "拉脱维亚共和国",
"Morocco": "摩洛哥",
"Moldova": "摩尔多瓦",
"Madagascar": "马达加斯加",
"Mexico": "墨西哥",
"Macedonia": "马其顿",
"Mali": "马里",
"Myanmar": "缅甸",
"Montenegro": "黑山共和国",
"Mongolia": "蒙古",
"Mozambique": "莫桑比克",
"Mauritania": "毛里塔尼亚",
"Malawi": "马拉维",
"Malaysia": "马来西亚",
"Namibia": "纳米比亚",
"New Caledonia": "新喀里多尼亚",
"Niger": "尼日尔",
"Nigeria": "尼日利亚",
"Nicaragua": "尼加拉瓜",
"Netherlands": "荷兰",
"Norway": "挪威",
"Nepal": "尼泊尔",
"New Zealand": "新西兰",
"Oman": "阿曼",
"Pakistan": "巴基斯坦",
"Panama": "巴拿马共和国",
"Peru": "秘鲁",
"Philippines": "菲律宾",
"Papua New Guinea": "巴布亚新几内亚",
"Poland": "波兰",
"Puerto Rico": "波多黎各",
"North Korea": "北朝鲜",
"Portugal": "葡萄牙",
"Paraguay": "巴拉圭",
"Qatar": "卡塔尔",
"Romania": "罗马尼亚",
"Russia": "俄罗斯",
"Rwanda": "卢旺达",
"Western Sahara": "西撒哈拉",
"Saudi Arabia": "沙特阿拉伯",
"Sudan": "苏丹",
"S. Sudan": "南苏丹",
"Senegal": "塞内加尔",
"Solomon Islands": "所罗门群岛",
"Sierra Leone": "塞拉利昂",
"El Salvador": "萨尔瓦多",
"Somaliland": "索马里兰",
"Somalia": "索马里",
"Republic of Serbia": "塞尔维亚",
"Suriname": "苏里南",
"Slovakia": "斯洛伐克共和国",
"Slovenia": "斯洛文尼亚",
"Sweden": "瑞典",
"Swaziland": "斯威士兰",
"Syria": "叙利亚",
"Chad": "乍得",
"Togo": "多哥",
"Thailand": "泰国",
"Tajikistan": "塔吉克斯坦共和国",
"Turkmenistan": "土库曼斯坦",
"East Timor": "东帝汶",
"Trinidad and Tobago": "特立尼达和多巴哥",
"Tunisia": "突尼斯",
"Turkey": "土耳其",
"Uganda": "乌干达",
"Ukraine": "乌克兰",
"Uruguay": "乌拉圭",
"United States": "美国",
"Uzbekistan": "乌兹别克斯坦",
"Venezuela": "委内瑞拉",
"Vietnam": "越南",
"Vanuatu": "瓦努阿图",
"West Bank": "西岸",
"Yemen": "也门",
"South Africa": "南非",
"Zambia": "赞比亚",
"Korea": "韩国",
"Tanzania": "坦桑尼亚",
"Zimbabwe": "津巴布韦",
"Congo": "刚果",
"Central African Rep.": "中非",
"Serbia": "塞尔维亚",
"Bosnia and Herz.": "波黑",
"Czech Rep.": "捷克",
"W. Sahara": "西撒哈拉",
"Lao PDR": "老挝",
"Dem. Rep. Korea": "朝鲜",
"Falkland Is.": "福克兰群岛",
"Timor-Leste": "东帝汶",
"Solomon Is.": "所罗门群岛",
"Palestine": "巴勒斯坦",
"N. Cyprus": "北塞浦路斯",
"Aland": "奥兰群岛",
"Fr. S. Antarctic Lands": "法属南半球和南极陆地",
"Mauritius": "毛里求斯",
"Comoros": "科摩罗",
"Eq. Guinea": "赤道几内亚",
"Guinea-Bissau": "几内亚比绍",
"Dominican Rep.": "多米尼加共和国",
"Saint Lucia": "圣卢西亚",
"Dominica": "多米尼克",
"Antigua and Barb.": "安提瓜和巴布达",
"U.S. Virgin Is.": "美国原始岛屿",
"Montserrat": "蒙塞拉特",
"Grenada": "格林纳达",
"Barbados": "巴巴多斯",
"Samoa": "萨摩亚独立国",
"Bahamas": "巴哈马",
"Cayman Is.": "开曼群岛",
"Faeroe Is.": "法罗群岛",
"IsIe of Man": "马恩岛",
"Malta": "马耳他共和国",
"Jersey": "泽西",
"Cape Verde": "佛得角共和国",
"Turks and Caicos Is.": "特克斯和凯科斯群岛",
"St. Vin. and Gren.": "圣文森特和格林纳丁斯"
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Some files were not shown because too many files have changed in this diff Show More