commit 654e3bde2f5088279c881c7e32d4b1cdea88aa86 Author: sankeyangshu <1260323835@qq.com> Date: Mon Nov 18 11:00:55 2024 +0800 ci: 更换Git仓库 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ddcefeb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see http://editorconfig.org + +# 表示是最顶层的 EditorConfig 配置文件 +root = true + +[*] # 表示所有文件适用 +charset = utf-8 # 设置文件字符集为 utf-8 +indent_style = space # 缩进风格(tab | space) +indent_size = 2 # 缩进大小 +end_of_line = lf # 控制换行类型(lf | cr | crlf) +trim_trailing_whitespace = true # 去除行首的任意空白字符 +insert_final_newline = true # 始终在文件末尾插入一个新行 + +[*.md] # 表示仅 md 文件适用以下规则 +max_line_length = off +trim_trailing_whitespace = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..396ac41 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,14 @@ +*.sh +node_modules +*.md +*.woff +*.ttf +.vscode +.idea +dist +/public +/docs +.husky +.local +/bin +Dockerfile diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..09e62f2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,70 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + node: true, + }, + // 指定如何解析语法 + parser: 'vue-eslint-parser', + // 优先级低于 parse 的语法解析配置 + parserOptions: { + parser: '@typescript-eslint/parser', + ecmaVersion: 'latest', + sourceType: 'module', + }, + // 继承某些已有的规则 + extends: [ + 'plugin:vue/vue3-essential', + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', // 添加 prettier 插件 + ], + plugins: ['vue', '@typescript-eslint', 'import', 'prettier', 'simple-import-sort'], + overrides: [ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser', + }, + ], + rules: { + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/promise-function-async': 'off', + 'vue/multi-word-component-names': 'off', + 'simple-import-sort/imports': [ + 'error', + { + groups: [ + [ + // 以字母(或数字或下划线)或“@”后面跟着字母开头的东西,通常为内置模块引入 + '^@?\\w', + // 内部导入 "@/" + '^@(/.*|$)', + `^@/assets$`, + `^@/components$`, + `^@/config$`, + `^@/hooks$`, + `^@/plugins$`, + `^@/router$`, + `^@/store$`, + `^@/styles$`, + `^@/utils$`, + // 父级导入. 把 `..` 放在最后. + '^\\.\\.(?!/?$)', + '^\\.\\./?$', + // 同级导入. 把同一个文件夹.放在最后 + '^\\./(?=.*/)(?!/?$)', + '^\\.(?!/?$)', + '^\\./?$', + // 样式导入. + '^.+\\.?(css|less|scss)$', + // 带有副作用导入,比如import 'a.css'这种. + '^\\u0000', + ], + ], + }, + ], + 'simple-import-sort/exports': 'error', // 导出 + 'import/order': 'off', + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..1a089f4 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx --no-install commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d24fdfc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3660c26 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "useTabs": false, + "tabWidth": 2, + "printWidth": 100, + "singleQuote": true, + "trailingComma": "es5", + "bracketSpacing": true, + "semi": true +} diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..0517076 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,3 @@ +/dist/* +/public/* +public/* diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000..8819814 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,41 @@ +// @see: https://stylelint.io + +module.exports = { + root: true, + // 继承某些已有的规则 + extends: [ + 'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化 + 'stylelint-config-standard-scss', // 配置 stylelint scss 插件 + 'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化 + 'stylelint-config-recess-order', // 配置 stylelint css 属性书写顺序插件, + ], + overrides: [ + // 扫描 .vue/html 文件中的 diff --git a/src/assets/icons/API.svg b/src/assets/icons/API.svg new file mode 100644 index 0000000..508f94b --- /dev/null +++ b/src/assets/icons/API.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/BoatInfo.svg b/src/assets/icons/BoatInfo.svg new file mode 100644 index 0000000..c61e020 --- /dev/null +++ b/src/assets/icons/BoatInfo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Help.svg b/src/assets/icons/Help.svg new file mode 100644 index 0000000..a42d47c --- /dev/null +++ b/src/assets/icons/Help.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/History.svg b/src/assets/icons/History.svg new file mode 100644 index 0000000..59e6fb1 --- /dev/null +++ b/src/assets/icons/History.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Home.svg b/src/assets/icons/Home.svg new file mode 100644 index 0000000..cb0faf5 --- /dev/null +++ b/src/assets/icons/Home.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Logout.svg b/src/assets/icons/Logout.svg new file mode 100644 index 0000000..c51813c --- /dev/null +++ b/src/assets/icons/Logout.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/ManifestInfo.svg b/src/assets/icons/ManifestInfo.svg new file mode 100644 index 0000000..673bd61 --- /dev/null +++ b/src/assets/icons/ManifestInfo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Moon.svg b/src/assets/icons/Moon.svg new file mode 100644 index 0000000..55116e6 --- /dev/null +++ b/src/assets/icons/Moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/Notify.svg b/src/assets/icons/Notify.svg new file mode 100644 index 0000000..2a3ad58 --- /dev/null +++ b/src/assets/icons/Notify.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/SendInfo.svg b/src/assets/icons/SendInfo.svg new file mode 100644 index 0000000..b9e0af0 --- /dev/null +++ b/src/assets/icons/SendInfo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Setting.svg b/src/assets/icons/Setting.svg new file mode 100644 index 0000000..de266bd --- /dev/null +++ b/src/assets/icons/Setting.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/SubscribeInfo.svg b/src/assets/icons/SubscribeInfo.svg new file mode 100644 index 0000000..f359e27 --- /dev/null +++ b/src/assets/icons/SubscribeInfo.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/Sunny.svg b/src/assets/icons/Sunny.svg new file mode 100644 index 0000000..21959d5 --- /dev/null +++ b/src/assets/icons/Sunny.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/imgs/logo.png b/src/assets/imgs/logo.png new file mode 100644 index 0000000..6a3a766 Binary files /dev/null and b/src/assets/imgs/logo.png differ diff --git a/src/assets/vue.svg b/src/assets/vue.svg new file mode 100644 index 0000000..ca8129c --- /dev/null +++ b/src/assets/vue.svg @@ -0,0 +1 @@ + diff --git a/src/components/Pagination/index.vue b/src/components/Pagination/index.vue new file mode 100644 index 0000000..0f054dd --- /dev/null +++ b/src/components/Pagination/index.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..803f435 --- /dev/null +++ b/src/components/SvgIcon/index.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/src/components/SwitchDark/index.vue b/src/components/SwitchDark/index.vue new file mode 100644 index 0000000..c0fe263 --- /dev/null +++ b/src/components/SwitchDark/index.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts new file mode 100644 index 0000000..3c1525a --- /dev/null +++ b/src/hooks/useTheme.ts @@ -0,0 +1,26 @@ +import { computed } from 'vue'; +import { useSettingStore } from '@/store/modules/setting'; + +/** + * @description: 全局主题设置 + */ +export const useTheme = () => { + // 获取全局状态管理仓库中系统设置状态 + const settingStore = useSettingStore(); + const isDark = computed(() => settingStore.isDark); + + // 切换暗黑模式 + const switchDark = () => { + const body = document.documentElement; + + if (isDark.value) { + body.setAttribute('class', 'dark'); + } else { + body.setAttribute('class', ''); + } + }; + + return { + switchDark, + }; +}; diff --git a/src/layouts/Footer/index.vue b/src/layouts/Footer/index.vue new file mode 100644 index 0000000..127d483 --- /dev/null +++ b/src/layouts/Footer/index.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/src/layouts/Header/index.vue b/src/layouts/Header/index.vue new file mode 100644 index 0000000..08e64bd --- /dev/null +++ b/src/layouts/Header/index.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/layouts/Main/index.vue b/src/layouts/Main/index.vue new file mode 100644 index 0000000..28ec7bc --- /dev/null +++ b/src/layouts/Main/index.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/src/layouts/Sidebar/components/SubMenu.vue b/src/layouts/Sidebar/components/SubMenu.vue new file mode 100644 index 0000000..cba106a --- /dev/null +++ b/src/layouts/Sidebar/components/SubMenu.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/layouts/Sidebar/index.vue b/src/layouts/Sidebar/index.vue new file mode 100644 index 0000000..8a1779e --- /dev/null +++ b/src/layouts/Sidebar/index.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/layouts/index.vue b/src/layouts/index.vue new file mode 100644 index 0000000..a299316 --- /dev/null +++ b/src/layouts/index.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..0432413 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,29 @@ +import { createApp } from 'vue'; +import setupElementPlus from '@/plugins/element'; // 导入element plus +import setupSvgIcons from '@/plugins/icons'; // 导入svg图标组件 +import { setupRouter } from '@/router'; +import { setupStore } from '@/store'; +import App from './App.vue'; +import './styles/index.scss'; // 全局css +import 'virtual:svg-icons-register'; // svg-icons注册导入 + +function bootstrap() { + // 创建实例 + const app = createApp(App); + + // 配置 store + setupStore(app); + + // 配置路由 + setupRouter(app); + + // 导入svg图标 + setupSvgIcons(app); + + // 导入element和全局注册element 图标 + setupElementPlus(app); + + app.mount('#app'); +} + +bootstrap(); diff --git a/src/plugins/element.ts b/src/plugins/element.ts new file mode 100644 index 0000000..5f25488 --- /dev/null +++ b/src/plugins/element.ts @@ -0,0 +1,16 @@ +import * as ElementPlusIconsVue from '@element-plus/icons-vue'; // 统一导入el-icon图标 +import ElementPlus from 'element-plus'; +import { App } from 'vue'; +import 'element-plus/dist/index.css'; +import 'element-plus/theme-chalk/dark/css-vars.css'; // 暗黑主题 + +/** + * 导入element和全局注册element 图标 + */ +export default (app: App) => { + app.use(ElementPlus); + // 统一注册el-icon图标 + for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component); + } +}; diff --git a/src/plugins/icons.ts b/src/plugins/icons.ts new file mode 100644 index 0000000..dc09d07 --- /dev/null +++ b/src/plugins/icons.ts @@ -0,0 +1,6 @@ +import { App } from 'vue'; +import SvgIcon from '@/components/SvgIcon/index.vue'; // svg图标组件 + +export default (app: App) => { + app.component('svg-icon', SvgIcon); +}; diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..48a215c --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,53 @@ +import { App } from 'vue'; +import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; +import boatRoutes from './modules/boat'; +import historyRoutes from './modules/history'; +import manifestRoutes from './modules/manifest'; +import sendRoutes from './modules/send'; +import subscribeRoutes from './modules/subscribe'; + +const routes: Array = [ + { + path: '/', + name: 'layout', + component: Layout, + redirect: '/home', + children: [ + { + path: '/home', + name: 'home', + component: () => import('@/views/Home/index.vue'), + meta: { title: 'home', affix: true }, + }, + { + path: '/notify', + name: 'notify', + component: () => import('@/views/Notify/index.vue'), + meta: { title: 'notify', affix: true }, + }, + { + path: '/resource', + name: 'resource', + component: () => import('@/views/Resource/index.vue'), + meta: { title: 'resource', affix: true }, + }, + ], + }, + ...boatRoutes, + ...manifestRoutes, + ...sendRoutes, + ...subscribeRoutes, + ...historyRoutes, +]; + +// 创建一个可以被 Vue 应用程序使用的路由实例 +export const router = createRouter({ + history: createWebHashHistory(), + routes, +}); + +// 配置路由器 +export function setupRouter(app: App) { + app.use(router); +} diff --git a/src/router/modules/boat.ts b/src/router/modules/boat.ts new file mode 100644 index 0000000..d2111e6 --- /dev/null +++ b/src/router/modules/boat.ts @@ -0,0 +1,52 @@ +import { RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; + +/** + * 船舶路由 + */ +const boatRoutes: Array = [ + { + path: '/boat', + component: Layout, + redirect: '/boat/info', + meta: { + title: '船舶信息', + icon: 'BoatInfo', + native: false, + }, + children: [ + { + path: '/boat/info', + name: 'boatInfo', + component: () => import('@/views/Boat/Info/index.vue'), + meta: { + title: '船期信息', + icon: 'Menu', + native: true, + }, + }, + { + path: '/boat/query', + name: 'boatQuery', + component: () => import('@/views/Boat/Query/index.vue'), + meta: { + title: '船图查询', + icon: 'Menu', + native: true, + }, + }, + { + path: '/boat/track', + name: 'boatTrack', + component: () => import('@/views/Boat/Track/index.vue'), + meta: { + title: '船位跟踪', + icon: 'Menu', + native: true, + }, + }, + ], + }, +]; + +export default boatRoutes; diff --git a/src/router/modules/history.ts b/src/router/modules/history.ts new file mode 100644 index 0000000..9863229 --- /dev/null +++ b/src/router/modules/history.ts @@ -0,0 +1,42 @@ +import { RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; + +/** + * 历史数据路由 + */ +const historyRoutes: Array = [ + { + path: '/history', + component: Layout, + redirect: '/history/mine', + meta: { + title: '历史数据', + icon: 'History', + native: false, + }, + children: [ + { + path: '/history/mine', + name: 'Mine', + component: () => import('@/views/History/Mine/index.vue'), + meta: { + title: '我发布的', + icon: 'Menu', + native: true, + }, + }, + { + path: '/history/receive', + name: 'Receive', + component: () => import('@/views/History/Receive/index.vue'), + meta: { + title: '我收到的', + icon: 'Menu', + native: true, + }, + }, + ], + }, +]; + +export default historyRoutes; diff --git a/src/router/modules/manifest.ts b/src/router/modules/manifest.ts new file mode 100644 index 0000000..23a29db --- /dev/null +++ b/src/router/modules/manifest.ts @@ -0,0 +1,53 @@ +import { RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; + +/** + * 舱单路由 + */ +const manifestRoutes: Array = [ + { + path: '/manifest', + component: Layout, + redirect: '/manifest/manage', + meta: { + title: '舱单信息', + icon: 'ManifestInfo', + native: false, + }, + children: [ + { + path: '/manifest/manage', + name: 'manifestManage', + component: () => import('@/views/Manifest/Manage/index.vue'), + meta: { + title: '舱单信息', + icon: 'Menu', + native: true, + }, + }, + + { + path: '/manifest/detail', + name: 'manifestDetail', + component: () => import('@/views/Manifest/Detail/index.vue'), + meta: { + title: '提单明细', + icon: 'Menu', + native: true, + }, + }, + { + path: '/manifest/stowage', + name: 'manifestStowage', + component: () => import('@/views/Manifest/Stowage/index.vue'), + meta: { + title: '积载图', + icon: 'Menu', + native: true, + }, + }, + ], + }, +]; + +export default manifestRoutes; diff --git a/src/router/modules/send.ts b/src/router/modules/send.ts new file mode 100644 index 0000000..ac58182 --- /dev/null +++ b/src/router/modules/send.ts @@ -0,0 +1,23 @@ +import { RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; + +/** + * 发布信息路由 + */ +const sendRoutes: Array = [ + { + path: '/send', + component: Layout, + redirect: '/send/index', + children: [ + { + path: '/send/index', + name: 'send', + component: () => import('@/views/Send/index.vue'), + meta: { title: '发布信息', icon: 'SendInfo', native: false }, + }, + ], + }, +]; + +export default sendRoutes; diff --git a/src/router/modules/subscribe.ts b/src/router/modules/subscribe.ts new file mode 100644 index 0000000..c095fd4 --- /dev/null +++ b/src/router/modules/subscribe.ts @@ -0,0 +1,42 @@ +import { RouteRecordRaw } from 'vue-router'; +import Layout from '@/layouts/index.vue'; + +/** + * 订阅信息路由 + */ +const subscribeRoutes: Array = [ + { + path: '/subscribe', + component: Layout, + redirect: '/subscribe/mine', + meta: { + title: '订阅信息', + icon: 'SubscribeInfo', + native: false, + }, + children: [ + { + path: '/subscribe/mine', + name: 'Mine', + component: () => import('@/views/Subscribe/Mine/index.vue'), + meta: { + title: '我的订阅', + icon: 'Menu', + native: true, + }, + }, + { + path: '/subscribe/receive', + name: 'Receive', + component: () => import('@/views/Subscribe/Receive/index.vue'), + meta: { + title: '收到订阅', + icon: 'Menu', + native: true, + }, + }, + ], + }, +]; + +export default subscribeRoutes; diff --git a/src/router/permission.ts b/src/router/permission.ts new file mode 100644 index 0000000..80a7bec --- /dev/null +++ b/src/router/permission.ts @@ -0,0 +1,76 @@ +import NProgress from 'nprogress'; // 进度条 +import { router } from '@/router'; +import 'nprogress/nprogress.css'; // 进度条样式 + +// 进度条配置 +NProgress.configure({ showSpinner: false }); + +// 白名单-不需要权限验证 +const whiteList = ['/login']; + +/** + * 路由前置守卫 + * @param to 要到哪里去 + * @param from 从哪里来 + * @param next 是否要去 + */ +router.beforeEach(async (to, from, next) => { + // 进度条开始 + NProgress.start(); + + // 设置标题 + if (typeof to.meta.title === 'string') { + document.title = to.meta.title || import.meta.env.VITE_APP_TITLE; + } + + // 获取用户信息 store + // const userStore = useUserStore(); + // 获取用户是否登录状态,确定用户是否已登录过,存在Token + // const hasToken = userStore.token; + + if (false) { + // 用户登录 + if (to.path === '/login') { + // 如果已登录,重定向到主页 + next({ path: '/' }); + } else { + // 获取用户权限 store + // const permissionStore = usePermissionStore(); + // 确定用户是否已通过getInfo获得其权限角色 + // const hasRoles = userStore.roles && userStore.roles.length > 0; + try { + // // 路由添加进去了没有及时更新 需要重新进去一次拦截 + // if (!permissionStore.routes.length) { + // // 获取权限列表进行接口访问 因为这里页面要切换权限 + // const accessRoutes = await permissionStore.generateRoutes(userStore.roles); + + // // 动态添加访问路由表 + // accessRoutes.forEach((item) => router.addRoute(item)); + + // // 这里相当于push到一个页面 不在进入路由拦截 + // next({ ...to, replace: true }); + // } else { + // // 如果不传参数就会重新执行路由拦截,重新进到这里 + // next(); + // } + next(); + } catch (error) { + next(`/login?redirect=${to.path}`); + } + } + } else { + // 用户未登录 + if (whiteList.indexOf(to.path) !== -1) { + // 在免登录白名单中,直接进入 + next(); + } else { + // 没有访问权限的其他页面将重定向到登录页面 + next(`/login?redirect=${to.path}`); + } + } +}); + +router.afterEach(() => { + // 进度条结束 + NProgress.done(); +}); diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..674738d --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,12 @@ +import { createPinia } from 'pinia'; +import { App } from 'vue'; + +// 创建pinia实例 +const store = createPinia(); + +// 配置pinia +export function setupStore(app: App) { + app.use(store); +} + +export { store }; diff --git a/src/store/modules/setting.ts b/src/store/modules/setting.ts new file mode 100644 index 0000000..586e895 --- /dev/null +++ b/src/store/modules/setting.ts @@ -0,0 +1,23 @@ +import { defineStore } from 'pinia'; + +interface settingsStateType { + isDark: boolean; +} + +export const useSettingStore = defineStore({ + // id: 必须的,在所有 Store 中唯一 + id: 'settingState', + + // state: 返回对象的函数 + state: (): settingsStateType => ({ + isDark: false, // 深色模式 切换暗黑模式 + }), + + // actions: 可以同步 也可以异步 + actions: { + // 设置暗黑模式 + setThemeDark(value: boolean) { + this.isDark = value; + }, + }, +}); diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 0000000..3efbde9 --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,32 @@ +@import './reset.scss'; +@import './transition.scss'; +html, +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', + Arial, sans-serif; +} +label { + font-weight: 700; +} +html { + box-sizing: border-box; + height: 100%; +} +body { + background: #f0f2f5; +} +#app { + height: 100%; +} + +/* 自定义暗黑模式样式 */ +html.dark { + body { + color: #fff; + background-color: #222; + } +} diff --git a/src/styles/reset.scss b/src/styles/reset.scss new file mode 100644 index 0000000..e7fc595 --- /dev/null +++ b/src/styles/reset.scss @@ -0,0 +1,126 @@ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + padding: 0; + margin: 0; + font: inherit; + font-size: 100%; + vertical-align: baseline; + border: 0; +} + +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + padding: 0; + margin: 0; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote::before, +blockquote::after, +q::before, +q::after { + content: ''; + content: none; +} +table { + border-spacing: 0; + border-collapse: collapse; +} diff --git a/src/styles/transition.scss b/src/styles/transition.scss new file mode 100644 index 0000000..628918a --- /dev/null +++ b/src/styles/transition.scss @@ -0,0 +1,38 @@ +// 全局动画 css + +// logo动画 +.sidebarLogoFade-enter-active { + transition: opacity 2s; +} +.sidebarLogoFade-enter-from, +.sidebarLogoFade-leave-to { + opacity: 0; +} + +// 面包屑动画 +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all 0.5s; +} +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(10px) skewX(-10deg); +} +.breadcrumb-leave-active { + position: absolute; +} + +// 路由 +.fade-slide-leave-active, +.fade-slide-enter-active { + transition: all 0.3s; +} +.fade-slide-enter-from { + opacity: 0; + transform: translateX(-30px); +} +.fade-slide-leave-to { + opacity: 0; + transform: translateX(30px); +} diff --git a/src/utils/routers.ts b/src/utils/routers.ts new file mode 100644 index 0000000..5785aa3 --- /dev/null +++ b/src/utils/routers.ts @@ -0,0 +1,86 @@ +import path from 'path-browserify'; +import { RouteRecordRaw } from 'vue-router'; + +/** + * @description: 返回所有子路由 + * @param {RouteRecordRaw[]} routes 路由数组 + * @return 子路由数组 + */ +const getChildrenRoutes = (routes: RouteRecordRaw[]) => { + const result: RouteRecordRaw[] = []; + routes.forEach((route) => { + if (route.children && route.children.length > 0) { + result.push(...route.children); + } + }); + return result; +}; + +/** + * @description: 处理脱离层级的路由:某个一级路由为其他子路由,则剔除该一级路由,保留路由层级 + * @param {RouteRecordRaw[]} routes + * @return 符合条件的路由 + */ +export const filterRoutes = (routes: RouteRecordRaw[]) => { + const childrenRoutes = getChildrenRoutes(routes); + return routes.filter((route) => { + return !childrenRoutes.find((childrenRoute) => { + return childrenRoute.path === route.path; + }); + }); +}; + +/** + * @description: 判断数据是否为空值 + * @param {any} data 数据 + * @return 判断结果-是否为空 + */ +const isNull = (data: any) => { + if (!data) return true; + if (JSON.stringify(data) === '{}') return true; + if (JSON.stringify(data) === '[]') return true; + return false; +}; + +/** + * @description: 根据routes数据,返回对应的menu规则数据 + * @param {RouteRecordRaw[]} routes + * @param {string} basePath 基础路径 + * @return 对应的menu规则数据 + */ +export const generateMenus = (routes: RouteRecordRaw[], basePath = '') => { + const result: RouteRecordRaw[] = []; + // 不满足条件:meta && meta.title && meta.icon 的数据不应该存在 + routes.forEach((item) => { + // 不存在children && meta ,直接返回 + if (isNull(item.children) && isNull(item.meta)) return; + // 存在children,不存在meta,迭代 generateMenus + if (isNull(item.meta) && !isNull(item.children)) { + result.push(...generateMenus(item.children as RouteRecordRaw[])); // 断言children为Array类型 + return; + } + // 不存在 children,存在meta || 存在children,也存在meta + // 因为最终的menu需要进行跳转,此时我们需要合并path + const routePath = path.resolve(basePath, item.path); + // 路由分离之后,可能存在同名父路由的情况 + let route = result.find((item) => item.path === routePath); + // 当前路由尚未加入到result + if (!route) { + route = { + ...item, + path: routePath, + children: [], + }; + // 路由icon和title存在 + if (route.meta?.icon && route.meta.title) { + result.push(route); + } + } + + // 存在children 和 meta + if (!isNull(item.children)) { + route.children?.push(...generateMenus(item.children as RouteRecordRaw[], route.path)); + } + }); + return result; +}; diff --git a/src/views/Boat/Info/components/InfoTable.vue b/src/views/Boat/Info/components/InfoTable.vue new file mode 100644 index 0000000..1bd6803 --- /dev/null +++ b/src/views/Boat/Info/components/InfoTable.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/src/views/Boat/Info/index.vue b/src/views/Boat/Info/index.vue new file mode 100644 index 0000000..c400b6b --- /dev/null +++ b/src/views/Boat/Info/index.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/src/views/Boat/Query/index.vue b/src/views/Boat/Query/index.vue new file mode 100644 index 0000000..6038aa4 --- /dev/null +++ b/src/views/Boat/Query/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Boat/Track/index.vue b/src/views/Boat/Track/index.vue new file mode 100644 index 0000000..a13c33c --- /dev/null +++ b/src/views/Boat/Track/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/History/Mine/index.vue b/src/views/History/Mine/index.vue new file mode 100644 index 0000000..8bf2edb --- /dev/null +++ b/src/views/History/Mine/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/History/Receive/index.vue b/src/views/History/Receive/index.vue new file mode 100644 index 0000000..1b87da3 --- /dev/null +++ b/src/views/History/Receive/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Home/components/Card.vue b/src/views/Home/components/Card.vue new file mode 100644 index 0000000..5cb2671 --- /dev/null +++ b/src/views/Home/components/Card.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/views/Home/components/HomeChart.vue b/src/views/Home/components/HomeChart.vue new file mode 100644 index 0000000..c02767a --- /dev/null +++ b/src/views/Home/components/HomeChart.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/views/Home/index.vue b/src/views/Home/index.vue new file mode 100644 index 0000000..94c0560 --- /dev/null +++ b/src/views/Home/index.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/src/views/Manifest/Detail/index.vue b/src/views/Manifest/Detail/index.vue new file mode 100644 index 0000000..33bbf3c --- /dev/null +++ b/src/views/Manifest/Detail/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Manifest/Manage/index.vue b/src/views/Manifest/Manage/index.vue new file mode 100644 index 0000000..a2b3542 --- /dev/null +++ b/src/views/Manifest/Manage/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Manifest/Stowage/index.vue b/src/views/Manifest/Stowage/index.vue new file mode 100644 index 0000000..cb54f83 --- /dev/null +++ b/src/views/Manifest/Stowage/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Notify/index.vue b/src/views/Notify/index.vue new file mode 100644 index 0000000..958d3a4 --- /dev/null +++ b/src/views/Notify/index.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/views/Resource/index.vue b/src/views/Resource/index.vue new file mode 100644 index 0000000..cd8745f --- /dev/null +++ b/src/views/Resource/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Send/index.vue b/src/views/Send/index.vue new file mode 100644 index 0000000..5dcff0c --- /dev/null +++ b/src/views/Send/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Subscribe/Mine/index.vue b/src/views/Subscribe/Mine/index.vue new file mode 100644 index 0000000..8bf2edb --- /dev/null +++ b/src/views/Subscribe/Mine/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/views/Subscribe/Receive/index.vue b/src/views/Subscribe/Receive/index.vue new file mode 100644 index 0000000..1b87da3 --- /dev/null +++ b/src/views/Subscribe/Receive/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..af36df3 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..67ce0b0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..9d31e2a --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..590a4ae --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,28 @@ +import vue from '@vitejs/plugin-vue'; +import path from 'path'; +import { defineConfig } from 'vite'; +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; + +function resolve(dir: string) { + return path.join(__dirname, '.', dir); +} + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + // 使用 svg 图标 + createSvgIconsPlugin({ + // 指定需要缓存的图标文件夹 + iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], + // 指定symbolId格式 + symbolId: 'icon-[dir]-[name]', + }), + ], + // 配置别名 + resolve: { + alias: { + '@': resolve('src'), // 设置 `@` 指向 `src` 目录 + }, + }, +});