Browse Source

docs: first init

pull/7/head
94dreamer 3 years ago
parent
commit
4d7177f80b
  1. 3
      .eslintignore
  2. 75
      .eslintrc
  3. 22
      PROXY.md
  4. 15
      cache.dockerfile
  5. 27
      index.html
  6. 91
      package.json
  7. 310
      src/components/setting.vue
  8. 101
      src/components/trend/index.vue
  9. 212
      src/config/color.ts
  10. 9
      src/config/global.js
  11. 35
      src/main.jsx
  12. 342
      src/pages/login/index.vue
  13. 208
      src/pages/user/index.vue
  14. 39
      src/store/modules/user.js
  15. 249
      src/style/variables.less
  16. 60
      vite.config.js

3
.eslintignore

@ -0,0 +1,3 @@
dist
node_modules
!.prettierrc.js

75
.eslintrc

@ -0,0 +1,75 @@
{
"extends": ["airbnb-base", "prettier", "plugin:@typescript-eslint/recommended", "plugin:vue/essential"],
"env": {
"browser": true,
"node": true,
"jest": true,
"es6": true
},
"globals": {
"cy": "readonly"
},
"plugins": ["vue", "@typescript-eslint"],
"parserOptions": {
"parser": "@typescript-eslint/parser",
"sourceType": "module",
"allowImportExportEverywhere": true,
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-require-imports": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/prefer-for-of": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"import/no-extraneous-dependencies": 0,
"import/extensions": 0,
"import/no-unresolved": 0,
"indent": [2, 2],
"camelcase": 0,
"class-methods-use-this": 0,
"new-cap": 0,
"no-new": 1,
"no-shadow": 0,
"no-console": 0,
"no-underscore-dangle": 0,
"no-confusing-arrow": 0,
"no-plusplus": [
"error",
{
"allowForLoopAfterthoughts": true
}
],
"func-style": 0,
"prefer-default-export": 0,
"max-len": 0,
"consistent-return": 0
},
"overrides": [
{
"files": ["*.vue"],
"rules": {
"vue/return-in-computed-property": 1,
"vue/order-in-components": 2,
"vue/component-name-in-template-casing": [2, "kebab-case"],
"vue/require-default-prop": 0,
"@typescript-eslint/explicit-module-boundary-types": "off",
"import/order": "off"
}
},
{
"files": ["src/*", "*.js"],
"rules": {
"no-var-requires": 0,
"no-console": 0,
"no-unused-expressions": 0,
"@typescript-eslint/explicit-module-boundary-types": "off",
"import/order": "off"
}
}
]
}

22
PROXY.md

