提交 450cbfe6 authored 作者: xiejiang's avatar xiejiang

feat: init初始化项目

上级 48a0a0a4
# @see: http://editorconfig.org
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
end_of_line = lf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 始终在文件末尾插入一个新行
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
max_line_length = 130 # 最大行长度
[*.md] # 表示仅对 md 文件适用以下规则
max_line_length = off # 关闭最大行长度限制
trim_trailing_whitespace = false # 关闭末尾空格修剪
# title
VITE_GLOB_APP_TITLE = '智慧教育后台管理系统'
# 本地运行端口号
VITE_PORT = 5173
# 启动时自动打开浏览器
VITE_OPEN = false
# 打包后是否生成包分析文件
VITE_REPORT = false
###
# @Author: xiejiang
# @Date: 2024-11-05 10:14:56
# @LastEditors: xiejiang
# @LastEditTime: 2024-12-05 11:37:54
# @Description:
# Copyright(c)2024 by 好老师教育科技有限公司 All right Reserved.
###
# 本地环境
VITE_USER_NODE_ENV = development
# 公共基础路径
VITE_PUBLIC_PATH = /
# 打包时是否删除 console
VITE_DROP_CONSOLE = true
# 开发环境接口地址
# VITE_API_URL = http://api.pge.seevin.com
# 汪洋
VITE_API_URL = http://172.16.3.197:8095
# 邹琪涛
# VITE_API_URL = https://e28e-14-105-62-130.ngrok-free.app
# 开发环境跨域代理,支持配置多个
VITE_PROXY = []
# 线上环境
VITE_USER_NODE_ENV = production
# 公共基础路径
VITE_PUBLIC_PATH = /
# 是否启用 gzip 或 brotli 压缩打包,如果需要多个压缩规则,可以使用 “,” 分隔
# Optional: gzip | brotli | none
VITE_BUILD_COMPRESS = none
# 打包压缩后是否删除源文件
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# 打包时是否删除 console
VITE_DROP_CONSOLE = true
# 线上环境接口地址
VITE_API_URL = "https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e"
# 测试环境
VITE_USER_NODE_ENV = test
# 公共基础路径
VITE_PUBLIC_PATH = /
# 是否启用 gzip 或 brotli 压缩打包,如果需要多个压缩规则,可以使用 “,” 分隔
# Optional: gzip | brotli | none
VITE_BUILD_COMPRESS = none
# 打包压缩后是否删除源文件
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
# 打包时是否删除 console
VITE_DROP_CONSOLE = true
# 测试环境接口地址
VITE_API_URL = http://api.hidowell.seevin.com
*.sh
node_modules
*.md
.vscode
.idea
/dist
/docs
.husky
.local
/bin
/src/assets/**
package.json
/*
* @Author: zhanyoulin<zhanyoulin456@163.com>
* @Date: 2023-09-06 09:18:04
* @LastEditors: zhanyoulin
* @LastEditTime: 2023-10-13 10:06:22
* @Description:
*/
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-sparse-arrays': 'off', // 忽略数组中逗号错误
// eslint (http://eslint.cn/docs/rules)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行
'prefer-const': 'off', // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
'no-undef': 'off',
semi: [0, 'never'], // 允许使用分号
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'off', // 禁止使用 @ts-ignore
'@typescript-eslint/ban-ts-comment': 'error', // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
'@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/ban-types': 'off', // 禁止使用特定类型
'@typescript-eslint/no-var-requires': 'off', // 允许使用 require() 函数导入模块
'@typescript-eslint/no-empty-function': 'off', // 禁止空函数
'@typescript-eslint/no-non-null-assertion': 'off', // 不允许使用后缀运算符的非空断言(!)
// vue (https://eslint.vuejs.org/rules)
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用,此规则仅在启用该no-unused-vars规则时有效
'vue/v-slot-style': 'error', // 强制执行 v-slot 指令样式
'vue/no-mutating-props': 'error', // 不允许改变组件 prop
'vue/custom-event-name-casing': 'off', // 为自定义事件名称强制使用特定大小写
'vue/html-closing-bracket-newline': 'off', // 在标签的右括号之前要求或禁止换行
'vue/attribute-hyphenation': 'error', // 对模板中的自定义组件强制执行属性命名样式:my-prop="prop"
'vue/attributes-order': 'off', // vue api使用顺序,强制执行属性顺序
'vue/no-v-html': 'off', // 禁止使用 v-html
'vue/require-default-prop': 'off', // 此规则要求为每个 prop 为必填时,必须提供默认值
'vue/multi-word-component-names': 'off' // 要求组件名称始终为 “-” 链接的单词
}
}
node_modules
.nvmdrc
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-staged
/dist/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*
stats.html
/*
* @Author: zhanyoulin<zhanyoulin456@163.com>
* @Date: 2023-06-13 09:41:17
* @LastEditors: zhanyoulin
* @LastEditTime: 2023-06-23 14:01:15
* @Description:
*/
// @see: https://www.prettier.cn
module.exports = {
// 指定最大换行长度
printWidth: 120,
// 缩进制表符宽度 | 空格数
tabWidth: 2,
// 使用制表符而不是空格缩进行 (true:制表符,false:空格)
useTabs: false,
// 结尾不用分号 (true:有,false:没有)
semi: false,
// 使用单引号 (true:单引号,false:双引号)
singleQuote: true,
// 在对象字面量中决定是否将属性名用引号括起来 可选值 "<as-needed|consistent|preserve>"
quoteProps: 'as-needed',
// 在JSX中使用单引号而不是双引号 (true:单引号,false:双引号)
jsxSingleQuote: true,
// 多行时尽可能打印尾随逗号 可选值"<none|es5|all>"
trailingComma: 'none',
// 在对象,数组括号与文字之间加空格 "{ foo: bar }" (true:有,false:没有)
bracketSpacing: true,
// 将 > 多行元素放在最后一行的末尾,而不是单独放在下一行 (true:放末尾,false:单独一行)
bracketSameLine: false,
// (x) => {} 箭头函数参数只有一个时是否要有小括号 (avoid:省略括号,always:不省略括号)
arrowParens: 'avoid',
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 可以在文件顶部插入一个特殊标记,指定该文件已使用 Prettier 格式化
insertPragma: false,
// 用于控制文本是否应该被换行以及如何进行换行
proseWrap: 'preserve',
// 在html中空格是否是敏感的 "css" - 遵守 CSS 显示属性的默认值, "strict" - 空格被认为是敏感的 ,"ignore" - 空格被认为是不敏感的
htmlWhitespaceSensitivity: 'css',
// 控制在 Vue 单文件组件中 <script> 和 <style> 标签内的代码缩进方式
vueIndentScriptAndStyle: false,
// 换行符使用 lf 结尾是 可选值 "<auto|lf|crlf|cr>"
endOfLine: 'auto',
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码 (rangeStart:开始,rangeEnd:结束)
rangeStart: 0,
rangeEnd: Infinity
}
/dist/*
/public/*
public/*
stats.html
/src/styles/tailwind.css
/src/assets/*
{
"recommendations": [
"vue.volar",
"vue.vscode-typescript-vue-plugin",
"hollowtree.vue-snippets",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"stylelint.vscode-stylelint",
"esbenp.prettier-vscode",
"editorconfig.editorconfig",
"syler.sass-indented",
"mikestead.dotenv"
]
}
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
},
"stylelint.enable": true,
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass", "html"],
"files.eol": "\n",
"typescript.tsdk": "node_modules/typescript/lib",
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"vue.codeActions.enabled": false
}
{
"Vue3+defineOptions快速生成模板": {
"scope": "vue",
"prefix": "vue3",
"body": [
"<template>",
"\t<div></div>",
"</template>\n",
"<script setup lang='ts'>",
"defineOptions({",
"\tname: ''",
"})",
"</script>\n",
"<style lang='less' scoped></style>",
"$2"
],
"description": "Vue3+defineOptions快速生成模板"
}
}
# Changelog
### feature
MIT License
Copyright (c) 2022 zhanyoulin
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.
# web-platform # smart-education-admin
运营平台前端项目 智慧教育后台
\ No newline at end of file
### 介绍 📖
### 代码仓库 ⭐
- GitLab:http://code.seevin.com/project-collaboration-platform/admin-web
### 主要技术栈 🔨
- 使用 Vue3.5x + TypeScript 开发,单文件组件**< script setup lang="ts">**
- 采用 Vite4 作为项目开发、打包工具(配置 Gzip 打包、TSX 语法、跨域代理…)
- 使用 Pinia 作为状态管理,集成 Pinia 持久化插件
- 使用 TypeScript 对 Axios 整个二次封装(请求拦截、取消、常用请求封装…)
- 使用 [tailwind](https://www.tailwindcss.cn/docs/installation) 作为 CSS 框架
- 使用 [TDesign](https://tdesign.tencent.com/)作为UI组件库
- 使用 VueRouter 进行路由权限拦截、页面按钮权限配置、路由懒加载
- 使用 KeepAlive 对页面进行缓存,支持多级嵌套页面缓存
- 常用自定义指令开发(权限、复制、水印、拖拽、节流、防抖、长按…)
- 使用 Prettier 统一格式化代码,集成 ESLint、Stylelint 代码校验规范
- 使用 husky、lint-staged、commitlint 规范提交信息
### 安装使用步骤 📔
- **Clone:**
```text
git clone ssh://git@code.seevin.com:8022/project-collaboration-platform/admin-web.git
```
- **Install:**
```text
pnpm install
```
- **Run:**
```text
pnpm dev
pnpm serve
```
- **Build:**
```text
# 开发环境
pnpm build:dev
# 测试环境
pnpm build
# 生产环境
pnpm build:prod
```
- **Lint:**
```text
# eslint 检测代码
pnpm lint:eslint
# prettier 格式化代码
pnpm lint:prettier
# stylelint 格式化样式
pnpm lint:stylelint
```
- **commit:**
```text
# 提交代码(提交前会自动执行lint-staged命令)
git add .
git commit -m 'feat: 新增xxx功能'
git push
```
### 文件资源目录 📚
```text
admin-web
├─ .husky # husky 配置文件
├─ .vscode # VSCode 推荐配置
├─ build # Vite 配置项
├─ public # 静态资源文件(该文件夹不会被打包)
├─ src
│ ├─ api # API 接口管理
│ ├─ assets # 静态资源文件
│ ├─ components # 全局组件
│ ├─ config # 全局配置项
│ ├─ directives # 全局指令文件
│ ├─ enums # 项目常用枚举
│ ├─ hooks # 常用 Hooks 封装
│ ├─ languages # 语言国际化 i18n
│ ├─ layouts # 框架布局模块
│ ├─ routers # 路由管理
│ ├─ stores # pinia store
│ ├─ styles # 全局样式文件
│ ├─ typings # 全局 ts 声明
│ ├─ utils # 常用工具库`
│ ├─ views # 项目所有页面
│ ├─ App.vue # 项目主组件
│ ├─ main.ts # 项目入口文件
│ └─ vite-env.d.ts # 指定 ts 识别 vue
├─ .editorconfig # 统一不同编辑器的编码风格
├─ .env # vite 常用配置
├─ .env.development # 开发环境配置
├─ .env.production # 生产环境配置
├─ .env.test # 测试环境配置
├─ .eslintignore # 忽略 Eslint 校验
├─ .eslintrc.cjs # Eslint 校验配置文件
├─ .gitignore # 忽略 git 提交
├─ .prettierignore # 忽略 Prettier 格式化
├─ .prettierrc.cjs # Prettier 格式化配置
├─ .stylelintignore # 忽略 stylelint 格式化
├─ stylelint.config.js # stylelint 样式规范配置文件
├─ CHANGELOG.md # 项目更新日志
├─ commitlint.config.cjs # git 提交规范配置
├─ index.html # 入口 html
├─ LICENSE # 开源协议文件
├─ package.json # 依赖包管理
├─ pnpm-lock.yaml # 依赖包管理
├─ postcss.config.cjs # postcss 配置
├─ README.md # README 介绍
├─ tsconfig.json # typescript 全局配置
├─ uno.config.ts # unocss 全局配置
└─ vite.config.ts # vite 全局配置文件
```
### 浏览器支持 🌎
- 本地开发推荐使用 Chrome 最新版浏览器 [Download](https://www.google.com/intl/zh-CN/chrome/)
- 生产环境支持现代浏览器,不再支持 IE 浏览器,更多浏览器可以查看 [Can I Use Es Module](https://caniuse.com/?search=ESModule)
| ![IE](https://i.imgtg.com/2023/04/11/8z7ot.png) | ![Edge](https://i.imgtg.com/2023/04/11/8zr3p.png) | ![Firefox](https://i.imgtg.com/2023/04/11/8zKiU.png) | ![Chrome](https://i.imgtg.com/2023/04/11/8zNrx.png) | ![Safari](https://i.imgtg.com/2023/04/11/8zeGj.png) |
| :---------------------------------------------: | :-----------------------------------------------: | :--------------------------------------------------: | :-------------------------------------------------: | :-------------------------------------------------: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
/*
* @Author: zhanyoulin<zhanyoulin456@163.com>
* @Date: 2023-06-23 11:04:27
* @LastEditors: zhanyoulin
* @LastEditTime: 2023-06-23 13:49:05
* @Description:
*/
import path from 'path'
export function isDevFn(mode: string): boolean {
return mode === 'development'
}
export function isProdFn(mode: string): boolean {
return mode === 'production'
}
export function isTestFn(mode: string): boolean {
return mode === 'test'
}
/**
* Whether to generate package preview
*/
export function isReportMode(): boolean {
return process.env.VITE_REPORT === 'true'
}
// Read all environment variable configuration files to process.env
export function wrapperEnv(envConf: Recordable): ViteEnv {
const ret: any = {}
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, '\n')
realName = realName === 'true' ? true : realName === 'false' ? false : realName
if (envName === 'VITE_PORT') realName = Number(realName)
if (envName === 'VITE_PROXY') {
try {
realName = JSON.parse(realName)
} catch (error) {
console.log(error)
}
}
ret[envName] = realName
}
return ret
}
/**
* Get user root directory
* @param dir file path
*/
export function getRootPath(...dir: string[]) {
return path.resolve(process.cwd(), ...dir)
}
import { resolve } from 'path'
import { PluginOption } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'
import { createHtmlPlugin } from 'vite-plugin-html'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import viteCompression from 'vite-plugin-compression'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { TDesignResolver } from 'unplugin-vue-components/resolvers'
import legacy from '@vitejs/plugin-legacy' // polyfill低版本谷歌浏览器
import checker from 'vite-plugin-checker'
/**
* 创建 vite 插件
* @param viteEnv
*/
export const createVitePlugins = (viteEnv: ViteEnv): (PluginOption | PluginOption[])[] => {
const { VITE_GLOB_APP_TITLE, VITE_REPORT } = viteEnv
return [
vue(),
// vue 可以使用 jsx/tsx 语法
vueJsx(),
// 创建打包压缩配置
createCompression(viteEnv),
// eslintPlugin(),
// 注入变量到 html 文件
createHtmlPlugin({
inject: {
data: { title: VITE_GLOB_APP_TITLE }
}
}),
// 使用 svg 图标
createSvgIconsPlugin({
iconDirs: [resolve(process.cwd(), 'src/assets/icons')],
symbolId: 'icon-[dir]-[name]'
}),
// 是否生成包预览,分析依赖包大小做优化处理
VITE_REPORT && (visualizer({ filename: 'stats.html', gzipSize: true, brotliSize: true }) as PluginOption),
AutoImport({
imports: ['vue', 'vue-router'],
resolvers: [
TDesignResolver({
library: 'vue-next'
})
],
dts: 'src/autoImport.d.ts'
}),
Components({
// allow auto load markdown components under `./src/components/`
extensions: ['vue', 'md'],
// allow auto import and register components used in markdown
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [
TDesignResolver({
library: 'vue-next'
})
],
dts: 'src/components.d.ts'
}),
legacy({
targets: ['defaults', 'not IE 11', 'chrome 68']
}),
checker({
typescript: true
})
]
}
/**
* @description 根据 compress 配置,生成不同的压缩规则
* @param viteEnv
*/
const createCompression = (viteEnv: ViteEnv): PluginOption | PluginOption[] => {
const { VITE_BUILD_COMPRESS = 'none', VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv
const compressList = VITE_BUILD_COMPRESS.split(',')
const plugins: PluginOption[] = []
if (compressList.includes('gzip')) {
plugins.push(
viteCompression({
ext: '.gz',
algorithm: 'gzip',
deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE
})
)
}
if (compressList.includes('brotli')) {
plugins.push(
viteCompression({
ext: '.br',
algorithm: 'brotliCompress',
deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE
})
)
}
return plugins
}
import type { ProxyOptions } from 'vite'
type ProxyItem = [string, string]
type ProxyList = ProxyItem[]
type ProxyTargetList = Record<string, ProxyOptions>
/**
* 创建代理,用于解析 .env.development 代理配置
* @param list
*/
export function createProxy(list: ProxyList = []) {
const ret: ProxyTargetList = {}
for (const [prefix, target] of list) {
const httpsRE = /^https:\/\//
const isHttps = httpsRE.test(target)
// https://github.com/http-party/node-http-proxy#options
ret[prefix] = {
target: target,
changeOrigin: true,
ws: true,
rewrite: path => path.replace(new RegExp(`^${prefix}`), ''),
// https is require secure=false
...(isHttps ? { secure: false } : {})
}
}
return ret
}
module.exports = {
extends: ['@commitlint/config-conventional'],
// 以下是我们自定义的规则
rules: {
'type-enum': [
2,
'always',
[
'bug', // 此项特别针对bug号,用于向测试反馈bug列表的bug修改情况
'feat', // 新功能(feature)
'fix', // 修补bug
'docs', // 文档(documentation)
'format', // 格式(不影响代码运行的变动)
'style', // 修改css样式
'refactor', // 重构(即不是新增功能,也不是修改bug的代码变动)
'test', // 增加测试
'chore', // 构建过程或辅助工具的变动
'revert', // feat(pencil): add ‘graphiteWidth’ option (撤销之前的commit)
'merge' // 合并分支, 例如: merge(前端页面)
]
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vue.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%- title %></title>
</head>
<body>
<div id="app">
<style>
html,
body,
#app {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.loading-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.loading-box .loading-wrap {
display: flex;
align-items: center;
justify-content: center;
padding: 98px;
}
.dot {
position: relative;
box-sizing: border-box;
display: inline-block;
width: 32px;
height: 32px;
font-size: 32px;
transform: rotate(45deg);
animation: ant-rotate 1.2s infinite linear;
}
.dot i {
position: absolute;
display: block;
width: 14px;
height: 14px;
background-color: var(--primary);
border-radius: 100%;
opacity: 0.3;
transform: scale(0.75);
transform-origin: 50% 50%;
animation: ant-spin-move 1s infinite linear alternate;
}
.dot i:nth-child(1) {
top: 0;
left: 0;
}
.dot i:nth-child(2) {
top: 0;
right: 0;
animation-delay: 0.4s;
}
.dot i:nth-child(3) {
right: 0;
bottom: 0;
animation-delay: 0.8s;
}
.dot i:nth-child(4) {
bottom: 0;
left: 0;
animation-delay: 1.2s;
}
@keyframes ant-rotate {
to {
transform: rotate(405deg);
}
}
@keyframes ant-spin-move {
to {
opacity: 1;
}
}
</style>
<div class="loading-box">
<div class="loading-wrap">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
</div>
</div>
<script>
const globalState = JSON.parse(window.localStorage.getItem('admin-global'))
if (globalState) {
const dot = document.querySelectorAll('.dot i')
const html = document.querySelector('html')
dot.forEach(item => (item.style.background = globalState.primary))
if (globalState.isDark) html.style.background = '#141414'
}
</script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
{
"name": "admin-web",
"private": true,
"version": "1.0.0",
"type": "module",
"description": "智慧教育后台管理系统",
"author": {
"name": "zhanyoulin",
"email": "zhanyoulin456@163.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://code.seevin.com/project-collaboration-platform/admin-web"
},
"scripts": {
"dev": "vite",
"serve": "vite",
"build": "vue-tsc --noEmit && vite build --mode test",
"build:prod": "vue-tsc --noEmit && vite build --mode production",
"type:check": "vue-tsc --noEmit --skipLibCheck",
"preview": "npm run build:dev && vite preview",
"lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
"lint:fix": "eslint --ext .vue,.js,jsx,.ts,.tsx ./ --max-warnings 0 --fix",
"prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
"stylelint": "stylelint src/**/*.{html,vue,sass,less}",
"stylelint:fix": "stylelint --fix src/**/*.{html,vue,css,sass,less}",
"prepare": "husky install",
"lint-staged": "lint-staged",
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"@types/vuedraggable": "^2.24.0",
"@vueuse/core": "^11.1.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^1.7.7",
"dayjs": "^1.11.13",
"js-md5": "^0.8.3",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"only-allow": "^1.2.1",
"pinia": "^2.2.4",
"pinia-plugin-persistedstate": "^3.2.0",
"qs": "^6.13.0",
"tdesign-icons-vue-next": "^0.2.6",
"tdesign-vue-next": "^1.10.4",
"vue": "^3.5.11",
"vue-router": "^4.4.5",
"vuedraggable": "^2.24.3"
},
"devDependencies": {
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@rushstack/eslint-patch": "^1.8.0",
"@types/js-md5": "^0.7.2",
"@types/lodash-es": "^4.17.12",
"@types/nprogress": "^0.2.3",
"@types/qs": "^6.9.16",
"@vitejs/plugin-legacy": "^4.0.5",
"@vitejs/plugin-vue": "4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/eslint-config-typescript": "^13.0.0",
"autoprefixer": "^10.4.20",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"husky": "^9.1.6",
"less": "^4.2.0",
"lint-staged": "^15.2.10",
"postcss": "^8.4.47",
"postcss-html": "^1.7.0",
"postcss-less": "^6.0.0",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"stylelint": "~16.2.1",
"stylelint-config-standard": "^36.0.0",
"stylelint-order": "~6.0.4",
"tailwindcss": "^3.4.13",
"typescript": "~5.4.0",
"unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4",
"vite": "4.5.5",
"vite-plugin-checker": "^0.8.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-html": "^3.2.2",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^2.1.6"
},
"engines": {
"node": ">=16.0.0",
"pnpm": ">=8.0.0"
},
"lint-staged": {
"src/**/*.{js,ts,vue,jsx,json}": [
"prettier --write",
"eslint --fix"
]
},
"browserslist": {
"production": [
"> 1%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"require": "./dist/index.js"
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论