mirror of
https://github.com/Tencent/tdesign-vue-next-starter.git
synced 2024-12-24 02:46:29 +08:00
Merge branch 'develop' of github.com:Tencent/tdesign-vue-next-starter into site
This commit is contained in:
commit
cfe9beaa7e
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
### 项目简介
|
### 项目简介
|
||||||
|
|
||||||
TDesign Vue Next Starter 是一个基于 TDesign,使用 `Vue3`、`Vite2`、`Pinia`、`TypeScript` 开发,可进行个性化主题配置,旨在提供项目开箱即用的、配置式的中后台项目。
|
TDesign Vue Next Starter 是一个基于 TDesign,使用 `Vue3`、`Vite`、`Pinia`、`TypeScript` 开发,可进行个性化主题配置,旨在提供项目开箱即用的、配置式的中后台项目。
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="http://tdesign.tencent.com/starter/vue-next/">在线预览</a>
|
<a href="http://tdesign.tencent.com/starter/vue-next/">在线预览</a>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
English | [简体中文](./README-zh_CN.md)
|
English | [简体中文](./README-zh_CN.md)
|
||||||
### Introduction
|
### Introduction
|
||||||
|
|
||||||
TDesign Vue Next Starter is a TDesign-based developed with `Vue 3`, `Vite 3+`, `Pinia`, `TypeScript`. It can be customized theme configuration, and aims to provide project out-of-the-box, configuration-style middle and background projects.
|
TDesign Vue Next Starter is a TDesign-based developed with `Vue 3`, `Vite`, `Pinia`, `TypeScript`. It can be customized theme configuration, and aims to provide project out-of-the-box, configuration-style middle and background projects.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="http://tdesign.tencent.com/starter/vue-next/">Live Preview</a>
|
<a href="http://tdesign.tencent.com/starter/vue-next/">Live Preview</a>
|
||||||
|
|
75
package.json
75
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@tencent/tdesign-vue-next-starter",
|
"name": "@tencent/tdesign-vue-next-starter",
|
||||||
"version": "0.7.6",
|
"version": "0.8.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:mock": "vite --open --mode mock",
|
"dev:mock": "vite --open --mode mock",
|
||||||
"dev": "vite --open --mode development",
|
"dev": "vite --open --mode development",
|
||||||
|
@ -12,70 +12,69 @@
|
||||||
"lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
|
"lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
|
||||||
"lint:fix": "eslint --ext .vue,.js,jsx,.ts,.tsx ./ --max-warnings 0 --fix",
|
"lint:fix": "eslint --ext .vue,.js,jsx,.ts,.tsx ./ --max-warnings 0 --fix",
|
||||||
"stylelint": "stylelint src/**/*.{html,vue,sass,less}",
|
"stylelint": "stylelint src/**/*.{html,vue,sass,less}",
|
||||||
"stylelint:fix": "stylelint --fix src/**/*.{html,vue,vss,sass,less}",
|
"stylelint:fix": "stylelint --fix src/**/*.{html,vue,css,sass,less}",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"site:preview": "npm run build && cp -r dist _site",
|
"site:preview": "npm run build && cp -r dist _site",
|
||||||
"test": "echo \"no test specified,work in process\"",
|
"test": "echo \"no test specified,work in process\"",
|
||||||
"test:coverage": "echo \"no test:coverage specified,work in process\""
|
"test:coverage": "echo \"no test:coverage specified,work in process\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.4.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.9",
|
||||||
"echarts": "5.1.2",
|
"echarts": "5.1.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.33",
|
"pinia": "^2.1.4",
|
||||||
"pinia-plugin-persistedstate": "^3.1.0",
|
"pinia-plugin-persistedstate": "^3.1.0",
|
||||||
"qrcode.vue": "^3.3.4",
|
"qrcode.vue": "^3.4.0",
|
||||||
"qs": "^6.11.1",
|
"qs": "^6.11.2",
|
||||||
"tdesign-icons-vue-next": "^0.1.11",
|
"tdesign-icons-vue-next": "^0.1.11",
|
||||||
"tdesign-site-components": "^0.12.9",
|
"tdesign-site-components": "^0.12.9",
|
||||||
"tdesign-theme-generator": "^1.0.5",
|
"tdesign-theme-generator": "^1.0.5",
|
||||||
"tdesign-vue-next": "^1.3.4",
|
"tdesign-vue-next": "^1.3.10",
|
||||||
"tvision-color": "^1.6.0",
|
"tvision-color": "^1.6.0",
|
||||||
"vue": "^3.2.47",
|
"vue": "^3.3.4",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-router": "~4.1.6"
|
"vue-router": "~4.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.3.0",
|
"@commitlint/cli": "^17.6.6",
|
||||||
"@commitlint/config-conventional": "^17.3.0",
|
"@commitlint/config-conventional": "^17.6.6",
|
||||||
"@types/echarts": "^4.9.16",
|
"@types/echarts": "^4.9.18",
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.195",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
||||||
"@typescript-eslint/parser": "^5.47.1",
|
"@typescript-eslint/parser": "^5.61.0",
|
||||||
"@vitejs/plugin-vue": "^3.2.0",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^1.3.10",
|
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||||
"@vue/compiler-sfc": "^3.2.47",
|
"@vue/compiler-sfc": "^3.3.4",
|
||||||
"@vue/eslint-config-typescript": "^11.0.2",
|
"@vue/eslint-config-typescript": "^11.0.3",
|
||||||
"commitizen": "^4.2.4",
|
"commitizen": "^4.3.0",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"eslint": "^8.30.0",
|
"eslint": "^8.44.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||||
"eslint-plugin-vue": "^9.8.0",
|
"eslint-plugin-vue": "^9.15.1",
|
||||||
"eslint-plugin-vue-scoped-css": "^2.2.0",
|
"eslint-plugin-vue-scoped-css": "^2.5.0",
|
||||||
"husky": "^8.0.2",
|
"husky": "^8.0.3",
|
||||||
"less": "^4.1.3",
|
"less": "^4.1.3",
|
||||||
"lint-staged": "^13.1.0",
|
"lint-staged": "^13.2.3",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"prettier": "^2.8.1",
|
"prettier": "^2.8.8",
|
||||||
"stylelint": "~14.9.1",
|
"stylelint": "~15.10.0",
|
||||||
"stylelint-config-prettier": "~9.0.4",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-less": "1.0.6",
|
"stylelint-order": "~6.0.3",
|
||||||
"stylelint-order": "~6.0.1",
|
"typescript": "~5.1.6",
|
||||||
"typescript": "~4.9.5",
|
"vite": "^4.3.9",
|
||||||
"vite": "^3.2.5",
|
"vite-plugin-mock": "^3.0.0",
|
||||||
"vite-plugin-mock": "^2.9.6",
|
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
"vue-tsc": "^1.2.0"
|
"vue-tsc": "^1.8.4"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
|
@ -87,7 +86,7 @@
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"npm run lint:fix"
|
"npm run lint:fix"
|
||||||
],
|
],
|
||||||
"*.{html,vue,vss,sass,less}": [
|
"*.{html,vue,css,sass,less}": [
|
||||||
"npm run stylelint:fix"
|
"npm run stylelint:fix"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view v-if="!isRefreshing" v-slot="{ Component }">
|
<router-view v-if="!isRefreshing" v-slot="{ Component }">
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade">
|
||||||
<keep-alive :include="aliveViews">
|
<keep-alive :include="aliveViews">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
@ -53,6 +53,7 @@ const isRefreshing = computed(() => {
|
||||||
.fade-enter-active {
|
.fade-enter-active {
|
||||||
transition: opacity @anim-duration-slow @anim-time-fn-easing;
|
transition: opacity @anim-duration-slow @anim-time-fn-easing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter,
|
.fade-enter,
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
|
@ -206,7 +206,6 @@ watchEffect(() => {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 200px;
|
bottom: 200px;
|
||||||
right: 0;
|
right: 0;
|
||||||
transition: transform 0.3s cubic-bezier(0.7, 0.3, 0.1, 1), visibility 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
border-radius: 20px 0 0 20px;
|
border-radius: 20px 0 0 20px;
|
||||||
|
@ -252,9 +251,9 @@ watchEffect(() => {
|
||||||
.setting-group-title {
|
.setting-group-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
margin: 32px 0 24px 0;
|
margin: 32px 0 24px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-family: PingFang SC;
|
font-family: 'PingFang SC', var(--td-font-family);
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--td-text-color-primary);
|
color: var(--td-text-color-primary);
|
||||||
|
@ -283,6 +282,7 @@ watchEffect(() => {
|
||||||
.setting-container {
|
.setting-container {
|
||||||
padding-bottom: 100px;
|
padding-bottom: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-radio-group.t-size-m {
|
.t-radio-group.t-size-m {
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -306,6 +306,7 @@ watchEffect(() => {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-radius: var(--td-radius-default);
|
border-radius: var(--td-radius-default);
|
||||||
border: 2px solid var(--td-component-border);
|
border: 2px solid var(--td-component-border);
|
||||||
|
|
||||||
> .t-radio-button__label {
|
> .t-radio-button__label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
id="monitorContainer"
|
id="monitorContainer"
|
||||||
ref="monitorContainer"
|
|
||||||
class="dashboard-chart-container"
|
class="dashboard-chart-container"
|
||||||
:style="{ width: '100%', height: `${resizeTime * 326}px` }"
|
:style="{ width: '100%', height: `${resizeTime * 326}px` }"
|
||||||
/>
|
/>
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card" :bordered="false">
|
<t-card title="销售渠道" :subtitle="currentMonth" class="dashboard-chart-card" :bordered="false">
|
||||||
<div
|
<div
|
||||||
id="countContainer"
|
id="countContainer"
|
||||||
ref="countContainer"
|
|
||||||
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
|
:style="{ width: `${resizeTime * 326}px`, height: `${resizeTime * 326}px`, margin: '0 auto' }"
|
||||||
class="dashboard-chart-container"
|
class="dashboard-chart-container"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -17,12 +17,7 @@
|
||||||
@change="onStokeDataChange"
|
@change="onStokeDataChange"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div id="stokeContainer" style="width: 100%; height: 351px" class="dashboard-chart-container"></div>
|
||||||
id="stokeContainer"
|
|
||||||
ref="stokeContainer"
|
|
||||||
style="width: 100%; height: 351px"
|
|
||||||
class="dashboard-chart-container"
|
|
||||||
></div>
|
|
||||||
</t-card>
|
</t-card>
|
||||||
</t-col>
|
</t-col>
|
||||||
<t-col :xs="12" :xl="3">
|
<t-col :xs="12" :xl="3">
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #operation="slotProps">
|
<template #operation="slotProps">
|
||||||
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
<t-link theme="primary" @click="rehandleClickOp(slotProps)">详情</t-link>
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</t-card>
|
</t-card>
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
<trend :type="row.growUp > 0 ? 'up' : 'down'" :describe="Math.abs(row.growUp)" />
|
||||||
</template>
|
</template>
|
||||||
<template #operation="slotProps">
|
<template #operation="slotProps">
|
||||||
<a class="t-button-link" @click="rehandleClickOp(slotProps)">详情</a>
|
<t-link theme="primary" @click="rehandleClickOp(slotProps)">详情</t-link>
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</t-card>
|
</t-card>
|
||||||
|
|
|
@ -87,8 +87,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #op="slotProps">
|
<template #op="slotProps">
|
||||||
<a :class="prefix + '-link'" @click="listClick()">管理</a>
|
<t-space>
|
||||||
<a :class="prefix + '-link'" @click="deleteClickOp(slotProps)">删除</a>
|
<t-link theme="primary" @click="listClick()">管理</t-link>
|
||||||
|
<t-link theme="danger" @click="deleteClickOp(slotProps)">删除</t-link>
|
||||||
|
</t-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #op-column>
|
<template #op-column>
|
||||||
|
@ -128,7 +130,6 @@ export default {
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { getPurchaseList } from '@/api/detail';
|
import { getPurchaseList } from '@/api/detail';
|
||||||
import { prefix } from '@/config/global';
|
|
||||||
|
|
||||||
import Product from './components/Product.vue';
|
import Product from './components/Product.vue';
|
||||||
import { BASE_INFO_DATA, PRODUCT_LIST, TABLE_COLUMNS_DATA as columns } from './constants';
|
import { BASE_INFO_DATA, PRODUCT_LIST, TABLE_COLUMNS_DATA as columns } from './constants';
|
||||||
|
@ -188,5 +189,5 @@ const onConfirm = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import url('./index.less');
|
@import './index.less';
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -40,8 +40,10 @@
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template #op="slotProps">
|
<template #op="slotProps">
|
||||||
<a :class="prefix + '-link'" @click="listClick()">管理</a>
|
<t-space>
|
||||||
<a :class="prefix + '-link'" @click="deleteClickOp(slotProps)">删除</a>
|
<t-link theme="primary" @click="listClick()">管理</t-link>
|
||||||
|
<t-link theme="danger" @click="deleteClickOp(slotProps)">删除</t-link>
|
||||||
|
</t-space>
|
||||||
</template>
|
</template>
|
||||||
<template #op-column>
|
<template #op-column>
|
||||||
<t-icon name="descending-order" />
|
<t-icon name="descending-order" />
|
||||||
|
@ -84,7 +86,6 @@ import { CanvasRenderer } from 'echarts/renderers';
|
||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { getProjectList } from '@/api/detail';
|
import { getProjectList } from '@/api/detail';
|
||||||
import { prefix } from '@/config/global';
|
|
||||||
import { useSettingStore } from '@/store';
|
import { useSettingStore } from '@/store';
|
||||||
import { changeChartsTheme } from '@/utils/color';
|
import { changeChartsTheme } from '@/utils/color';
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ const deleteClickOp = (e: { rowIndex: number }) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import url('../base/index.less');
|
@import '../base/index.less';
|
||||||
|
|
||||||
.detail-deploy {
|
.detail-deploy {
|
||||||
:deep(.t-card) {
|
:deep(.t-card) {
|
||||||
|
|
|
@ -51,8 +51,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #op="slotProps">
|
<template #op="slotProps">
|
||||||
<a class="t-button-link" @click="handleClickDetail()">详情</a>
|
<t-space>
|
||||||
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
<t-link theme="primary" @click="handleClickDetail()">详情</t-link>
|
||||||
|
<t-link theme="danger" @click="handleClickDelete(slotProps)">删除</t-link>
|
||||||
|
</t-space>
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
</t-card>
|
</t-card>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
class="form-item-content"
|
class="form-item-content"
|
||||||
:options="CONTRACT_STATUS_OPTIONS"
|
:options="CONTRACT_STATUS_OPTIONS"
|
||||||
placeholder="请选择合同状态"
|
placeholder="请选择合同状态"
|
||||||
|
clearable
|
||||||
/>
|
/>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
</t-col>
|
</t-col>
|
||||||
|
@ -43,6 +44,7 @@
|
||||||
class="form-item-content"
|
class="form-item-content"
|
||||||
:options="CONTRACT_TYPE_OPTIONS"
|
:options="CONTRACT_TYPE_OPTIONS"
|
||||||
placeholder="请选择合同类型"
|
placeholder="请选择合同类型"
|
||||||
|
clearable
|
||||||
/>
|
/>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
</t-col>
|
</t-col>
|
||||||
|
@ -90,8 +92,10 @@
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
<template #op="slotProps">
|
<template #op="slotProps">
|
||||||
<a class="t-button-link" @click="rehandleClickOp(slotProps)">管理</a>
|
<t-space>
|
||||||
<a class="t-button-link" @click="handleClickDelete(slotProps)">删除</a>
|
<t-link theme="primary" @click="rehandleClickOp(slotProps)">管理</t-link>
|
||||||
|
<t-link theme="danger" @click="handleClickDelete(slotProps)">删除</t-link>
|
||||||
|
</t-space>
|
||||||
</template>
|
</template>
|
||||||
</t-table>
|
</t-table>
|
||||||
<t-dialog
|
<t-dialog
|
||||||
|
@ -120,6 +124,13 @@ import {
|
||||||
} from '@/constants';
|
} from '@/constants';
|
||||||
import { useSettingStore } from '@/store';
|
import { useSettingStore } from '@/store';
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
name: string;
|
||||||
|
no: string;
|
||||||
|
status?: number;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
const store = useSettingStore();
|
const store = useSettingStore();
|
||||||
|
|
||||||
const COLUMNS: PrimaryTableCol[] = [
|
const COLUMNS: PrimaryTableCol[] = [
|
||||||
|
@ -168,11 +179,10 @@ const COLUMNS: PrimaryTableCol[] = [
|
||||||
const searchForm = {
|
const searchForm = {
|
||||||
name: '',
|
name: '',
|
||||||
no: '',
|
no: '',
|
||||||
status: typeof CONTRACT_STATUS,
|
|
||||||
type: '',
|
type: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const formData = ref({ ...searchForm });
|
const formData = ref<FormData>({ ...searchForm });
|
||||||
const rowKey = 'index';
|
const rowKey = 'index';
|
||||||
const verticalAlign = 'top' as const;
|
const verticalAlign = 'top' as const;
|
||||||
const hover = true;
|
const hover = true;
|
||||||
|
@ -242,6 +252,7 @@ const onReset = (val: unknown) => {
|
||||||
};
|
};
|
||||||
const onSubmit = (val: unknown) => {
|
const onSubmit = (val: unknown) => {
|
||||||
console.log(val);
|
console.log(val);
|
||||||
|
console.log(formData.value);
|
||||||
};
|
};
|
||||||
const rehandlePageChange = (pageInfo: PageInfo, newDataSource: TableRowData[]) => {
|
const rehandlePageChange = (pageInfo: PageInfo, newDataSource: TableRowData[]) => {
|
||||||
console.log('分页变化', pageInfo, newDataSource);
|
console.log('分页变化', pageInfo, newDataSource);
|
||||||
|
@ -281,6 +292,7 @@ const headerAffixedTop = computed(
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.expand {
|
.expand {
|
||||||
.t-button__text {
|
.t-button__text {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -37,9 +37,13 @@ export const usePermissionStore = defineStore('permission', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async restoreRoutes() {
|
async restoreRoutes() {
|
||||||
this.removeRoutes.forEach((item: RouteRecordRaw) => {
|
// 不需要在此额外调用initRoutes更新侧边导肮内容,在登录后asyncRoutes为空会调用
|
||||||
router.addRoute(item);
|
this.asyncRoutes.forEach((item: RouteRecordRaw) => {
|
||||||
|
if (item.name) {
|
||||||
|
router.removeRoute(item.name);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
this.asyncRoutes = [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,7 +45,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-menu--dark .t-menu__operations .t-icon {
|
.t-menu--dark .t-menu__operations .t-icon {
|
||||||
color: rgba(255, 255, 255, 0.55);
|
color: rgba(255, 255, 255, 55%);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
&-layout {
|
&-layout {
|
||||||
height: calc(100vh - var(--td-comp-size-xxxl));
|
height: calc(100vh - var(--td-comp-size-xxxl));
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
||||||
&-tabs-nav {
|
&-tabs-nav {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -153,6 +155,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// 对部分样式进行重置
|
// 对部分样式进行重置
|
||||||
body {
|
body {
|
||||||
color: var(--td-text-color-secondary);
|
color: var(--td-text-color-secondary);
|
||||||
font-family: -apple-system, BlinkMacSystemFont, var(--td-font-family);
|
|
||||||
font: var(--td-font-body-medium);
|
font: var(--td-font-body-medium);
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, var(--td-font-family);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -37,34 +37,3 @@ p {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-button-link,
|
|
||||||
a {
|
|
||||||
color: var(--td-brand-color);
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color @anim-duration-base @anim-time-fn-easing;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--td-brand-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: var(--td-brand-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
color: var(--td-brand-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.t-button-link {
|
|
||||||
margin-right: var(--td-comp-margin-xxl);
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
75
src/types/axios.d.ts
vendored
75
src/types/axios.d.ts
vendored
|
@ -1,18 +1,89 @@
|
||||||
import { AxiosRequestConfig } from 'axios';
|
import type { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Axios请求配置
|
||||||
|
*/
|
||||||
export interface RequestOptions {
|
export interface RequestOptions {
|
||||||
|
/**
|
||||||
|
* 接口地址
|
||||||
|
*
|
||||||
|
* 例: http://www.baidu.com/api
|
||||||
|
*/
|
||||||
apiUrl?: string;
|
apiUrl?: string;
|
||||||
|
/**
|
||||||
|
* 是否自动添加接口前缀
|
||||||
|
*
|
||||||
|
* 例: http://www.baidu.com/api
|
||||||
|
* urlPrefix: 'api'
|
||||||
|
*/
|
||||||
isJoinPrefix?: boolean;
|
isJoinPrefix?: boolean;
|
||||||
|
/**
|
||||||
|
* 接口前缀
|
||||||
|
*/
|
||||||
urlPrefix?: string;
|
urlPrefix?: string;
|
||||||
|
/**
|
||||||
|
* POST请求的时候添加参数到Url中
|
||||||
|
*/
|
||||||
joinParamsToUrl?: boolean;
|
joinParamsToUrl?: boolean;
|
||||||
|
/**
|
||||||
|
* 格式化提交参数时间
|
||||||
|
*/
|
||||||
formatDate?: boolean;
|
formatDate?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否需要对响应数据进行处理
|
||||||
|
*/
|
||||||
isTransformResponse?: boolean;
|
isTransformResponse?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否返回原生响应头
|
||||||
|
*
|
||||||
|
* 例: 需要获取响应头时使用该属性
|
||||||
|
*/
|
||||||
isReturnNativeResponse?: boolean;
|
isReturnNativeResponse?: boolean;
|
||||||
ignoreRepeatRequest?: boolean;
|
/**
|
||||||
|
* 是否忽略请求取消令牌
|
||||||
|
*
|
||||||
|
* 如果启用,则重复请求时不进行处理
|
||||||
|
*
|
||||||
|
* 如果禁用,则重复请求时会取消当前请求
|
||||||
|
*/
|
||||||
|
ignoreCancelToken?: boolean;
|
||||||
|
/**
|
||||||
|
* 自动对请求添加时间戳参数
|
||||||
|
*/
|
||||||
joinTime?: boolean;
|
joinTime?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否携带Token
|
||||||
|
*/
|
||||||
withToken?: boolean;
|
withToken?: boolean;
|
||||||
|
/**
|
||||||
|
* 重试配置
|
||||||
|
*/
|
||||||
retry?: {
|
retry?: {
|
||||||
|
/**
|
||||||
|
* 重试次数
|
||||||
|
*/
|
||||||
count: number;
|
count: number;
|
||||||
|
/**
|
||||||
|
* 隔多久重试
|
||||||
|
*
|
||||||
|
* 单位: 毫秒
|
||||||
|
*/
|
||||||
|
delay: number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 接口级节流
|
||||||
|
*
|
||||||
|
* 单位: 毫秒
|
||||||
|
*/
|
||||||
|
throttle?: {
|
||||||
|
delay: number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 接口级防抖
|
||||||
|
*
|
||||||
|
* 单位: 毫秒
|
||||||
|
*/
|
||||||
|
debounce?: {
|
||||||
delay: number;
|
delay: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
import axios, {
|
||||||
|
AxiosError,
|
||||||
|
AxiosInstance,
|
||||||
|
AxiosRequestConfig,
|
||||||
|
AxiosRequestHeaders,
|
||||||
|
AxiosResponse,
|
||||||
|
InternalAxiosRequestConfig,
|
||||||
|
} from 'axios';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
import isFunction from 'lodash/isFunction';
|
import isFunction from 'lodash/isFunction';
|
||||||
|
import throttle from 'lodash/throttle';
|
||||||
import { stringify } from 'qs';
|
import { stringify } from 'qs';
|
||||||
|
|
||||||
import { ContentTypeEnum } from '@/constants';
|
import { ContentTypeEnum } from '@/constants';
|
||||||
|
@ -9,12 +18,20 @@ import { AxiosRequestConfigRetry, RequestOptions, Result } from '@/types/axios';
|
||||||
import { AxiosCanceler } from './AxiosCancel';
|
import { AxiosCanceler } from './AxiosCancel';
|
||||||
import { CreateAxiosOptions } from './AxiosTransform';
|
import { CreateAxiosOptions } from './AxiosTransform';
|
||||||
|
|
||||||
// Axios模块
|
/**
|
||||||
|
* Axios 模块
|
||||||
|
*/
|
||||||
export class VAxios {
|
export class VAxios {
|
||||||
// axios句柄
|
/**
|
||||||
|
* Axios实例句柄
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private instance: AxiosInstance;
|
private instance: AxiosInstance;
|
||||||
|
|
||||||
// axios选项
|
/**
|
||||||
|
* Axios配置
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private readonly options: CreateAxiosOptions;
|
private readonly options: CreateAxiosOptions;
|
||||||
|
|
||||||
constructor(options: CreateAxiosOptions) {
|
constructor(options: CreateAxiosOptions) {
|
||||||
|
@ -23,57 +40,71 @@ export class VAxios {
|
||||||
this.setupInterceptors();
|
this.setupInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建axios句柄
|
/**
|
||||||
|
* 创建Axios实例
|
||||||
|
* @param config
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private createAxios(config: CreateAxiosOptions): void {
|
private createAxios(config: CreateAxiosOptions): void {
|
||||||
this.instance = axios.create(config);
|
this.instance = axios.create(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取数据处理
|
/**
|
||||||
|
* 获取数据处理类
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private getTransform() {
|
private getTransform() {
|
||||||
const { transform } = this.options;
|
const { transform } = this.options;
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取句柄
|
/**
|
||||||
|
* 获取Axios实例
|
||||||
|
*/
|
||||||
getAxios(): AxiosInstance {
|
getAxios(): AxiosInstance {
|
||||||
return this.instance;
|
return this.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置 axios
|
/**
|
||||||
|
* 配置Axios
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
configAxios(config: CreateAxiosOptions) {
|
configAxios(config: CreateAxiosOptions) {
|
||||||
if (!this.instance) {
|
if (!this.instance) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.createAxios(config);
|
this.createAxios(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置通用头信息
|
/**
|
||||||
|
* 设置公共头部信息
|
||||||
|
* @param headers
|
||||||
|
*/
|
||||||
setHeader(headers: Record<string, string>): void {
|
setHeader(headers: Record<string, string>): void {
|
||||||
if (!this.instance) {
|
if (!this.instance) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.assign(this.instance.defaults.headers, headers);
|
Object.assign(this.instance.defaults.headers, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置拦截器
|
/**
|
||||||
|
* 设置拦截器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private setupInterceptors() {
|
private setupInterceptors() {
|
||||||
const transform = this.getTransform();
|
const transform = this.getTransform();
|
||||||
if (!transform) {
|
if (!transform) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } =
|
const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } =
|
||||||
transform;
|
transform;
|
||||||
const axiosCanceler = new AxiosCanceler();
|
const axiosCanceler = new AxiosCanceler();
|
||||||
|
|
||||||
// 请求配置处理
|
// 请求拦截器
|
||||||
this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||||
|
// 如果忽略取消令牌,则不会取消重复的请求
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const { ignoreRepeatRequest } = config.requestOptions;
|
const { ignoreCancelToken } = config.requestOptions;
|
||||||
const ignoreRepeat = ignoreRepeatRequest ?? this.options.requestOptions?.ignoreRepeatRequest;
|
const ignoreCancel = ignoreCancelToken ?? this.options.requestOptions?.ignoreCancelToken;
|
||||||
if (!ignoreRepeat) axiosCanceler.addPending(config);
|
if (!ignoreCancel) axiosCanceler.addPending(config);
|
||||||
|
|
||||||
if (requestInterceptors && isFunction(requestInterceptors)) {
|
if (requestInterceptors && isFunction(requestInterceptors)) {
|
||||||
config = requestInterceptors(config, this.options);
|
config = requestInterceptors(config, this.options) as InternalAxiosRequestConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
@ -99,9 +130,12 @@ export class VAxios {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 支持Form Data
|
/**
|
||||||
|
* 支持 FormData 请求格式
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
supportFormData(config: AxiosRequestConfig) {
|
supportFormData(config: AxiosRequestConfig) {
|
||||||
const headers = config.headers || this.options.headers;
|
const headers = config.headers || (this.options.headers as AxiosRequestHeaders);
|
||||||
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -118,6 +152,24 @@ export class VAxios {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支持 params 序列化
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
|
supportParamsStringify(config: AxiosRequestConfig) {
|
||||||
|
const headers = config.headers || this.options.headers;
|
||||||
|
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
||||||
|
|
||||||
|
if (contentType === ContentTypeEnum.FormURLEncoded || !Reflect.has(config, 'params')) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...config,
|
||||||
|
paramsSerializer: (params: any) => stringify(params, { arrayFormat: 'brackets' }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||||
return this.request({ ...config, method: 'GET' }, options);
|
return this.request({ ...config, method: 'GET' }, options);
|
||||||
}
|
}
|
||||||
|
@ -138,8 +190,62 @@ export class VAxios {
|
||||||
return this.request({ ...config, method: 'PATCH' }, options);
|
return this.request({ ...config, method: 'PATCH' }, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求
|
/**
|
||||||
async request<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
* 上传文件封装
|
||||||
|
* @param key 文件所属的key
|
||||||
|
* @param file 文件
|
||||||
|
* @param config 请求配置
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
upload<T = any>(key: string, file: File, config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
||||||
|
const params: FormData = config.params ?? new FormData();
|
||||||
|
params.append(key, file);
|
||||||
|
|
||||||
|
return this.request(
|
||||||
|
{
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': ContentTypeEnum.FormData,
|
||||||
|
},
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求封装
|
||||||
|
* @param config
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
request<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
||||||
|
const { requestOptions } = this.options;
|
||||||
|
|
||||||
|
if (requestOptions.throttle !== undefined && requestOptions.debounce !== undefined) {
|
||||||
|
throw new Error('throttle and debounce cannot be set at the same time');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestOptions.throttle && requestOptions.throttle.delay !== 0) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
throttle(() => resolve(this.synthesisRequest(config, options)), requestOptions.throttle.delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestOptions.debounce && requestOptions.debounce.delay !== 0) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
debounce(() => resolve(this.synthesisRequest(config, options)), requestOptions.debounce.delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.synthesisRequest(config, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求方法
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private async synthesisRequest<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
||||||
let conf: CreateAxiosOptions = cloneDeep(config);
|
let conf: CreateAxiosOptions = cloneDeep(config);
|
||||||
const transform = this.getTransform();
|
const transform = this.getTransform();
|
||||||
|
|
||||||
|
@ -154,6 +260,8 @@ export class VAxios {
|
||||||
conf.requestOptions = opt;
|
conf.requestOptions = opt;
|
||||||
|
|
||||||
conf = this.supportFormData(conf);
|
conf = this.supportFormData(conf);
|
||||||
|
// 支持params数组参数格式化,因axios默认的toFormData即为brackets方式,无需配置paramsSerializer为qs,有需要可解除注释,参数参考qs文档
|
||||||
|
// conf = this.supportParamsStringify(conf);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.instance
|
this.instance
|
||||||
|
|
|
@ -5,10 +5,20 @@ import isFunction from 'lodash/isFunction';
|
||||||
// 存储请求与取消令牌的键值对列表
|
// 存储请求与取消令牌的键值对列表
|
||||||
let pendingMap = new Map<string, Canceler>();
|
let pendingMap = new Map<string, Canceler>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求Url
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&');
|
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 请求管理器
|
||||||
|
*/
|
||||||
export class AxiosCanceler {
|
export class AxiosCanceler {
|
||||||
// 添加请求到列表
|
/**
|
||||||
|
* 添加请求到列表中
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
addPending(config: AxiosRequestConfig) {
|
addPending(config: AxiosRequestConfig) {
|
||||||
this.removePending(config);
|
this.removePending(config);
|
||||||
const url = getPendingUrl(config);
|
const url = getPendingUrl(config);
|
||||||
|
@ -22,7 +32,9 @@ export class AxiosCanceler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空所有请求
|
/**
|
||||||
|
* 移除现有的所有请求
|
||||||
|
*/
|
||||||
removeAllPending() {
|
removeAllPending() {
|
||||||
pendingMap.forEach((cancel) => {
|
pendingMap.forEach((cancel) => {
|
||||||
if (cancel && isFunction(cancel)) cancel();
|
if (cancel && isFunction(cancel)) cancel();
|
||||||
|
@ -30,7 +42,10 @@ export class AxiosCanceler {
|
||||||
pendingMap.clear();
|
pendingMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除某个请求
|
/**
|
||||||
|
* 移除指定请求
|
||||||
|
* @param config
|
||||||
|
*/
|
||||||
removePending(config: AxiosRequestConfig) {
|
removePending(config: AxiosRequestConfig) {
|
||||||
const url = getPendingUrl(config);
|
const url = getPendingUrl(config);
|
||||||
|
|
||||||
|
@ -43,6 +58,9 @@ export class AxiosCanceler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置
|
||||||
|
*/
|
||||||
reset() {
|
reset() {
|
||||||
pendingMap = new Map<string, Canceler>();
|
pendingMap = new Map<string, Canceler>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,64 @@
|
||||||
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
|
|
||||||
import type { RequestOptions, Result } from '@/types/axios';
|
import type { RequestOptions, Result } from '@/types/axios';
|
||||||
|
|
||||||
// 创建Axios选项
|
/**
|
||||||
|
* @description 创建Axios实例配置
|
||||||
|
*/
|
||||||
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
/**
|
||||||
|
* 请求验证方案
|
||||||
|
*
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
||||||
|
*/
|
||||||
authenticationScheme?: string;
|
authenticationScheme?: string;
|
||||||
// 数据处理
|
/**
|
||||||
|
* 请求数据处理
|
||||||
|
*/
|
||||||
transform?: AxiosTransform;
|
transform?: AxiosTransform;
|
||||||
// 请求选项
|
/**
|
||||||
|
* 请求配置
|
||||||
|
*/
|
||||||
requestOptions?: RequestOptions;
|
requestOptions?: RequestOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Axios 数据处理
|
/**
|
||||||
|
* Axios请求数据处理 抽象类
|
||||||
|
*/
|
||||||
export abstract class AxiosTransform {
|
export abstract class AxiosTransform {
|
||||||
// 请求前Hook
|
/**
|
||||||
|
* 请求前钩子
|
||||||
|
*/
|
||||||
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;
|
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;
|
||||||
|
|
||||||
// 转换前Hook
|
/**
|
||||||
transformRequestHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any;
|
* 数据处理前钩子
|
||||||
|
*/
|
||||||
|
transformRequestHook?: <T = any>(res: AxiosResponse<Result>, options: RequestOptions) => T;
|
||||||
|
|
||||||
// 请求失败处理
|
/**
|
||||||
requestCatchHook?: (e: Error | AxiosError, options: RequestOptions) => Promise<any>;
|
* 请求失败钩子
|
||||||
|
*/
|
||||||
|
requestCatchHook?: <T = any>(e: Error | AxiosError, options: RequestOptions) => Promise<T>;
|
||||||
|
|
||||||
// 请求前的拦截器
|
/**
|
||||||
requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => InternalAxiosRequestConfig;
|
* 请求拦截器
|
||||||
|
*/
|
||||||
|
requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => AxiosRequestConfig;
|
||||||
|
|
||||||
// 请求后的拦截器
|
/**
|
||||||
|
* 响应拦截器
|
||||||
|
*/
|
||||||
responseInterceptors?: (res: AxiosResponse) => AxiosResponse;
|
responseInterceptors?: (res: AxiosResponse) => AxiosResponse;
|
||||||
|
|
||||||
// 请求前的拦截器错误处理
|
/**
|
||||||
|
* 请求拦截器错误处理
|
||||||
|
*/
|
||||||
requestInterceptorsCatch?: (error: AxiosError) => void;
|
requestInterceptorsCatch?: (error: AxiosError) => void;
|
||||||
|
|
||||||
// 请求后的拦截器错误处理
|
/**
|
||||||
|
* 响应拦截器错误处理
|
||||||
|
*/
|
||||||
responseInterceptorsCatch?: (error: AxiosError, instance: AxiosInstance) => void;
|
responseInterceptorsCatch?: (error: AxiosError, instance: AxiosInstance) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
||||||
import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
|
import type { AxiosInstance } from 'axios';
|
||||||
import isString from 'lodash/isString';
|
import isString from 'lodash/isString';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ const transform: AxiosTransform = {
|
||||||
|
|
||||||
// 如果204无内容直接返回
|
// 如果204无内容直接返回
|
||||||
const method = res.config.method?.toLowerCase();
|
const method = res.config.method?.toLowerCase();
|
||||||
if (res.status === 204 || method === 'put' || method === 'patch') {
|
if (res.status === 204 && ['put', 'patch', 'delete'].includes(method)) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ const transform: AxiosTransform = {
|
||||||
? `${options.authenticationScheme} ${token}`
|
? `${options.authenticationScheme} ${token}`
|
||||||
: token;
|
: token;
|
||||||
}
|
}
|
||||||
return config as InternalAxiosRequestConfig;
|
return config;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 响应拦截器处理
|
// 响应拦截器处理
|
||||||
|
@ -186,8 +186,10 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
||||||
formatDate: true,
|
formatDate: true,
|
||||||
// 是否加入时间戳
|
// 是否加入时间戳
|
||||||
joinTime: true,
|
joinTime: true,
|
||||||
// 忽略重复请求
|
// 是否忽略请求取消令牌
|
||||||
ignoreRepeatRequest: true,
|
// 如果启用,则重复请求时不进行处理
|
||||||
|
// 如果禁用,则重复请求时会取消当前请求
|
||||||
|
ignoreCancelToken: true,
|
||||||
// 是否携带token
|
// 是否携带token
|
||||||
withToken: true,
|
withToken: true,
|
||||||
// 重试
|
// 重试
|
||||||
|
|
|
@ -1,7 +1,38 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
defaultSeverity: 'error',
|
defaultSeverity: 'error',
|
||||||
extends: ['stylelint-config-prettier'],
|
extends: ['stylelint-config-standard'],
|
||||||
plugins: ['stylelint-less'],
|
rules: {
|
||||||
|
'no-duplicate-selectors': null,
|
||||||
|
'block-no-empty': null,
|
||||||
|
'selector-class-pattern': null,
|
||||||
|
'declaration-block-no-redundant-longhand-properties': [true, { ignoreShorthands: ['/flex/'] }],
|
||||||
|
'custom-property-pattern': null,
|
||||||
|
'keyframes-name-pattern': null,
|
||||||
|
'no-empty-source': null,
|
||||||
|
'font-family-no-missing-generic-family-keyword': [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
ignoreFontFamilies: ['PingFangSC-Regular', 'PingFangSC-Medium', 't'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
|
||||||
|
'function-url-quotes': null,
|
||||||
|
'max-line-length': null,
|
||||||
|
'at-rule-empty-line-before': ['always', { ignore: ['after-comment'] }],
|
||||||
|
'declaration-colon-newline-after': null,
|
||||||
|
'no-descending-specificity': null,
|
||||||
|
'selector-type-no-unknown': null,
|
||||||
|
'color-function-notation': 'legacy',
|
||||||
|
'value-keyword-case': null,
|
||||||
|
'property-no-unknown': [true, { checkPrefixed: true }],
|
||||||
|
'import-notation': 'string',
|
||||||
|
'selector-pseudo-class-no-unknown': [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
ignorePseudoClasses: ['deep'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ['**/*.html', '**/*.vue'],
|
files: ['**/*.html', '**/*.vue'],
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
|
||||||
vueJsx(),
|
vueJsx(),
|
||||||
viteMockServe({
|
viteMockServe({
|
||||||
mockPath: 'mock',
|
mockPath: 'mock',
|
||||||
localEnabled: true,
|
enable: true,
|
||||||
}),
|
}),
|
||||||
svgLoader(),
|
svgLoader(),
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue
Block a user