@ -0,0 +1,22 @@
# TDesign starter 本地开发联调
## 工具准备
- 浏览器插件:[SwitchyOmega](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=zh-CNhttps://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=zh-CN)
- 调试代理工具:[whistle](https://wproxy.org/whistle/)
## 代理配置
`npm run dev`开启本地服务后,可以配置代理将线上域名的非后台 api 路径(如`/api`)的静态文件请求代理到本地,这样就可以进行本地联调和前端代码热更新了。
举例子:
```
/tdesign.tencent.com(?!\/api)/ 127.0.0.1:3001
```
其中:
- tdesign.tencent.com:修改你的线上域名
- /api:修改成后台请求路径
- 3001:修改成本地服务端口

15
cache.dockerfile

@ -0,0 +1,15 @@
# 选择一个 Base 镜像
FROM node:12
# 设置工作目录
WORKDIR /space
# 将 by 中的文件列表 COPY 过来
COPY . .
# 根据 COPY 过来的文件进行依赖的安装
RUN npm i
# 设置好需要的环境变量
ENV NODE_PATH=/space/node_modules

27
index.html

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn-go.cn/aegis/aegis-sdk/latest/aegis.min.18.js"></script>
<title>TDesign Starter</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.jsx"></script>
<script language="javascript">
if (window.location.host === 'tencent.tdesign.com') {
const aegis = new Aegis({
id: 'rDISNMyXckGLaZFQTK', // 项目ID,即上报key
reportAssetSpeed: true, // 静态资源测速
});
}
</script>
</body>
<script>
window.global = window;
</script>
</html>

91
package.json

@ -0,0 +1,91 @@
{
"name": "tdesign-vue2-starter",
"version": "0.0.1",
"scripts": {
"dev:mock": "vite --open --mode mock",
"dev": "vite --open --mode development",
"dev:linux": "vite --mode developmenet",
"build:test": "vite build --mode test",
"build": "vite build --mode release",
"serve": "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",
"stylelint": "stylelint src/**/*.{html,vue,sass,less}",
"stylelint:fix": "stylelint --cache --fix src/**/*.{html,vue,vss,sass,less}"
},
"dependencies": {
"@vitejs/plugin-legacy": "^1.5.3",
"dayjs": "^1.10.6",
"echarts": "^5.1.2",
"lint-staged": "^10.5.4",
"nprogress": "^0.2.0",
"qrcode.vue": "^1.7.0",
"tdesign-icons-vue": "0.0.4",
"tdesign-vue": "^0.28.2",
"typescript": "^4.2.4",
"vite-plugin-vue2-svg": "^0.1.8",
"vue": "^2.6.11",
"vuex": "^3.6.2"
},
"devDependencies": {
"@commitlint/cli": "^12.0.1",
"@commitlint/config-conventional": "^12.0.1",
"@rollup/plugin-dynamic-import-vars": "^1.1.1",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"axios": "^0.21.1",
"commitizen": "^4.2.3",
"eslint": "^7.22.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-vue": "^7.8.0",
"http-proxy-agent": "^4.0.1",
"husky": "^4.2.5",
"less": "^4.1.0",
"less-loader": "^7.2.1",
"less-vars-to-js": "^1.3.0",
"mockjs": "^1.1.0",
"prettier": "^2.3.2",
"stylelint": "^13.13.1",
"stylelint-config-airbnb": "0.0.0",
"stylelint-order": "^4.1.0",
"stylelint-scss": "^3.20.1",
"vite": "^2.6.14",
"vite-plugin-mock": "^2.3.0",
"vite-plugin-theme": "^0.8.1",
"vite-plugin-vue2": "^1.2.2",
"vue-clipboard2": "^0.3.1",
"vue-router": "^3.5.1",
"vuex-router-sync": "^5.0.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"prepare-commit-msg": "exec < /dev/tty && git cz --hook || true",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": [
"prettier --write",
"npm run lint:fix",
"git add"
],
"*.{html,vue,vss,sass,less}": [
"npm run stylelint:fix",
"git add"
]
},
"bit": {
"env": {},
"componentsDefaultDirectory": "components/{name}",
"packageManager": "npm"
}
}

310
src/components/setting.vue

@ -0,0 +1,310 @@
<template>
<div>
<t-drawer
size="458px"
:footer="false"
:visible.sync="showSettingPannel"
value="medium"
header="页面配置"
:closeBtn="true"
:onCloseBtnClick="handleCloseDrawer"
class="setting-drawer-container"
>
<div>
<t-form :data="formData" size="large" ref="form" labelAlign="left" @reset="onReset" @submit="onSubmit">
<div class="setting-group-title">主题模式</div>
<t-radio-group v-model="formData.mode" defaultVaule="dark">
<div v-for="(item, index) in modeOption" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item"><thumbnail :src="getThumbnailUrl(item)" /></t-radio-button>
</div>
</t-radio-group>
<div class="setting-group-title">主题色</div>
<t-radio-group v-model="formData.brandTheme" defaultVaule="default">
<div v-for="(item, index) in colorOption" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item" class="setting-layout-color-group"
><color-container :value="item" />
</t-radio-button>
</div>
</t-radio-group>
<div class="setting-group-title">导航布局</div>
<t-radio-group v-model="formData.layout" defaultVaule="top">
<div v-for="(item, index) in layoutOption" :key="index" class="setting-layout-drawer">
<t-radio-button :key="index" :value="item"><thumbnail :src="getThumbnailUrl(item)" /></t-radio-button>
</div>
</t-radio-group>
<!-- <t-form-item label="导航风格" name="theme" class="setting-route-theme">
<t-radio-group v-model="formData.theme" defaultVaule="light" variant="default-filled" size="small">
<t-radio-button value="light">明亮</t-radio-button>
<t-radio-button value="dark">暗黑</t-radio-button>
</t-radio-group>
</t-form-item> -->
<t-form-item v-show="formData.layout === 'mix'" label="分割菜单(混合模式下有效)" name="splitMenu">
<t-switch v-model="formData.splitMenu"></t-switch>
</t-form-item>
<t-form-item v-show="formData.layout !== 'side'" label="固定 Header" name="isHeaderFixed">
<t-switch v-model="formData.isHeaderFixed"></t-switch>
</t-form-item>
<t-form-item v-show="formData.layout !== 'top'" label="固定 Sidebar" name="isSidebarFixed">
<t-switch v-model="formData.isSidebarFixed"></t-switch>
</t-form-item>
<div class="setting-group-title">元素开关</div>
<t-form-item label="显示 Header" name="showHeader" v-show="formData.layout === 'side'">
<t-switch v-model="formData.showHeader"></t-switch>
</t-form-item>
<t-form-item label="显示 Breadcrumbs" name="showBreadcrumb">
<t-switch v-model="formData.showBreadcrumb"></t-switch>
</t-form-item>
<t-form-item label="显示 Footer" name="showFooter">
<t-switch v-model="formData.showFooter"></t-switch>
</t-form-item>
<t-form-item
label="footer 内收"
name="footerPosition"
v-show="formData.showFooter && !formData.isSidebarFixed"
>
<t-switch v-model="formData.isFooterAside"></t-switch>
</t-form-item>
</t-form>
<div class="setting-info">
<p>请复制后手动修改配置文件: /src/config/style.js</p>
<t-button theme="primary" variant="text" @click="handleCopy">复制配置项</t-button>
</div>
</div>
</t-drawer>
<t-button class="tdesign-setting" shape="circle" theme="primary" @click="handleClick" v-show="showSettingBtn">
<t-icon name="setting" size="24px" slot="icon" />
<span class="tdesign-setting-text">页面配置</span>
</t-button>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import STYLE_CONFIG from '@/config/style';
import Thumbnail from '@/components/thumbnail/index.vue';
import ColorContainer from '@/components/color.vue';
export default {
name: 'DefaultLayoutSetting',
components: { Thumbnail, ColorContainer },
data() {
return {
modeOption: ['light', 'dark', 'auto'],
layoutOption: ['side', 'top', 'mix'],
colorOption: ['default', 'purple', 'cyan', 'green', 'yellow', 'orange', 'red', 'pink'],
visible: false,
formData: { ...STYLE_CONFIG },
};
},
computed: {
...mapGetters('setting', ['showSettingBtn']),
showSettingPannel: {
get() {
return this.$store.state.setting.showSettingPannel;
},
set(newVal) {
this.$store.commit('setting/toggleSettingPannel', newVal);
},
},
iconName() {
return this.visible ? 'close' : 'setting';
},
showOthers() {
return (this.formData.showFooter && !this.formData.isSidebarFixed) || !this.formData.splitMenu;
},
},
watch: {
formData: {
handler(newVal) {
this.$store.dispatch('setting/changeTheme', newVal);
},
deep: true,
},
},
methods: {
onReset() {
this.formData = {
...STYLE_CONFIG,
};
this.$message.success('已恢复初始设置');
},
onSubmit({ result, firstError, e }) {
e.preventDefault();
if (result === true) {
this.visible = false;
} else {
this.$message.warning(firstError);
}
},
getThumbnailUrl(name) {
return `https://tdesign.gtimg.com/starter/setting/${name}.png`;
},
handleClick() {
this.$store.commit('setting/toggleSettingPannel', true);
// this.visible = !this.visible;
},
handleCloseDrawer() {
this.$store.commit('setting/toggleSettingPannel', false);
},
handleCopy() {
const text = JSON.stringify(this.formData, null, 4);
this.$copyText(text).then(() => {
this.$message.closeAll();
this.$message.success('复制成功');
});
},
},
};
</script>
<style lang="less">
@import '@/style/index.less';
.tdesign-setting {
z-index: 100;
position: fixed;
bottom: 200px;
right: 0;
transition: transform .3s cubic-bezier(.7, .3, .1, 1), visibility .3s cubic-bezier(.7, .3, .1, 1);
height: 40px;
width: 40px;
border-radius: 20px 0 0 20px;
transition: all .3s;
.t-icon {
margin-left: 8px;
}
.tdesign-setting-text {
font-size: 12px;
display: none;
}
&:hover {
width: 96px;
.tdesign-setting-text {
display: inline-block;
}
}
}
.setting-layout-color-group {
display: inline-flex;
width: 42px;
height: 42px;
justify-content: center;
align-items: center;
border-radius: 50% !important;
border: 2px solid transparent !important;
> .t-radio-button__label {
display: inline-flex;
}
}
.tdesign-setting-close {
position: fixed;
bottom: 200px;
right: 300px;
}
.setting-group-title {
font-size: 14px;
line-height: 22px;
margin: 32px 0 24px 0;
text-align: left;
font-family: PingFang SC;
font-style: normal;
font-weight: 500;
color: @text-color-primary;
}
.setting-link {
cursor: pointer;
color: @brand-color;
margin-bottom: 8px;
}
.setting-info {
position: absolute;
bottom: 24px;
line-height: 20px;
font-size: 12px;
text-align: center;
color: @text-color-placeholder;
width: 100%;
}
.setting-drawer-container {
.t-radio-group.t-radio-group-medium {
min-height: 32px;
width: 100%;
height: auto;
justify-content: space-between;
align-items: center;
}
.setting-layout-drawer {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 16px;
.t-radio-button {
display: inline-flex;
max-height: 78px;
padding: 6px !important;
border-radius: @border-radius;
border: 2px solid #e3e6eb;
// &:last-child {
// border-right: 2px solid transparent;
// }
> .t-radio-button__label {
display: inline-flex;
}
}
.t-is-checked {
border: 2px solid @brand-color !important;
}
.t-form__controls--content {
justify-content: end;
}
}
.t-form__controls--content {
justify-content: end;
}
}
.setting-route-theme {
.t-form__label {
min-width: 310px !important;
color: @text-color-secondary;
}
}
.setting-color-theme {
.setting-layout-drawer {
.t-radio-button {
height: 32px;
}
&:last-child {
margin-right: 0;
}
}
}
</style>

101
src/components/trend/index.vue

@ -0,0 +1,101 @@
<template>
<span :class="containerCls">
<span :class="iconCls">
<svg
v-if="type === 'up'"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M11.5 8L8 11.5L4.5 8" stroke="currentColor" stroke-width="1.5" />
<path d="M8 11L8 4" stroke="currentColor" stroke-width="1.5" />
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" v-else>
<path d="M4.5 8L8 4.5L11.5 8" stroke="currentColor" stroke-width="1.5" />
<path d="M8 5V12" stroke="currentColor" stroke-width="1.5" />
</svg>
</span>
<span>{{ describe }}</span>
</span>
</template>
<script>
export default {
name: 'trend',
props: {
type: String,
describe: [String, Number],
isReverseColor: Boolean,
},
computed: {
containerCls() {
return [
'trend-container',
{
'trend-container__reverse': this.isReverseColor,
'trend-container__up': !this.isReverseColor && this.type === 'up',
'trend-container__down': !this.isReverseColor && this.type === 'down',
},
];
},
iconCls() {
return ['trend-icon-container'];
},
},
};
</script>
<style lang="less" scoped>
@import '@/style/variables.less';
.trend {
&-container {
&__up {
color: #e34d59 !important;
display: inline-flex;
align-items: center;
justify-content: center;
.trend-icon-container {
background: #f9d7d9;
margin-right: 8px;
}
}
&__down {
color: #00a870 !important;
display: inline-flex;
align-items: center;
justify-content: center;
.trend-icon-container {
background: #bcebdc;
margin-right: 8px;
}
}
&__reverse {
color: #ffffff !important;
display: inline-flex;
align-items: center;
justify-content: center;
.trend-icon-container {
background: @brand-color-5;
margin-right: 8px;
}
}
.trend-icon-container {
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
}
}
}
</style>

212
src/config/color.ts

@ -0,0 +1,212 @@
type ColorToken = Record<string, string>;
type ColorSeries = Record<string, ColorToken>;
const BACKGROUND_TOKEN: ColorSeries = {
BLUE_GREY: {
'@gray-color-1': '#F1F2F5',
'@gray-color-2': '#EBEDF1',
'@gray-color-3': '#E3E6EB',
'@gray-color-4': '#D6DBE3',
'@gray-color-5': '#BCC4D0',
'@gray-color-6': '#97A3B7',
'@gray-color-7': '#7787A2',
'@gray-color-8': '#5F7292',
'@gray-color-9': '#4B5B76',
'@gray-color-10': '#3C485C',
'@gray-color-11': '#2C3645',
'@gray-color-12': '#232A35',
'@gray-color-13': '#1C222B',
'@gray-color-14': '#13161B',
},
NEUTRAL_GREY: {
'@gray-color-1': '#F3F3F3',
'@gray-color-2': '#EEEEEE',
'@gray-color-3': '#E7E7E7',
'@gray-color-4': '#DCDCDC',
'@gray-color-5': '#C5C5C5',
'@gray-color-6': '#A6A6A6',
'@gray-color-7': '#8B8B8B',
'@gray-color-8': '#777777',
'@gray-color-9': '#5E5E5E',
'@gray-color-10': '#4B4B4B',
'@gray-color-11': '#383838',
'@gray-color-12': '#2C2C2C',
'@gray-color-13': '#242424',
'@gray-color-14': '#181818',
},
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const NEUTRAL_GREY_TOKEN: ColorToken = {
'@gray-color-1': '#F3F3F3',
'@gray-color-2': '#EEEEEE',
'@gray-color-3': '#E7E7E7',
'@gray-color-4': '#DCDCDC',
'@gray-color-5': '#C5C5C5',
'@gray-color-6': '#A6A6A6',
'@gray-color-7': '#8B8B8B',
'@gray-color-8': '#777777',
'@gray-color-9': '#5E5E5E',
'@gray-color-10': '#4B4B4B',
'@gray-color-11': '#383838',
'@gray-color-12': '#2C2C2C',
'@gray-color-13': '#242424',
'@gray-color-14': '#181818',
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const DEFAULT_TOKEN: ColorToken = {
'@brand-color': '#0052D9',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const PURPLE_TOKEN: ColorToken = {
'@brand-color': '#834ec2',
'@brand-color-1': '#f3e0ff',
'@brand-color-2': '#e6c4ff',
'@brand-color-3': '#d8abff',
'@brand-color-4': '#c68cff',
'@brand-color-5': '#ae78f0',
'@brand-color-6': '#9963d8',
'@brand-color-7': '#834ec2',
'@brand-color-8': '#6d3bac',
'@brand-color-9': '#572796',
'@brand-color-10': '#421381',
};
const COLOR_TOKEN: ColorSeries = {
DEFAULT: {
'@brand-color': '#0052D9',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
CYAN: {
'@brand-color': '#0594FA',
'@brand-color-1': '#D6F7FF',
'@brand-color-2': '#85DAFF',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
GREEN: {
'@brand-color': '#00A870',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
ORANGE: {
'@brand-color': '#ED7B2F',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
RED: {
'@brand-color': '#E34D59',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
PINK: {
'@brand-color': '#ED49B4',
'@brand-color-1': '#ECF2FE',
'@brand-color-2': '#D4E3FC',
'@brand-color-3': '#BBD3FB',
'@brand-color-4': '#96BBF8',
'@brand-color-5': '#699EF5',
'@brand-color-6': '#4787F0',
'@brand-color-7': '#266FE8',
'@brand-color-8': '#0052D9',
'@brand-color-9': '#0034B5',
'@brand-color-10': '#001F97',
},
PURPLE: {
'@brand-color': '#834ec2',
'@brand-color-1': '#f3e0ff',
'@brand-color-2': '#e6c4ff',
'@brand-color-3': '#d8abff',
'@brand-color-4': '#c68cff',
'@brand-color-5': '#ae78f0',
'@brand-color-6': '#9963d8',
'@brand-color-7': '#834ec2',
'@brand-color-8': '#6d3bac',
'@brand-color-9': '#572796',
'@brand-color-10': '#421381',
},
YELLOW: {
'@brand-color': '#ebb105',
'@brand-color-1': '#fff8b8',
'@brand-color-2': '#ffe478',
'@brand-color-3': '#fbca25',
'@brand-color-4': '#ebb105',
'@brand-color-5': '#d29c00',
'@brand-color-6': '#ba8700',
'@brand-color-7': '#a37200',
'@brand-color-8': '#8c5f00',
'@brand-color-9': '#754c00',
'@brand-color-10': '#5e3a00',
},
};
function toUnderline(name: string): string {
return name.replace(/([A-Z])/g, '_$1').toUpperCase();
}
export function getGreyColor(type: string): ColorToken {
const name = toUnderline(type);
return BACKGROUND_TOKEN[name] || {};
}
export function getBrandColor(type: string): ColorToken {
const name = toUnderline(type);
return COLOR_TOKEN[name] || COLOR_TOKEN.DEFAULT;
}
export function getColorList(colorArray: [ColorToken]): string[] {
const pureColorList = [];
colorArray.map((colorToken) => Object.keys(colorToken).map((key) => pureColorList.push(colorToken[key])));
return pureColorList;
}

9
src/config/global.js

@ -0,0 +1,9 @@
export const prefix = 'tdesign-starter';
export const theme = 'light';
export const authenticationMethod = 'customize';
export default {
prefix,
theme,
authenticationMethod,
};

35
src/main.jsx

@ -0,0 +1,35 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import { sync } from 'vuex-router-sync';
import TDesign from 'tdesign-vue/esm';
import VueClipboard from 'vue-clipboard2';
import axiosInstance from '@/utils/request';
import App from './App.vue';
import router from './router';
import TDesignPageHeader from './components/page-header.vue';
import '@/style/index.less';
import './permisson';
import store from './store';
Vue.use(VueRouter);
Vue.use(TDesign);
Vue.use(VueClipboard);
Vue.component('t-page-header', TDesignPageHeader);
Vue.prototype.$request = axiosInstance;
Vue.config.productionTip = false;
sync(store, router);
new Vue({
router,
store,
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line @typescript-eslint/no-unused-vars
render: (h) => (
<div>
<App />
</div>
),
}).$mount('#app');

342
src/pages/login/index.vue

@ -0,0 +1,342 @@
<template>
<div class="login-wrapper">
<div class="login-container">
<div class="title-container">
<img class="icon" src="https://tdesign.gtimg.com/starter/logo%402x.png" />
<div class="side-title" v-show="loginStep !== 'login-step4' && loginStep !== 'login-step5'">
<p class="tip1">没有账号吗?</p>
<p class="tip2" @click="toLoginStep('login-step4')">注册新账号</p>
</div>
<div class="side-title" v-show="loginStep === 'login-step4' || loginStep === 'login-step5'">
<p class="tip1">已有账号吗?</p>
<p class="tip2" @click="toLoginStep('login-step1')">登录</p>
</div>
</div>
<div class="login-step1" v-show="loginStep == 'login-step1'">
<div class="input-container">
<t-input style="width: 400px" size="large" v-model="userInfo.EngName" placeholder="请输入您的邮箱/手机号">
<t-icon name="user" slot="prefix-icon" />
</t-input>
<t-popup placement="right" trigger="focus" showArrow>
<t-input
style="width: 400px"
size="large"
:type="showPsw ? 'text' : 'password'"
clearablec
placeholder="请输入密码"
v-model="psw"
@keyup="checkPsw"
>
<t-icon name="lock-on" slot="prefix-icon"></t-icon>
<t-icon @click="showPsw = !showPsw" slot="suffix-icon" :name="showPsw ? 'browse' : 'browse-off'" />
</t-input>
<template #content>
<div>
<div :class="['rex-check', { 'format-correct': check1 }]">
<t-icon name="check-circle-filled" size="large" />
<span>1-20个英文字符</span>
</div>
<div :class="['rex-check', { 'format-correct': check2 }]">
<t-icon name="check-circle-filled" size="large" />
<span>需包含下划线</span>
</div>
</div>
</template>
</t-popup>
<div class="check-container">
<t-checkbox>记住账号</t-checkbox>
<span class="tip">忘记账号</span>
</div>
<div class="button-container">
<t-button style="width: 400px" size="large" @click="toLogin">登录</t-button>
</div>
</div>
<div class="bottom-container">
<span class="tip" @click="toLoginStep('login-step3')">使用微信扫码登录</span>
<i>|</i>
<span class="tip" @click="toLoginStep('login-step6')">使用短信登录</span>
</div>
</div>
<!-- <div class="login-step2" v-show="loginStep == 'login-step2'">
<div class="input-container">
<div class="tip-container">
<span class="tip1" @click="toLoginStep('login-step1')">
<t-icon name="arrow-left" style="color: #0052d9" />
返回
</span>
<span class="tip2">忘记账号</span>
</div>
<t-input type="password" size="large">
<t-icon name="lock-on" slot="prefix-icon" />
</t-input>
<div class="button-container">
<t-button block variant="base" size="large" style="width: 400px" @click="toLogin">登录</t-button>
</div>
</div>
</div> -->
<div class="login-step3" v-show="loginStep == 'login-step3'">
<div class="input-container">
<div class="tip-container">
<span class="tip1">请使用微信扫一扫登录</span>
<span class="tip2">刷新 <t-icon name="refresh" color="#0052D9" /> </span>
</div>
<qrcode-vue value="https://tencent.tdesign.com/vue/components/quick-start" :size="192" level="H" />
</div>
<div class="bottom-container">
<span class="tip" @click="toLoginStep('login-step1')">使用账号密码登录</span>
<i>|</i>
<span class="tip" @click="toLoginStep('login-step6')">使用短信登录</span>
</div>
</div>
<div class="login-step4" v-show="loginStep == 'login-step4'">
<div class="input-container">
<t-input style="width: 400px" size="large" v-model="userInfo.EngName" placeholder="请输入您的手机号">
<t-icon name="user" slot="prefix-icon" />
</t-input>
<t-popup placement="right" trigger="focus" showArrow>
<t-input
style="width: 400px"
size="large"
:type="showPsw ? 'text' : 'password'"
clearablec
placeholder="请输入登录密码"
v-model="psw"
@keyup="checkPsw"
>
<t-icon name="lock-on" slot="prefix-icon"></t-icon>
<t-icon @click="showPsw = !showPsw" slot="suffix-icon" :name="showPsw ? 'browse' : 'browse-off'" />
</t-input>
<template #content>
<div>
<div :class="['rex-check', { 'format-correct': check1 }]">
<t-icon name="check-circle-filled" size="large" />
<span>1-20个英文字符</span>
</div>
<div :class="['rex-check', { 'format-correct': check2 }]">
<t-icon name="check-circle-filled" size="large" />
<span>需包含下划线</span>
</div>
</div>
</template>
</t-popup>
<div class="verification-code">
<t-input style="width: 282px" size="large" placeholder="请输入验证码" />
<t-button v-if="captchaSent" variant="outline" disabled>
{{ countDownText }}
</t-button>
<t-button v-else @click="waitCodeNumCount" variant="outline"> 发送验证码 </t-button>
</div>
<div class="check-container">
<t-checkbox>我已阅读并同意 <span>TDesign服务协议</span> <span>TDesign 隐私声明</span></t-checkbox>
</div>
<div class="button-container">
<t-button style="width: 400px" size="large" @click="toLogin">注册</t-button>
</div>
</div>
<div class="bottom-container">
<span class="tip" @click="toLoginStep('login-step5')">使用邮箱注册</span>
</div>
</div>
<div class="login-step5" v-show="loginStep == 'login-step5'">
<div class="input-container">
<t-select
v-model="userInfo.EngName"
placeholder="请输入您的邮箱"
filterable
style="width: 400px"
size="large"
:empty="''"
:options="emailOptions"
:onSearch="remoteMethod"
>
<template #t-input>
<t-icon name="lock-on" slot="prefix-icon"></t-icon>
</template>
</t-select>
<t-popup placement="right" trigger="focus" showArrow>
<t-input
style="width: 400px"
size="large"
:type="showPsw ? 'text' : 'password'"
clearablec
placeholder="请输入登录密码"
v-model="psw"
@keyup="checkPsw"
>
<t-icon name="lock-on" slot="prefix-icon"></t-icon>
<t-icon @click="showPsw = !showPsw" slot="suffix-icon" :name="showPsw ? 'browse' : 'browse-off'" />
</t-input>
<template #content>
<div>
<div :class="['rex-check', { 'format-correct': check1 }]">
<t-icon name="check-circle-filled" size="large" />
<span>1-20个英文字符</span>
</div>
<div :class="['rex-check', { 'format-correct': check2 }]">
<t-icon name="check-circle-filled" size="large" />
<span>需包含下划线</span>
</div>
</div>
</template>
</t-popup>
<div class="check-container">
<t-checkbox>我已阅读并同意 <span>TDesign服务协议</span> <span>TDesign 隐私声明</span></t-checkbox>
</div>
<div class="button-container">
<t-button style="width: 400px" size="large" @click="toLogin">注册</t-button>
</div>
</div>
<div class="bottom-container">
<span class="tip" @click="toLoginStep('login-step4')">使用手机号注册</span>
</div>
</div>
<div class="login-step6" v-show="loginStep == 'login-step6'">
<div class="input-container">
<t-input style="width: 400px" size="large" v-model="userInfo.EngName" placeholder="请输入您的手机号">
<t-icon name="user" slot="prefix-icon" />
</t-input>
<div class="verification-code">
<t-input style="width: 282px" size="large" placeholder="请输入验证码" />
<t-button v-if="captchaSent" variant="outline" disabled>
{{ countDownText }}
</t-button>
<t-button v-else @click="waitCodeNumCount" variant="outline"> 发送验证码 </t-button>
</div>
<div class="button-container">
<t-button style="width: 400px" size="large" @click="toLogin">登录</t-button>
</div>
</div>
<div class="bottom-container">
<span class="tip" @click="toLoginStep('login-step1')">使用账号密码登录</span>
<i>|</i>
<span class="tip" @click="toLoginStep('login-step3')">使用微信扫码登录</span>
</div>
</div>
</div>
</div>
</template>
<script>
//
import './index.less';
import QrcodeVue from 'qrcode.vue';
/** 高级详情 */
export default {
name: 'login-index',
components: { QrcodeVue },
data() {
return {
loginStep: 'login-step1',
userInfo: {
EngName: '',
DeptNameString: '测试部门',
},
src2: 'https://tencent.tdesign.com/vue/components/quick-start',
showPsw: false,
psw: '',
check1: false,
check2: false,
countDown: 60,
countDownText: '59s后重发',
timer: null,
captchaSent: false,
emailOptions: [],
};
},
watch: {
loginStep() {
this.userInfo.EngName = '';
this.psw = '';
},
},
mounted() {
// 使退
this.userInfo = {
EngName: this.$store.state.user.loginName,
DeptNameString: this.$store.state.user.deptNameString,
};
},
methods: {
nextStep() {
this.loginStep = 'login-step2';
},
checkPsw() {
const regExp = /^[a-z0-9_]{1,20}$/;
if (regExp.test(this.psw)) {
this.check1 = true;
} else {
this.check1 = false;
}
if (this.psw.indexOf('_') !== -1) {
this.check2 = true;
} else {
this.check2 = false;
}
},
toLogin() {
this.$store.commit('user/SET_USER_INFO', this.userInfo);
this.$router.push({
path: '/',
});
},
toLoginStep(login_step) {
this.loginStep = login_step;
},
//
waitCodeNumCount() {
this.captchaSent = true;
// 60
if (!this.timer) {
this.timer = setInterval(() => {
if (this.countDown > 0 && this.countDown <= 60) {
this.countDown -= 1;
if (this.countDown !== 0) {
this.countDownText = `${this.countDown}s后重发`;
} else {
clearInterval(this.timer);
this.countDown = 60;
this.countDownText = '59秒后可重发';
this.captchaSent = false;
this.timer = null;
}
}
}, 1000);
}
},
remoteMethod(search) {
if (search && search.indexOf('@') === -1) {
this.emailOptions = [
{
value: `${search}@qq.com`,
label: `${search}@qq.com`,
},
{
value: `${search}@gmail.com`,
label: `${search}@gmail.com`,
},
{
value: `${search}@126.com`,
label: `${search}@126.com`,
},
{
value: `${search}@163.com`,
label: `${search}@163.com`,
},
{
value: `${search}@hotmail.com`,
label: `${search}@hotmail.com`,
},
{
value: `${search}@21cn.com`,
label: `${search}@21cn.com`,
},
{
value: `${search}@yahoo.com`,
label: `${search}@yahoo.com`,
},
];
}
},
},
};
</script>

208
src/pages/user/index.vue

@ -0,0 +1,208 @@
<template>
<div>
<!-- <t-page-header>个人中心1111</t-page-header> -->
<div class="user-panel">
<t-row>
<t-col class="user-left-panel" :flex="3">
<div class="user-top">
<div class="user-left-greeting">
HiImage
<span class="regular"> 下午好今天是你加入鹅厂的第 100 </span>
<img src="@/assets/tencent-logo.png" class="user-left-logo" />
</div>
<div class="user-right-info">
<div class="head-bar">
<div class="title">个人信息</div>
<t-icon name="edit" size="18" />
</div>
<t-row class="content" justify="space-between">
<t-col class="contract" :span="3">
<div class="contract-title">手机</div>
<div class="contract-detail">+86 13923734567</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">座机</div>
<div class="contract-detail">734567</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">办公邮箱</div>
<div class="contract-detail">Account@qq.com</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">座位</div>
<div class="contract-detail">T32F 012</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">管理主体</div>
<div class="contract-detail">腾讯集团</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">直属上级</div>
<div class="contract-detail">Account@qq.com</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">职位</div>
<div class="contract-detail">高级 UI 设计师</div>
</t-col>
<t-col class="contract" :span="3">
<div class="contract-title">入职时间</div>
<div class="contract-detail">2021-07-01</div>
</t-col>
<t-col class="contract" :span="6">
<div class="contract-title">所属团队</div>
<div class="contract-detail">腾讯/腾讯公司/某事业群/某产品部/某运营中心/商户服务组</div>
</t-col>
</t-row>
</div>
</div>
<div class="user-bottom">
<div class="t-demo-tabs">
<t-tabs value="second">
<t-tab-panel value="first" label="内容列表">
<p style="padding: 25px">内容列表</p>
</t-tab-panel>
<t-tab-panel value="second" label="内容列表">
<div class="user-bottom-container">
<div class="head-bar">
<div class="title">主页访问数据<span class="unit"></span></div>
<t-date-picker
class="time-picker"
:defaultValue="LAST_7_DAYS"
theme="primary"
mode="date"
range
@change="onLineChange"
></t-date-picker>
</div>
<div id="lineContainer" style="width: 100%; height: 330px"></div>
</div>
</t-tab-panel>
<t-tab-panel value="third" label="内容列表">
<p style="padding: 25px">内容列表</p>
</t-tab-panel>
</t-tabs>
</div>
</div>
</t-col>
<t-col class="user-right-panel" :flex="1">
<div class="user-top">
<div class="account">
<img class="img" src="https://tdesign.gtimg.com/starter/personal/avatar4.png" />
<div class="name">My Account</div>
<div class="position">XXXG 港澳业务拓展组员工 直客销售</div>
</div>
</div>
<div class="user-middle">
<div class="head-bar">
<div class="title">团队成员</div>
<t-icon name="edit" size="18" />
</div>
<t-list :split="false">
<t-list-item>
<t-list-item-meta
avatar="https://tdesign.gtimg.com/starter/personal/avatar5.png"
title="Lovellzhang 张庆霖"
description="直客销售 港澳拓展组员工"
></t-list-item-meta>
</t-list-item>
<t-list-item>
<t-list-item-meta
avatar="https://tdesign.gtimg.com/starter/personal/avatar1.png"
title="Jiajingwang 王佳静"
description="前端开发 前台研发组员工 "
></t-list-item-meta>
</t-list-item>
<t-list-item>
<t-list-item-meta
avatar="https://tdesign.gtimg.com/starter/personal/avatar2.png"
title="cruisezhang 张超"
description="技术产品 产品组员工"
></t-list-item-meta>
</t-list-item>
<t-list-item>
<t-list-item-meta
avatar="https://tdesign.gtimg.com/starter/personal/avatar3.png"
title="Tobchen 陈超建"
description="产品运营 港澳拓展组员工"
></t-list-item-meta>
</t-list-item>
</t-list>
</div>
<div class="user-bottom">
<div class="head-bar">
<div class="title">服务产品</div>
<t-icon name="edit" size="18" />
</div>
<t-row class="content" justify="space-between">
<t-col class="contract" :span="4">
<img src="https://tdesign.gtimg.com/starter/tdesign-icon1.png" class="user-right-logo" />
</t-col>
<t-col class="contract" :span="4">
<img src="https://tdesign.gtimg.com/starter/tdesign-icon2.png" class="user-right-logo" />
</t-col>
<t-col class="contract" :span="4">
<img src="https://tdesign.gtimg.com/starter/tdesign-icon3.png" class="user-right-logo" />
</t-col>
</t-row>
</div>
</t-col>
</t-row>
</div>
</div>
</template>
<script>
import { prefix } from '@/config/global';
//
import './index.less';
import { LAST_7_DAYS } from '@/utils/date.ts';
import * as echarts from 'echarts/core';
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
import { LineChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
import { getFolderlineDataSet } from '@/pages/dashboard-base/index';
echarts.use([GridComponent, TooltipComponent, LineChart, CanvasRenderer, LegendComponent]);
export default {
data() {
return {
prefix,
dashboardBase: '',
lineContainer: '',
lineChart: '',
LAST_7_DAYS,
};
},
mounted() {
if (!this.lineContainer) {
this.lineContainer = document.getElementById('lineContainer');
}
this.lineChart = echarts.init(this.lineContainer);
this.lineChart.setOption({
grid: {
x: 30, // 80px
y: 30, // 60px
x2: 10, // 80px
y2: 30, // 60px
},
...getFolderlineDataSet(),
});
window.addEventListener('resize', this.updateContainer, false);
},
methods: {
/** 图表选择 */
onLineChange(value) {
this.lineChart.setOption(getFolderlineDataSet(value));
},
updateContainer() {
this.lineChart.resize({
width: this.lineContainer.clientWidth,
height: this.lineContainer.clientHeight,
});
},
},
};
</script>

39
src/store/modules/user.js

@ -0,0 +1,39 @@
// 定义的state初始值
const state = {
loginName: '',
deptNameString: '',
};
// 定义的state的初始值方法,传入state或者额外的方法,然后利用vuex的双向数据驱动进行值的改变
// 可通过this.$store.commit(' ')调用,但是触发的是同步事件
const mutations = {
SET_USER_INFO(state, userInfo) {
// eslint-disable-next-line no-param-reassign
state.loginName = userInfo.EngName;
// eslint-disable-next-line no-param-reassign
state.deptNameString = userInfo.DeptNameString;
},
};
// 使用actions的好处在于不会触发同步时间,而是异步事件
// actions里面自定义的函数接收一个context参数和要变化的形参,context与store实例具有相同的方法和属性,所以它可以执行context.commit(' ')
const actions = {
// 获取用户信息
async getUserInfo() {
try {
console.log('当前编译环境');
console.log(process.env.NODE_ENV);
} catch (err) {
// 弹框提示错误信息
console.log(`智能网关获取用户信息错误:${err.message}`);
// Message.error({ message: `获取用户信息错误:${err.message}`, closeBtn: true });
}
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};

249
src/style/variables.less

@ -0,0 +1,249 @@
/** 公共前缀 */
@prefix: tdesign-starter;
// 颜色色板
@brand-color-1: var(--td-brand-color-1);
@brand-color-2: var(--td-brand-color-2);
@brand-color-3: var(--td-brand-color-3);
@brand-color-4: var(--td-brand-color-4);
@brand-color-5: var(--td-brand-color-5);
@brand-color-6: var(--td-brand-color-6);
@brand-color-7: var(--td-brand-color-7);
@brand-color-8: var(--td-brand-color-8);
@brand-color-9: var(--td-brand-color-9);
@brand-color-10: var(--td-brand-color-10);
@warning-color-1: var(--td-warning-color-1);
@warning-color-2: var(--td-warning-color-2);
@warning-color-3: var(--td-warning-color-3);
@warning-color-4: var(--td-warning-color-4);
@warning-color-5: var(--td-warning-color-5);
@warning-color-6: var(--td-warning-color-6);
@warning-color-7: var(--td-warning-color-7);
@warning-color-8: var(--td-warning-color-8);
@warning-color-9: var(--td-warning-color-9);
@warning-color-10: var(--td-warning-color-10);
@error-color-1: var(--td-error-color-1);
@error-color-2: var(--td-error-color-2);
@error-color-3: var(--td-error-color-3);
@error-color-4: var(--td-error-color-4);
@error-color-5: var(--td-error-color-5);
@error-color-6: var(--td-error-color-6);
@error-color-7: var(--td-error-color-7);
@error-color-8: var(--td-error-color-8);
@error-color-9: var(--td-error-color-9);
@error-color-10: var(--td-error-color-10);
@success-color-1: var(--td-success-color-1);
@success-color-2: var(--td-success-color-2);
@success-color-3: var(--td-success-color-3);
@success-color-4: var(--td-success-color-4);
@success-color-5: var(--td-success-color-5);
@success-color-6: var(--td-success-color-6);
@success-color-7: var(--td-success-color-7);
@success-color-8: var(--td-success-color-8);
@success-color-9: var(--td-success-color-9);
@success-color-10: var(--td-success-color-10);
@gray-color-1: var(--td-gray-color-1);
@gray-color-2: var(--td-gray-color-2);
@gray-color-3: var(--td-gray-color-3);
@gray-color-4: var(--td-gray-color-4);
@gray-color-5: var(--td-gray-color-5);
@gray-color-6: var(--td-gray-color-6);
@gray-color-7: var(--td-gray-color-7);
@gray-color-8: var(--td-gray-color-8);
@gray-color-9: var(--td-gray-color-9);
@gray-color-10: var(--td-gray-color-10);
@gray-color-11: var(--td-gray-color-11);
@gray-color-12: var(--td-gray-color-12);
@gray-color-13: var(--td-gray-color-13);
@gray-color-14: var(--td-gray-color-14);
// 文字 & 图标 颜色
@font-white-1: var(--td-font-white-1);
@font-white-2: var(--td-font-white-2);
@font-white-3: var(--td-font-white-3);
@font-white-4: var(--td-font-white-4);
@font-gray-1: var(--td-font-gray-1);
@font-gray-2: var(--td-font-gray-2);
@font-gray-3: var(--td-font-gray-3);
@font-gray-4: var(--td-font-gray-4);
// 基础颜色
@brand-color: var(--td-brand-color); // 色彩-品牌-可操作
@warning-color: var(--td-warning-color); // 色彩-功能-警告
@error-color: var(--td-error-color); // 色彩-功能-失败
@success-color: var(--td-success-color); // 色彩-功能-成功
// 基础颜色的扩展 用于 hover / 聚焦 / 禁用 / 点击 等状态
@brand-color-hover: var(--td-brand-color-hover); // hover态
@brand-color-focus: var(--td-brand-color-focus); // focus态,包括鼠标和键盘
@brand-color-active: var(--td-brand-color-active); // 点击态
@brand-color-disabled: var(--td-brand-color-disabled); // 禁用态
@brand-color-light: var(--td-brand-color-light); // 浅色的选中态
// 警告色扩展
@warning-color-hover: var(--td-warning-color-hover);
@warning-color-focus: var(--td-warning-color-focus);
@warning-color-active: var(--td-warning-color-active);
@warning-color-disabled: var(--td-warning-color-disabled);
@warning-color-light: var(--td-warning-color-light);
// 失败/错误色扩展
@error-color-hover: var(--td-error-color-hover);
@error-color-focus: var(--td-error-color-focus);
@error-color-active: var(--td-error-color-active);
@error-color-disabled: var(--td-error-color-disabled);
@error-color-light: var(--td-error-color-light);
// 成功色扩展
@success-color-hover: var(--td-success-color-hover);
@success-color-focus: var(--td-success-color-focus);
@success-color-active: var(--td-success-color-active);
@success-color-disabled: var(--td-success-color-disabled);
@success-color-light: var(--td-success-color-light);
// 遮罩
@mask-active: var(--td-mask-active); // 遮罩-弹出
@mask-disabled: var(--td-mask-disabled); // 遮罩-禁用
// 背景色
@bg-color-page: var(--td-bg-color-page); // 色彩 - page
@bg-color-container: var(--td-bg-color-container); // 色彩 - 容器
@bg-color-container-hover: var(--td-bg-color-container-hover); // 色彩 - 容器 - hover
@bg-color-container-active: var(--td-bg-color-container-active); // 色彩 - 容器 - active
@bg-color-container-select: var(--td-bg-color-container-select); // 色彩 - 容器 - select
@bg-color-secondarycontainer: var(--td-bg-color-secondarycontainer); // 色彩 - 次级容器
@bg-color-secondarycontainer-hover: var(--td-bg-color-secondarycontainer-hover); // 色彩 - 次级容器 - hover
@bg-color-secondarycontainer-active: var(--td-bg-color-secondarycontainer-active); // 色彩 - 次级容器 - active
@bg-color-component: var(--td-bg-color-component); // 色彩 - 组件
@bg-color-component-hover: var(--td-bg-color-component-hover); // 色彩 - 组件 - hover
@bg-color-component-active: var(--td-bg-color-component-active); // 色彩 - 组件 - active
@bg-color-component-disabled: var(--td-bg-color-component-disabled); // 色彩 - 组件 - disabled
// TODO: 考虑是否在组件内部做判断,不增加额外变量
// 特殊组件背景色,目前只用于 button、input 组件多主题场景,浅色主题下固定为白色,深色主题下为 transparent 适配背景颜色
@bg-color-specialcomponent: var(--td-bg-color-specialcomponent);
// 文本颜色
@text-color-primary: var(--td-text-color-primary); // 色彩-文字-主要
@text-color-secondary: var(--td-text-color-secondary); // 色彩-文字-次要
@text-color-placeholder: var(--td-text-color-placeholder); // 色彩-文字-占位符/说明
@text-color-disabled: var(--td-text-color-disabled); // 色彩-文字-禁用
@text-color-anti: var(--td-text-color-anti); // 色彩-文字-反色
@text-color-brand: var(--td-text-color-brand); // 色彩-文字-品牌
@text-color-link: var(--td-text-color-link); // 色彩-文字-链接
// 分割线
@border-level-1-color: var(--td-border-level-1-color);
@component-stroke: var(--td-component-stroke);
// 边框
@border-level-2-color: var(--td-border-level-2-color);
@component-border: var(--td-component-border);
// shadow
// 基础/下层 投影 hover 使用的组件包括:表格 /
@shadow-1: var(--td-shadow-1);
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
@shadow-2: var(--td-shadow-2);
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
@shadow-3: var(--td-shadow-3);
// 内投影 用于弹窗类组件(气泡确认框 / 全局提示 / 消息通知)的内描边
@shadow-inset-top: var(--td-shadow-inset-top);
@shadow-inset-right: var(--td-shadow-inset-right);
@shadow-inset-bottom: var(--td-shadow-inset-bottom);
@shadow-inset-left: var(--td-shadow-inset-left);
@shadow-inset: @shadow-inset-top, @shadow-inset-right, @shadow-inset-bottom, @shadow-inset-left;
// 融合阴影
@shadow-2-inset: @shadow-2, @shadow-inset;
@shadow-3-inset: @shadow-3, @shadow-inset;
// Spacer
@spacer: 8px;
@spacer-s: @spacer * .5; // 间距-4
@spacer-l: @spacer * 1.5; // 间距-12
@spacer-1: @spacer; // 间距-8
@spacer-2: @spacer * 2; // 间距-16
@spacer-3: @spacer * 3; // 间距-24
@spacer-4: @spacer * 4; // 间距-32
@spacer-5: @spacer * 5; // 间距-大-40
@spacer-6: @spacer * 6; // 间距-大-48
@spacer-7: @spacer * 7; // 间距-大-48
@spacer-8: @spacer * 8; // 间距-大-48
@spacer-9: @spacer * 9; // 间距-大-48
@spacer-10: @spacer * 10; // 间距-大-80
// Font
@font-size: 10px;
@font-size-s: @font-size * 1.2; // 字号-五级字号
@font-size-base: @font-size * 1.4; // 字号-四级字号
@font-size-l: @font-size * 1.6; // 字号-三级字号
@font-size-xl: @font-size * 2; // 字号-二级字号
@font-size-xxl: @font-size * 3.6; // 字号-一级字号
// Line Height
@text-line-height: 1.5; // 行高-常规
@text-line-height-s: 20px; // 行高-对应五级文字
@text-line-height-base: 22px; // 行高-对应四级文字
@text-line-height-l: 24px; // 行高-对应三级文字
@text-line-height-xl: 28px; // 行高-对应二级文字
@text-line-height-xxl: 44px; //行高-对应一级文字
@font-family: PingFang SC, Microsoft YaHei, Arial Regular; // 字体-磅数-常规
@font-family-medium: PingFang SC, Microsoft YaHei, Arial Medium; // 字体-磅数-粗体
// Border Radius
@border-radius: 3px; // 圆角-全局
@border-radius-50: 50%; // 圆角-全圆角
// 表单相关
@form-height: 30px;
@form-text-color: @text-color-primary;
@form-bg-color: @bg-color-container;
@form-border-color: @border-level-2-color;
// 图标尺寸
@icon-default: 16px;
@icon-l: 24px;
// 滚动条颜色
@scrollbar-color: var(--td-scrollbar-color);
// 响应式断点
@screen-sm: 768px;
@screen-md: 992px;
@screen-lg: 1200px;
@screen-sm-min: @screen-sm;
@screen-md-min: @screen-md;
@screen-lg-min: @screen-lg;
@screen-sm-max: (@screen-md-min - 1px);
@screen-md-max: (@screen-lg-min - 1px);
// 动画
@anim-time-fn-easing: cubic-bezier(.38, 0, .24, 1);
@anim-time-fn-ease-out: cubic-bezier(0, 0, .15, 1);
@anim-time-fn-ease-in: cubic-bezier(.82, 0, 1, .9);
@anim-duration-base: .2s;
@anim-duration-moderate: .24s;
@anim-duration-slow: .28s;
@z-index-affix: 500;
@z-index-drawer: 1500;
@z-index-dialog: 2500;
@z-index-loading: 3500;
@z-index-message: 5000;
@z-index-Popup: 5500;
@z-index-Notification: 6000;

60
vite.config.js

@ -0,0 +1,60 @@
import { defineConfig } from 'vite';
import { viteMockServe } from 'vite-plugin-mock';
// import { viteThemePlugin } from 'vite-plugin-theme';
import { createVuePlugin } from 'vite-plugin-vue2';
import { createSvgPlugin } from 'vite-plugin-vue2-svg';
import path from 'path';
import proxy from './src/config/proxy';
// import { getColorList, getGreyColor, getBrandColor } from './src/config/color';
// import USER_CONFIG from './src/config/style';
// const { brandTheme, backgroundTheme } = USER_CONFIG;
// 如有引用.env 文件,可通过下面的方法拿到变量,类似于 process.env
// import.meta.env.VITE_SOME_KEY
export default defineConfig({
base: './',
resolve: {
alias: {
'~': path.resolve(__dirname, './'),
'@': path.resolve(__dirname, './src'),
},
},
css: {
preprocessorOptions: {
less: {
modifyVars: {
// 如需自定义组件其他 token, 在此处配置
},
},
},
},
plugins: [
createVuePlugin({
jsx: true,
}),
viteMockServe({
mockPath: 'mock',
localEnabled: true,
}),
// viteThemePlugin({
// colorVariables: getColorList([getGreyColor(backgroundTheme), getBrandColor(brandTheme)]),
// }),
createSvgPlugin(),
],
build: {
cssCodeSplit: false,
},
server: {
port: 3001,
proxy: {
...proxy,
},
},
});
Loading…
Cancel
Save