diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..4fc13c7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+root = true
+
+[*]
+indent_style = space
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.{ts,js,vue,css}]
+indent_size = 2
diff --git a/.env b/.env
new file mode 100644
index 0000000..ead7728
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VITE_SOME_KEY=123
diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..a97f050
--- /dev/null
+++ b/.env.development
@@ -0,0 +1 @@
+ VITE_SOME_KEY=456
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..9313def
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,30 @@
+snapshot*
+dist
+lib
+es
+node_modules
+common
+static
+cypress
+script/test/cypress
+_site
+temp*
+static/
+
+examples
+site/*
+!site/v3.js
+src/addon
+src/calendar
+src/locale
+src/upload
+src/dropdown
+src/transfer
+src/time-picker
+src/utils
+src/textarea
+typings
+dist
+es
+lib
+types
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
index 3c3629e..1fda54c
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,31 @@
node_modules
+.vscode
+.DS_Store
+.vscode
+
+# build files
+es/
+lib/
+dist/
+typings/
+
+_site
+package
+tmp*
+temp*
+coverage
+test-report.html
+.idea/
+yarn.lock
+*.zip
+.history
+script/test/cypress/screenshots
+script/test/cypress/videos
+script/test/cypress/results
+script/test/cypress/support
+results/
+yarn-error.log
+cypress
+cypress.json
+Dockerfile
+robotMsg.json
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..5e92232
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,39 @@
+module.exports = {
+ // 一行最多 120 字符
+ printWidth: 120,
+ // 使用 2 个空格缩进
+ tabWidth: 2,
+ // 不使用缩进符,而使用空格
+ useTabs: false,
+ // 行尾需要有分号
+ semi: true,
+ // 使用单引号
+ singleQuote: true,
+ // 对象的 key 仅在必要时用引号
+ quoteProps: 'as-needed',
+ // jsx 不使用单引号,而使用双引号
+ jsxSingleQuote: false,
+ // 末尾需要有逗号
+ trailingComma: 'all',
+ // 大括号内的首尾需要空格
+ bracketSpacing: true,
+ // jsx 标签的反尖括号需要换行
+ jsxBracketSameLine: false,
+ // 箭头函数,只有一个参数的时候,也需要括号
+ arrowParens: 'always',
+ // 每个文件格式化的范围是文件的全部内容
+ rangeStart: 0,
+ rangeEnd: Infinity,
+ // 不需要写文件开头的 @prettier
+ requirePragma: false,
+ // 不需要自动在文件开头插入 @prettier
+ insertPragma: false,
+ // 使用默认的折行标准
+ proseWrap: 'preserve',
+ // 根据显示样式决定 html 要不要折行
+ htmlWhitespaceSensitivity: 'css',
+ // vue 文件中的 script 和 style 内不用缩进
+ vueIndentScriptAndStyle: false,
+ // 换行符使用 lf
+ endOfLine: 'lf',
+};
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000..422b194
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1 @@
+module.exports = { extends: ['@commitlint/config-conventional'] };
diff --git a/docker/nginx.conf b/docker/nginx.conf
new file mode 100644
index 0000000..62b7d40
--- /dev/null
+++ b/docker/nginx.conf
@@ -0,0 +1,20 @@
+server {
+ if ($request_method = HEAD) {
+ return 200;
+ }
+
+ location / {
+ alias /usr/share/nginx/html/;
+ index index.html index.htm;
+ try_files $uri $uri/ /index.html;
+ }
+
+ access_log /var/log/nginx/access.log main;
+ error_log /var/log/nginx/error.log error;
+
+
+ error_page 500 502 503 504 /50x.html;
+ location = /50x.html {
+ root /usr/share/nginx/html;
+ }
+}
\ No newline at end of file
diff --git a/docs/20210627-114325.png b/docs/20210627-114325.png
new file mode 100644
index 0000000..4013e37
Binary files /dev/null and b/docs/20210627-114325.png differ
diff --git a/globals.d.ts b/globals.d.ts
new file mode 100644
index 0000000..1756ddc
--- /dev/null
+++ b/globals.d.ts
@@ -0,0 +1,13 @@
+// 通用声明
+declare type ClassName = { [className: string]: any } | ClassName[] | string;
+
+declare interface ImportMeta {
+ env: {
+ MODE: 'mock' | 'development' | 'test' | 'release';
+ };
+}
+
+declare module '*.svg' {
+ const content: string;
+ export default content;
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..a7f9882
--- /dev/null
+++ b/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ TDesign Pro
+
+
+
+
+
+
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..cacf9d3
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..59cb0aa
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/src/components/card/index.vue b/src/components/card/index.vue
new file mode 100644
index 0000000..7d7a686
--- /dev/null
+++ b/src/components/card/index.vue
@@ -0,0 +1,88 @@
+
+
+
+
+ {{ title }}
+ {{ describe }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/result/index.vue b/src/components/result/index.vue
new file mode 100644
index 0000000..0b0fd9d
--- /dev/null
+++ b/src/components/result/index.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+ {{ tip }}
+
+
+
+
+ 返回首页
+
+
+
+
+
+
+
+
diff --git a/src/components/thumbnail/index.vue b/src/components/thumbnail/index.vue
new file mode 100644
index 0000000..2815888
--- /dev/null
+++ b/src/components/thumbnail/index.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
diff --git a/src/config/global.ts b/src/config/global.ts
new file mode 100644
index 0000000..537adf6
--- /dev/null
+++ b/src/config/global.ts
@@ -0,0 +1,11 @@
+export const prefix = 'tdesign-pro';
+export const theme = 'light';
+// 登录方式设定,authenticationMethod取值有:smartProxy(走智能网关内网登录,要求.oa.co../.woa.co.. 等域名,且要求域名申请接入智能网关)
+// customize(自定义登录,外网域名,统一重定向到登录页面)
+// export const authenticationMethod = 'smartProxy';
+export const authenticationMethod = 'customize';
+export default {
+ prefix,
+ theme,
+ authenticationMethod,
+};
diff --git a/src/config/proxy.ts b/src/config/proxy.ts
new file mode 100644
index 0000000..42284bb
--- /dev/null
+++ b/src/config/proxy.ts
@@ -0,0 +1,20 @@
+export default {
+ development: {
+ // 开发环境接口请求
+ host: 'https://service-exndqyuk-1257786608.gz.apigw.tencentcs.com',
+ // 开发环境 cdn 路径
+ cdn: '',
+ },
+ test: {
+ // 测试环境接口地址
+ host: 'https://service-exndqyuk-1257786608.gz.apigw.tencentcs.com',
+ // 测试环境 cdn 路径
+ cdn: '',
+ },
+ release: {
+ // 正式环境接口地址
+ host: 'https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com',
+ // 正式环境 cdn 路径
+ cdn: '',
+ },
+};
diff --git a/src/config/routes.ts b/src/config/routes.ts
new file mode 100644
index 0000000..d788c8f
--- /dev/null
+++ b/src/config/routes.ts
@@ -0,0 +1,174 @@
+export default [
+ {
+ path: '/dashboard',
+ icon: 'dashboard',
+ title: '仪表盘',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/dashboard/base',
+ children: [
+ {
+ title: '概览仪表盘',
+ path: 'base',
+ component: '../pages/dashboard/base/index.vue',
+ },
+ {
+ title: '统计报表',
+ path: 'detail',
+ component: '../pages/dashboard/detail/index.vue',
+ },
+ ],
+ },
+ {
+ path: '/list',
+ icon: 'view-module',
+ title: '列表页',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/list/base',
+ children: [
+ {
+ title: '基础列表页',
+ path: 'base',
+ component: '../pages/list/base/index.vue',
+ },
+ {
+ title: '卡片列表页',
+ path: 'card',
+ component: '../pages/list/card/index.vue',
+ },
+ {
+ title: '筛选列表页',
+ path: 'select',
+ component: '../pages/list/select/index.vue',
+ },
+ {
+ title: '树状筛选列表页',
+ path: 'tree',
+ component: '../pages/list/tree/index.vue',
+ },
+ ],
+ },
+ {
+ path: '/form',
+ icon: 'queue',
+ title: '表单页',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/form/base',
+ children: [
+ {
+ title: '基础表单页',
+ path: 'base',
+ component: '../pages/form/base/index.vue',
+ },
+ {
+ title: '分步表单页',
+ path: 'step',
+ component: '../pages/form/step/index.vue',
+ },
+ ],
+ },
+ {
+ path: '/detail',
+ icon: 'layers',
+ title: '详情页',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/detail/base',
+ children: [
+ {
+ title: '基础详情页',
+ path: 'base',
+ component: '../pages/detail/base/index.vue',
+ // 默认不填,则需要每个页面都会经过登录的校验,若不需要进行登录校验则将needLogin:设为false
+ meta: { needLogin: false, title: '基础详情页' },
+ },
+ {
+ title: '多卡片详情页',
+ path: 'advanced',
+ component: '../pages/detail/advanced/index.vue',
+ },
+ {
+ title: '数据详情页',
+ path: 'deploy',
+ component: '../pages/detail/deploy/index.vue',
+ },
+ {
+ title: '二级详情页',
+ path: 'secondary',
+ component: '../pages/detail/secondary/index.vue',
+ },
+ ],
+ },
+ {
+ path: '/result',
+ icon: 'check-circle',
+ title: '结果页',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/result/success',
+ children: [
+ {
+ title: '成功页',
+ path: 'success',
+ component: '../pages/result/success/index.vue',
+ },
+ {
+ title: '失败页',
+ path: 'fail',
+ component: '../pages/result/fail/index.vue',
+ },
+ {
+ title: '网络异常',
+ path: 'network-error',
+ component: '../pages/result/network-error/index.vue',
+ },
+ {
+ title: '无权限',
+ path: '403',
+ component: '../pages/result/403/index.vue',
+ },
+ {
+ title: '访问页面不存在页',
+ path: '404',
+ component: '../pages/result/404/index.vue',
+ },
+ {
+ title: '服务器出错页',
+ path: '500',
+ component: '../pages/result/500/index.vue',
+ },
+ {
+ title: '浏览器不兼容页',
+ path: 'browser-incompatible',
+ component: '../pages/result/browser-incompatible/index.vue',
+ },
+ ],
+ },
+ {
+ path: '/user',
+ icon: 'user-circle',
+ title: '个人页',
+ component: '../layouts/td-layout.tsx',
+ redirect: '/user/index',
+ children: [
+ {
+ title: '个人中心',
+ path: 'index',
+ component: '../pages/user/index.vue',
+ },
+ ],
+ },
+ // 自定义登录页面
+ {
+ path: '/login',
+ title: '登录页',
+ component: '../layouts/blank.vue',
+ icon: 'chevron-right-rectangle',
+ redirect: '/login/index',
+ children: [
+ {
+ title: '登录中心',
+ path: 'index',
+ meta: { needLogin: false },
+ component: '../pages/login/index.vue',
+ },
+ ],
+ },
+];
diff --git a/src/config/style.ts b/src/config/style.ts
new file mode 100644
index 0000000..6d184d1
--- /dev/null
+++ b/src/config/style.ts
@@ -0,0 +1,12 @@
+export default {
+ showFooter: true,
+ isSidebarCompact: false,
+ showBreadcrumb: false,
+ theme: 'dark',
+ layout: 'side',
+ splitMenu: false,
+ isFooterAside: false,
+ isSidebarFixed: true,
+ isHeaderFixed: true,
+ showHeader: true,
+};
diff --git a/src/constants/index.ts b/src/constants/index.ts
new file mode 100644
index 0000000..18b4bbc
--- /dev/null
+++ b/src/constants/index.ts
@@ -0,0 +1,35 @@
+// 合同状态枚举
+export const CONTRACT_STATUS = {
+ FAIL: 0,
+ AUDIT_PENDING: 1,
+ EXEC_PENDING: 2,
+ EXECUTING: 3,
+ FINISH: 4,
+};
+
+export const CONTRACT_STATUS_OPTIONS = [
+ { value: CONTRACT_STATUS.FAIL, label: '审核失败' },
+ { value: CONTRACT_STATUS.AUDIT_PENDING, label: '待审核' },
+ { value: CONTRACT_STATUS.EXEC_PENDING, label: '待履行' },
+ { value: CONTRACT_STATUS.EXECUTING, label: '审核成功' },
+ { value: CONTRACT_STATUS.FINISH, label: '已完成' },
+];
+
+// 合同类型枚举
+export const CONTRACT_TYPES = {
+ MAIN: 0,
+ SUB: 1,
+ SUPPLEMENT: 2,
+};
+
+export const CONTRACT_TYPE_OPTIONS = [
+ { value: CONTRACT_TYPES.MAIN, label: '主合同' },
+ { value: CONTRACT_TYPES.SUB, label: '子合同' },
+ { value: CONTRACT_TYPES.SUPPLEMENT, label: '补充合同' },
+];
+
+// 合同收付类型枚举
+export const CONTRACT_PAYMENT_TYPES = {
+ PAYMENT: 0,
+ RECIPT: 1,
+};
diff --git a/src/pages/dashboard/base/index.less b/src/pages/dashboard/base/index.less
new file mode 100644
index 0000000..0ad0f33
--- /dev/null
+++ b/src/pages/dashboard/base/index.less
@@ -0,0 +1,309 @@
+@import '@/style/index';
+
+@media (max-width: @screen-md-max) {
+ .dashboard-panel .t-col-3 {
+ min-width: 50%;
+ &:first-child {
+ margin-bottom: 16px;
+ }
+ }
+ }
+
+.dashboard-panel .t-col {
+ .card-container {
+ margin: 0;
+ }
+}
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+
+.dashboard-panel {
+ padding: 0;
+ border-radius: @border-radius;
+
+ .card-container {
+ .card-content {
+ &-label-title {
+ color: @text-color-primary;
+ padding-bottom: 4px;
+ }
+ }
+ .t-table th, .t-table td {
+ padding: 10px 8px;
+ }
+ .t-table tr {
+ color: @text-color-primary;
+ }
+ }
+}
+
+ .dashboard-item-perfix {
+ margin-right: 0 !important;
+ }
+
+
+ .dashboard-item-bottom {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: flex-end;
+
+ .dashboard-item-bottom-left {
+ display: flex;
+ flex-direction: row;
+ align-items:flex-start;
+
+ &-unit {
+ font-size: 14px;
+ color: rgba(0,0,0,0.90);
+ padding-left: 4px;
+ padding-top: 17px;
+ }
+
+ &-number {
+ display: inline-block;
+ color: black;
+ font-size: 36px;
+ line-height: 44px;
+ }
+ }
+ }
+
+ .dashboard-item-bottom-right {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ height: 55px;
+
+ .dashboard-item-bottom-emergency {
+ width: 96px;
+ height: 32px;
+ background: #FFE9E9;
+ border-radius: 16px;
+ font-size: 14px;
+ color: #E34D59;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-top: 15px;
+ }
+
+ .dashboard-item-bottom-right-top {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ h1 {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ padding-right: 8px;
+ }
+ div {
+ height: 24px;
+ // font-weight: bold;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ padding-top: 14px;
+
+ > span {
+ color: #00A870;
+ }
+ }
+ }
+ .dashboard-item-bottom-right-bottom {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ h1 {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ padding-right: 8px;
+ }
+ div {
+ height: 24px;
+ background: #FFE9E9;
+ border-radius: @border-radius;
+ color: #E34D59;
+ // font-weight: bold;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ padding: 1px 8px;
+
+ .t-icon-caret-up {
+ margin-left: 5px !important;
+ }
+ }
+ }
+
+ }
+
+
+
+.dashboard-bottom {
+ margin-top: 16px;
+ display: flex;
+ flex-direction: row;
+
+ // 左边图表
+ .dashboard-bottom-left {
+ width: 100%;
+ height: 100%;
+
+ .dashboard-bottom-left-top {
+ display: flex;
+ flex-direction: row;
+ width: 100%;
+ height: 100%;
+
+ // 计量统计
+ .dashboard-bottom-left-top-count-chart {
+ padding: 20px 24px;
+ background-color: white;
+ border-radius: @border-radius;
+ width: 100%;
+ min-width: 300px;
+ height: 320px;
+ }
+ // 动态监测
+ .dashboard-bottom-left-top-monitor-chart {
+ padding: 20px 24px;
+ background-color: white;
+ border-radius: @border-radius;
+ margin-left: 16px;
+ width: 100%;
+ // min-width: 300px;
+ height: 320px;
+
+ }
+ }
+
+ // 出入库概览()
+ .dashboard-bottom-left-bottom {
+ background-color: white;
+ padding: 20px 24px;
+ border-radius: @border-radius;
+ margin-top: 16px;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ min-height: 366px;
+ }
+ }
+
+ // 右边列表-实时热度趋势
+ .dashboard-bottom-right {
+ padding: 20px 24px;
+ background-color: white;
+ border-radius: @border-radius;
+ margin-left: 16px;
+ width: 426px;
+ min-height: 690px;
+
+ ul {
+ padding-top: 16px;
+
+ li {
+ .dashboard-chart-tend-item-title {
+ color: grey !important;
+ }
+
+ .dashboard-chart-tend-sep {
+ padding: 0 0 17px 0 !important;
+ }
+
+ .dashboard-chart-tend-item-line {
+ border-bottom: solid 1px #dedede;
+ padding: 9px 0;
+ }
+
+ .dashboard-chart-tend-item {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+
+ .dashboard-chart-tend-left {
+ display: flex;
+ flex-direction: row;
+ .dashboard-chart-tend-num {
+ width: 48px;
+ }
+
+ .dashboard-chart-tend-rante {
+ width: 48px;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// 标题内容
+.dashboard-chart-title {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ font-weight: bold;
+
+ &-describe {
+ font-size: 14px !important;
+ color: rgba(0,0,0,0.60) !important;
+ text-align: left;
+ line-height: 22px;
+ }
+ &-container {
+ .t-date-picker {
+ width: 240px;
+ }
+ }
+
+ span {
+ font-size: 16px;
+ color: rgba(0,0,0,0.90);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .dashboard-chart-title-search {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid #DDDDDD;
+ border-radius: @border-radius;
+ padding: 0;
+ align-items: center;
+ justify-content: center;
+ font-weight: normal;
+
+ input {
+ border: solid 0px #ffffff !important;
+ }
+ }
+
+ label {
+ font-weight: normal !important;
+ padding: 5px 15px !important;
+
+ .t-radio-button__label {
+ font-size: 10px !important;
+ }
+ }
+}
+.dashboard-chart-container {
+ margin: 0 auto;
+}
+
+.dashboard-item-block {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/src/pages/dashboard/base/index.ts b/src/pages/dashboard/base/index.ts
new file mode 100644
index 0000000..edaa17c
--- /dev/null
+++ b/src/pages/dashboard/base/index.ts
@@ -0,0 +1,270 @@
+import dayjs from 'dayjs';
+
+export class DashboardBase {
+ /** 更新容器尺寸 */
+ setContainerSize(containerCopyValue: HTMLElement, absWidth = 0, absHeight = 0): void {
+ const container = containerCopyValue;
+ try {
+ if (container && container.style && container.parentElement) {
+ container.style.width = `${container.parentElement.clientWidth - absWidth}px`;
+ container.style.height = `${container.parentElement.clientHeight - absHeight}px`;
+ }
+ } catch (error) {
+ // hook
+ }
+ }
+}
+
+/**
+ * 获取随机数
+ *
+ * @param {number} [num=100]
+ * @returns
+ *
+ * @memberOf DashboardBase
+ */
+export function getRandomNum(num = 100): number {
+ let resultNum = Number((Math.random() * num).toFixed(0));
+
+ if (resultNum <= 1) {
+ resultNum = 1;
+ }
+
+ return resultNum;
+}
+
+/** 柱状图数据源 */
+export function constructInitDataset(dateTime: Array = []) {
+ const dataset: Array> = [['时间'], ['入库'], ['出库']];
+ const divideNum = 10;
+
+ for (let i = 0; i < divideNum; i++) {
+ const [timeArray, inArray, outArray] = dataset;
+ if (dateTime.length > 0) {
+ const dateAbsTime: number = (new Date(dateTime[1]).getTime() - new Date(dateTime[0]).getTime()) / divideNum;
+ const enhandTime: number = new Date(dateTime[0]).getTime() + dateAbsTime * i;
+ // console.log('dateAbsTime..', dateAbsTime, enhandTime);
+ timeArray.push(dayjs(enhandTime).format('YYYY-MM-DD'));
+ } else {
+ timeArray.push(
+ dayjs()
+ .subtract(divideNum - i, 'day')
+ .format('YYYY-MM-DD'),
+ );
+ }
+
+ inArray.push(getRandomNum().toString());
+ outArray.push(getRandomNum().toString());
+ }
+ return dataset;
+}
+
+/**
+ * 线性图表数据源
+ *
+ * @export
+ * @param {Array} [dateTime=[]]
+ * @returns {*}
+ */
+export function getLineChartDataSet(dateTime: Array = []): any {
+ if (dateTime.length > 0) {
+ const devideNum = 10;
+ const dateArray: Array = getDateArray(dateTime, devideNum);
+ return [
+ dateArray,
+ getSelftItemList('杯子', devideNum),
+ getSelftItemList('茶叶', devideNum),
+ getSelftItemList('蜂蜜', devideNum),
+ getSelftItemList('面粉', devideNum),
+ ];
+ }
+ return [
+ [
+ '日期',
+ '2020-01-16',
+ '2020-01-17',
+ '2020-01-18',
+ '2020-01-19',
+ '2020-01-20',
+ '2020-01-21',
+ '2020-01-22',
+ '2020-01-23',
+ '2020-01-24',
+ '2020-01-25',
+ ],
+ ['杯子', 5, 15, 15, 25, 24, 13, 32, 37, 43, 35],
+ ['茶叶', 1, 6, 13, 38, 39, 44, 48, 75, 62, 52],
+ ['蜂蜜', 16, 22, 27, 22, 32, 35, 23, 32, 33, 25],
+ ['面粉', 12, 12, 25, 29, 21, 30, 37, 47, 40, 47],
+ ];
+}
+/** 图表颜色 */
+export const chartListColor: Array = ['#0052D9', '#00A870', '#7D46BD', '#0594FA', '#ED7B2F'];
+
+/**
+ * 获取表头数据
+ *
+ * @export
+ * @param {string[]} dateTime
+ * @param {number} divideNum
+ * @returns {string[]}
+ */
+export function getDateArray(dateTime: string[] = [], divideNum = 10): string[] {
+ const timeArray: string[] = ['日期'];
+ if (dateTime.length > 0) {
+ for (let i = 0; i < divideNum; i++) {
+ const dateAbsTime: number = (new Date(dateTime[1]).getTime() - new Date(dateTime[0]).getTime()) / divideNum;
+ const enhandTime: number = new Date(dateTime[0]).getTime() + dateAbsTime * i;
+ timeArray.push(dayjs(enhandTime).format('YYYY-MM-DD'));
+ }
+ }
+
+ return timeArray;
+}
+
+/**
+ * 获取表行数据
+ *
+ * @export
+ * @param {string} productName
+ * @param {number} devideNum
+ */
+export function getSelftItemList(productName: string, devideNum: number): string[] {
+ const productArray: string[] = [productName];
+ for (let i = 0; i < devideNum; i++) {
+ productArray.push(getRandomNum(100 * i).toString());
+ }
+
+ return productArray;
+}
+
+/**
+ * 散点图数据
+ *
+ * @export
+ * @returns {any[]}
+ */
+export function getScattlerDataSet(): any[] {
+ const scatterData = [...Array(40)].map(() => [
+ getRandomNum(Math.random() * 100),
+ getRandomNum(Math.random() * 200),
+ getRandomNum(Math.random() * 30),
+ getRandomNum(Math.random() * 400),
+ ]);
+
+ return [
+ ['咖啡机质量', '咖啡机效果', '按摩仪质量', '按摩仪效果'],
+ [getRandomNum(100), getRandomNum(200), getRandomNum(100), getRandomNum(500)],
+ ...scatterData,
+ ];
+}
+
+/**
+ * 获域图数据结构
+ *
+ * @export
+ * @returns {any[]}
+ */
+export function getAreaChartDataSet(text = ''): any {
+ return {
+ title: {
+ text,
+ },
+ dataset: [
+ ['时间', '00:00', '02:00', '04:00', '06:00', '08:00'],
+ [
+ '测试',
+ getRandomNum(Math.random() * 100),
+ getRandomNum(Math.random() * 200),
+ getRandomNum(Math.random() * 300),
+ getRandomNum(Math.random() * 400),
+ getRandomNum(Math.random() * 500),
+ ],
+ [
+ '上线',
+ getRandomNum(Math.random() * 100),
+ getRandomNum(Math.random() * 200),
+ getRandomNum(Math.random() * 300),
+ getRandomNum(Math.random() * 400),
+ getRandomNum(Math.random() * 500),
+ ],
+ ],
+ area: {
+ smooth: true,
+ },
+ injectOption: (option) => ({ ...option, color: chartListColor }),
+ };
+}
+
+/**
+ * 柱状图数据结构
+ *
+ * @export
+ * @param {boolean} [isMonth=false]
+ * @returns {*}
+ */
+export function getColumnChartDataSet(isMonth = false): any {
+ if (isMonth) {
+ return {
+ title: {
+ text: '',
+ },
+ dataset: [
+ ['日期', '1', '4', '8', '12', '16', '20', '24'],
+ [
+ '告警',
+ getRandomNum(Math.random() * 800),
+ getRandomNum(Math.random() * 700),
+ getRandomNum(Math.random() * 600),
+ getRandomNum(Math.random() * 500),
+ getRandomNum(Math.random() * 400),
+ getRandomNum(Math.random() * 300),
+ getRandomNum(Math.random() * 100),
+ ],
+ ],
+ injectOption: (option) => ({ ...option, color: chartListColor }),
+ };
+ }
+ return {
+ title: {
+ text: '',
+ },
+ dataset: [
+ ['时间', '周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+ [
+ '告警',
+ getRandomNum(Math.random() * 200),
+ getRandomNum(Math.random() * 300),
+ getRandomNum(Math.random() * 600),
+ getRandomNum(Math.random() * 500),
+ getRandomNum(Math.random() * 100),
+ getRandomNum(Math.random() * 300),
+ getRandomNum(Math.random() * 100),
+ ],
+ ],
+ injectOption: (option) => ({ ...option, color: chartListColor }),
+ };
+}
+
+/**
+ * 获取饼图数据
+ *
+ * @export
+ * @param {number} [radius=1]
+ * @returns {*}
+ */
+export function getPieChartDataSet(radius = 42): any {
+ return {
+ title: {
+ text: '',
+ },
+ dataset: [
+ ['状态', '审核中', '待履行', '履行中', '已完成'],
+ ['数量', 67, 45, radius, 36],
+ ],
+ injectOption: (option) => ({ ...option, color: chartListColor }),
+ pie: {
+ radius: ['45%', '60%'], // 设置内圆和外圆半径
+ },
+ };
+}
diff --git a/src/pages/dashboard/detail/index.less b/src/pages/dashboard/detail/index.less
new file mode 100644
index 0000000..a188fd5
--- /dev/null
+++ b/src/pages/dashboard/detail/index.less
@@ -0,0 +1,147 @@
+@import '@/style/index';
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+
+.dashboard-panel-detail {
+ padding: 0;
+ border-radius: @border-radius;
+ }
+
+// 标题内容
+.dashboard-chart-title {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ font-weight: bold;
+
+ span {
+ font-size: 16px;
+ color: rgba(0,0,0,0.90);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .dashboard-chart-title-date {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid #DDDDDD;
+ border-radius: @border-radius;
+ padding: 5px 8px;
+ align-items: center;
+ justify-content: center;
+ font-weight: normal;
+
+ .dashboard-chart-title-to {
+ color: rgba(0,0,0,0.30);
+ padding: 0 10px;
+ }
+
+ .t-icon-creditcard {
+ margin-left: 20px !important;
+ }
+ }
+
+ .dashboard-chart-title-search {
+ display: flex;
+ flex-direction: row;
+ border: 1px solid #DDDDDD;
+ border-radius: @border-radius;
+ padding: 0;
+ align-items: center;
+ justify-content: center;
+ font-weight: normal;
+
+ input {
+ border: solid 0px #ffffff !important;
+ }
+ }
+
+ label {
+ font-weight: normal !important;
+ padding: 5px 15px !important;
+
+ .t-radio-button__label {
+ font-size: 10px !important;
+ }
+ }
+}
+
+
+.dashboard-detail-top-container {
+ padding: 20px 24px;
+ background-color: white;
+ border-radius: @border-radius;
+
+ .dashboard-detail-box {
+ .dashboard-detail-container-item:not(:last-child) {
+ border-right: solid 1px #EBEBEB;
+ margin-right: 22.5px;
+ }
+ @media screen and (min-width: @screen-md-max) {
+ .dashboard-detail-container-item-perfix {
+ border-right: solid 1px #EBEBEB;
+ margin-right: 22.5px;
+ }
+ display: flex;
+ }
+ @media screen and (max-width: @screen-md-max - 1px) and (min-width: 0) {
+ display: normal;
+ }
+ }
+ .dashboard-detail-container {
+ display: flex;
+ flex: 1;
+ flex-direction: row;
+ padding-top: 20px;
+
+ .dashboard-detail-container-item {
+ min-width: 108px;
+ width: 100%;
+ height: 106px;
+
+ span {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ }
+
+ h1 {
+ font-size: 36px;
+ color: rgba(0,0,0,0.90);
+ font-weight: 500;
+ padding-top: 8px;
+
+ span {
+ font-size: 14px;
+ color: rgba(0,0,0,0.30);
+ padding-left: 8px;
+ }
+ }
+
+ .dashboard-detail-container-item-text {
+ // color: #E34D59;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-items: center;
+ font-size: 12px;
+ color: rgba(0,0,0,0.40);
+ text-align: left;
+ line-height: 20px;
+ }
+ }
+ }
+}
+
+.dashboard-detail-bottom-container {
+ padding: 20px 24px;
+ background-color: white;
+ border-radius: @border-radius;
+ margin-top: 16px;
+ min-height: 400px;
+
+ .dashboard-chart-title-container {
+ width: 240px;
+ }
+}
diff --git a/src/pages/detail/advanced/index.less b/src/pages/detail/advanced/index.less
new file mode 100644
index 0000000..22dc4c3
--- /dev/null
+++ b/src/pages/detail/advanced/index.less
@@ -0,0 +1,176 @@
+@import '@/style/index';
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+.t-layout--content-replace {
+ color: rgba(0, 0, 0, 0.6) !important;
+}
+
+.row-padding {
+ padding-top: 30px;
+ padding-left: 20px;
+}
+.operater-block-container {
+ padding: 10px 0 30px;
+}
+.operater-add {
+ width: 100%;
+ height: 210px;
+ display: flex;
+ align-items: center;
+ justify-items: center;
+ padding: 20px 10px 24px 20px;
+ border: dashed 1px #dedede;
+
+ .operater-sub {
+ font-size: 14px;
+ color: @text-color-secondary;
+ margin: 0 auto;
+ text-align: center;
+ line-height: 22px;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ .t-icon {
+ color: @brand-color-8;
+ }
+ }
+
+ span {
+ padding-left: 10px;
+ }
+}
+
+.operater-gap {
+ margin-left: 20px;
+}
+
+.operater-block {
+ background-color: #EBEDF1;
+ padding: 20px 10px 24px 20px;
+ height: 210px;
+
+ .operater-title {
+ display: flex;
+ align-items: center;
+ margin-bottom: 25px;
+
+ h1 {
+ display: inline-block;
+ padding-left: 20px;
+ font-weight: bold;
+ font-size: 14px;
+ }
+ }
+ .operater-item {
+ padding-left: 48px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ display: flex;
+ h1 {
+ display: inline-block;
+ width: 136px;
+ text-align: left;
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ }
+ span {
+ width: 100%;
+ }
+ }
+}
+
+.@{prefix} {
+ &-panel {
+ background-color: white;
+ padding: @spacer-3;
+ border-radius: @border-radius;
+ margin-top: 16px;
+ }
+
+ &-search-input {
+ width: 360px;
+ margin-right: 8px;
+ }
+
+ &-operater-row {
+ margin-bottom: 12px;
+ }
+
+ &-operater-title {
+ font-size: 16px;
+ color: rgba(0, 0, 0, 0.9);
+ font-weight: bold;
+ }
+
+ &-operater-label {
+ color: #000;
+ padding-left: 112px;
+ }
+}
+
+.info-block {
+ column-count: 2;
+
+ .info-item {
+ padding: 12px 0;
+ display: flex;
+
+ h1 {
+ width: 84px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-color-secondary;
+ text-align: left;
+ line-height: 22px;
+ }
+ span {
+ margin-left: 24px;
+ }
+ i {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: @border-radius-50;
+ background: @success-color-5;
+ }
+ .inProgress {
+ color: @success-color-5;
+ }
+ .pdf {
+ color: @brand-color-8;
+ }
+ }
+}
+.dialog-info-block {
+
+ .info-item {
+ padding: 12px 0;
+ display: flex;
+
+ h1 {
+ width: 84px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-color-secondary;
+ text-align: left;
+ line-height: 22px;
+ }
+ span {
+ margin-left: 24px;
+ }
+ i {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: @border-radius-50;
+ background: @success-color-5;
+ }
+ .green {
+ color: @success-color-5;
+ }
+ .blue {
+ color: @brand-color-8;
+ }
+ }
+}
diff --git a/src/pages/detail/advanced/index.vue b/src/pages/detail/advanced/index.vue
new file mode 100644
index 0000000..0b996d8
--- /dev/null
+++ b/src/pages/detail/advanced/index.vue
@@ -0,0 +1,285 @@
+
+
+
合同详情页
+
+
+
+
+
+ 基本信息
+
+
+
+
+
{{ item.name }}
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
+
+ 发票进度
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 产品目录
+
+
+
+
+
+
+
+
+
+
+
Macbook
+
+
+
产品编号
+ p_tmp_60a637cd0d
+
+
+
计费方式
+ 按量计费
+
+
+
交付时间
+ 2020-12-21 11:05:17
+
+
+
+
+
+
+
+
椅子
+
+
+
产品编号
+ p_tmp_60a637cd0C
+
+
+
计费方式
+ 按量计费
+
+
+
交付时间
+ 2020-12-21 13:08:09
+
+
+
+
+
+
+
+
+
+
+ 产品采购明细
+
+
+
+
+
+ 管理
+ 删除
+
+
+
+
+
+
+
+
+
{{ item.name }}
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/detail/base/index.less b/src/pages/detail/base/index.less
new file mode 100644
index 0000000..06b11e6
--- /dev/null
+++ b/src/pages/detail/base/index.less
@@ -0,0 +1,57 @@
+@import '@/style/index';
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+
+.@{prefix} {
+ &-panel {
+ background-color: white;
+ padding: @spacer-3;
+ border-radius: @border-radius;
+ }
+
+ &-operater-row {
+ margin-bottom: 12px;
+ }
+
+ &-operater-title {
+ font-size: 16px;
+ color: @text-color-primary;
+ font-family: PingFangSC-Medium;
+ }
+}
+
+.info-block {
+ column-count: 2;
+
+ .info-item {
+ padding: 12px 0;
+ display: flex;
+
+ h1 {
+ font-weight: normal;
+ width: 84px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-color-secondary;
+ text-align: left;
+ line-height: 22px;
+ }
+ span {
+ margin-left: 24px;
+ }
+ i {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: @border-radius-50;
+ background: @success-color-5;
+ }
+ .inProgress {
+ color: @success-color-5;
+ }
+ .pdf {
+ color: @brand-color-8;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/detail/base/index.vue b/src/pages/detail/base/index.vue
new file mode 100644
index 0000000..d928488
--- /dev/null
+++ b/src/pages/detail/base/index.vue
@@ -0,0 +1,84 @@
+
+
+
合同基础详情
+
+
+
+
+ 基本信息
+
+
+
+
+
{{ item.name }}
+
+
+ {{ item.value }}
+
+
+
+
+
+
+
+
+ 变更记录
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/detail/secondary/index.less b/src/pages/detail/secondary/index.less
new file mode 100644
index 0000000..8014358
--- /dev/null
+++ b/src/pages/detail/secondary/index.less
@@ -0,0 +1,64 @@
+@import '@/style/variables.less';
+
+.secondary-notification {
+ background-color: white;
+ border-radius: @border-radius;
+ margin-top: 16px;
+
+ .t-tabs__content {
+ padding-top: 0;
+ }
+}
+.secondary-msg-list {
+ min-height: 443px;
+ max-height: calc(100vh - 400px);
+
+ .t-list-item {
+ cursor: pointer;
+
+ &:hover {
+ background-color: @bg-color-container-hover;
+ .msg-date {
+ display: none;
+ }
+ .msg-action {
+ display: flex;
+ align-items: center;
+
+ &-icon {
+ display: flex;
+ align-items: center;
+ }
+ }
+ }
+ }
+ .content {
+ font-family: PingFangSC-Medium;
+ font-size: 14px;
+ color:@text-color-placeholder;
+ text-align: left;
+ line-height: 22px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ span {
+ font-family: PingFangSC-Regular;
+ }
+ }
+ .unread {
+ color: @brand-color-8;
+ }
+ .msg-action {
+ display: none;
+
+ .set-read-icon {
+ margin-right: 24px;
+ }
+ }
+ &__empty-list {
+ min-height: 443px;
+ padding-top: 170px;
+ text-align: center;
+ }
+}
diff --git a/src/pages/detail/secondary/index.vue b/src/pages/detail/secondary/index.vue
new file mode 100644
index 0000000..d30d846
--- /dev/null
+++ b/src/pages/detail/secondary/index.vue
@@ -0,0 +1,276 @@
+
+ 通知中心
+
+
+
+
+
+
+ {{ item.content }} - {{ item.type }}
+
+
+
+ {{ item.date }}
+
+
+
+
+
+
+
+
暂无通知
+
+
+
+
+
+
+ {{ item.content }} - {{ item.type }}
+
+
+
+ {{ item.date }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
暂无未读通知
+
+
+
+
+
+
+ {{ item.content }} - {{ item.type }}
+
+
+
+ {{ item.date }}
+
+
+
+
+
+
+
+
暂无已读通知
+
+
+
+
+
+
+
diff --git a/src/pages/form/base/index.less b/src/pages/form/base/index.less
new file mode 100644
index 0000000..2b390e3
--- /dev/null
+++ b/src/pages/form/base/index.less
@@ -0,0 +1,29 @@
+@import '@/style/index';
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+
+.@{prefix} {
+ &-panel {
+ background-color: white;
+ padding: @spacer-3;
+ border-radius: @border-radius;
+
+ .base-form {
+ .t-form__label {
+ min-width: 108px;
+ }
+ }
+ }
+ &-form {
+ padding-right: 50px;
+ padding-top: 30px;
+ border-top: solid 1px #EEEEEE;
+ }
+}
+.upload-tips {
+ margin-left: 16px;
+ font-size: 12px;
+ color: @text-level-2-color;
+ line-height: 20px;
+}
diff --git a/src/pages/form/step/index.less b/src/pages/form/step/index.less
new file mode 100644
index 0000000..6e7e797
--- /dev/null
+++ b/src/pages/form/step/index.less
@@ -0,0 +1,62 @@
+@import '@/style/index';
+.t-tabs__content {
+ padding-top: @spacer-3;
+}
+
+.@{prefix} {
+ &-panel {
+ background-color: white;
+
+ &.@{prefix}-step-panel {
+ padding: 0;
+ }
+ }
+ &-step {
+ padding: 14px 0 24px 0;
+ }
+ &-form {
+ padding-right: 50px;
+ padding-top: 30px;
+ border-top: solid 1px #eeeeee;
+ }
+}
+
+.rule-tips {
+ padding: 24px 24px 0 24px;
+}
+
+.step-top {
+ padding: 24px;
+ border-bottom: #eeeeee solid 1px;
+}
+
+.step-form {
+ padding: 24px;
+
+ .t-form__label {
+ min-width: 108px;
+ }
+}
+
+.step-form-4 {
+ height: 365px;
+ margin-top: 72px;
+ text-align: center;
+
+ .t-icon {
+ margin: 6px;
+ }
+ .text {
+ margin: 16px 0 8px 0;
+ font-weight: bold;
+ font-size: 20px;
+ color: @text-level-1-color;
+ line-height: 30px;
+ }
+ .tips {
+ margin-bottom: 24px;
+ font-size: 14px;
+ color: @text-level-2-color;
+ line-height: 22px;
+ }
+}
diff --git a/src/pages/form/step/index.vue b/src/pages/form/step/index.vue
new file mode 100644
index 0000000..60c50e6
--- /dev/null
+++ b/src/pages/form/step/index.vue
@@ -0,0 +1,420 @@
+
+ 分步表单页
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1、申请开票后,电子发票在1~3个工作日内开具;增值税专用发票(纸质)如资质审核通过,将在电子发票开具后10个工作日内为您寄出;
+
+ 2、开票金额为您实际支付金额;
+ 3、如有疑问请直接联系:13300001111。
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+ {{ amount }} 元
+
+
+
+ 提交申请
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 上一步
+
+
+ 下一步
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+ 上一步
+
+
+ 下一步
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/list/select/index.vue b/src/pages/list/select/index.vue
new file mode 100644
index 0000000..08b195f
--- /dev/null
+++ b/src/pages/list/select/index.vue
@@ -0,0 +1,19 @@
+
+ 合同档案
+
+
+
+
diff --git a/src/pages/login/index.less b/src/pages/login/index.less
new file mode 100644
index 0000000..162e602
--- /dev/null
+++ b/src/pages/login/index.less
@@ -0,0 +1,247 @@
+@import '@/style/index';
+.login-wrapper {
+ width: 100%;
+ height: 100%;
+ background-image: url(https://tdesign.gtimg.com/pro-template/login-bg-img.jpg);
+ background-size: cover;
+ background-position: 50%;
+ position: relative;
+}
+.login-container {
+ position: absolute;
+ top: 28%;
+ left: 12%;
+ min-height: 500px;
+ line-height: 22px;
+}
+.title-container {
+ .icon {
+ width: 290px;
+ height: 60px;
+ }
+ .side-title {
+ margin-top: 24.9px;
+ .tip1, .tip2 {
+ display: inline-block;
+ margin-right: 8px;
+ }
+ .tip1 {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ }
+ .tip2 {
+ font-size: 14px;
+ color: @brand-color-8;
+ cursor: pointer;
+ }
+ }
+}
+
+.login-step1 {
+ .input-container {
+ margin-top: 72px;
+
+ .t-input {
+ display: block;
+ }
+ .t-popup-reference {
+ margin: 24px 0;
+ }
+ }
+ .check-container {
+ .t-checkbox__label {
+ color: @text-color-secondary;
+ span {
+ color: @brand-color-8;
+ }
+ }
+ }
+}
+.login-step3 {
+ .input-container {
+ margin-top: 34px;
+ }
+}
+.input-container {
+ .tip-container {
+ margin-bottom: 16px;
+ .tip1 {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+ }
+ .tip2 {
+ float: right;
+ font-size: 14px;
+ color: @brand-color-8;
+
+ .t-icon {
+ height: 20px;
+ vertical-align: text-bottom;
+ }
+ }
+ }
+ .button-container {
+ margin-top: 16px;
+ }
+ .check-container {
+ font-size: 14px;
+ color: rgba(0,0,0,0.60);
+
+ .tip {
+ float: right;
+ font-size: 14px;
+ color: @brand-color-8;
+ }
+ }
+}
+
+.login-step1 {
+ .bottom-container {
+ margin-top: 72px;
+ }
+}
+.login-step3 {
+ .bottom-container {
+ margin-top: 32px;
+ }
+ .input-container .tip-container {
+ width: 192px;
+ }
+}
+.login-step2 {
+ .input-container {
+ margin-top: 108.9px;
+ .tip1 {
+ cursor: pointer;
+ }
+ }
+}
+.bottom-container {
+ margin-top: 66px;
+ .tip {
+ font-size: 14px;
+ color: @brand-color-8;
+ cursor: pointer;
+ }
+ i {
+ font-style: normal;
+ color: @gray-color-3;
+ margin: 0 14px;
+ }
+
+}
+.rex-check {
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-color-placeholder;
+ line-height: 22px;
+}
+.format-correct {
+ color: @text-color-primary;
+
+ .t-icon {
+ color: @success-color-5;
+ }
+}
+
+.login-step4 {
+ .input-container {
+ margin-top: 64px;
+
+ .t-input {
+ display: block;
+ }
+ .t-popup-reference {
+ margin: 24px 0;
+ }
+ .verification-code {
+ margin-bottom: 24px;
+
+ .t-input {
+ display: inline-block;
+ }
+ button {
+ width: 102px;
+ height: 40px;
+ margin-left: 11px;
+ }
+ }
+ }
+ .bottom-container {
+ margin-top: 66px;
+ }
+ .check-container {
+ .t-checkbox__label {
+ color: @text-color-secondary;
+
+ span {
+ color: @brand-color-8;
+ }
+ }
+ }
+}
+
+.login-step5 {
+ .input-container {
+ margin-top: 64px;
+
+ .t-input {
+ display: block;
+ }
+ .t-popup-reference {
+ margin: 24px 0;
+ }
+ .t-select-popup-reference {
+ margin: 0;
+ }
+ }
+ .bottom-container {
+ margin-top: 66px;
+ }
+ .check-container {
+ .t-checkbox__label {
+ color: @text-color-secondary;
+
+ span {
+ color: @brand-color-8;
+ }
+ }
+ }
+}
+
+.login-step6 {
+ .input-container {
+ margin-top: 64px;
+
+ .t-input {
+ display: block;
+ }
+ .t-popup-reference {
+ margin: 24px 0;
+ }
+ .verification-code {
+ margin: 24px 0;
+
+ .t-input {
+ display: inline-block;
+ }
+ button {
+ width: 102px;
+ height: 40px;
+ margin-left: 11px;
+ }
+ }
+ }
+ .bottom-container {
+ margin-top: 66px;
+ }
+ .check-container {
+ .t-checkbox__label {
+ color: @text-color-secondary;
+
+ span {
+ color: @brand-color-8;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/result/403/index.vue b/src/pages/result/403/index.vue
new file mode 100644
index 0000000..ac93963
--- /dev/null
+++ b/src/pages/result/403/index.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/src/pages/result/404/index.vue b/src/pages/result/404/index.vue
new file mode 100644
index 0000000..4d07692
--- /dev/null
+++ b/src/pages/result/404/index.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/src/pages/result/500/index.vue b/src/pages/result/500/index.vue
new file mode 100644
index 0000000..809148b
--- /dev/null
+++ b/src/pages/result/500/index.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/src/pages/result/browser-incompatible/index.vue b/src/pages/result/browser-incompatible/index.vue
new file mode 100644
index 0000000..2f315bb
--- /dev/null
+++ b/src/pages/result/browser-incompatible/index.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/src/pages/result/fail/index.vue b/src/pages/result/fail/index.vue
new file mode 100644
index 0000000..9e4fa96
--- /dev/null
+++ b/src/pages/result/fail/index.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+ 项目创建失败
+
+
+ 企业微信联系检查创建者权限,或返回修改
+
+
+ $router.push('/form/base')">
+ 返回修改
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/result/network-error/index.vue b/src/pages/result/network-error/index.vue
new file mode 100644
index 0000000..96fa1e2
--- /dev/null
+++ b/src/pages/result/network-error/index.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/src/pages/result/success/index.vue b/src/pages/result/success/index.vue
new file mode 100644
index 0000000..e0d8665
--- /dev/null
+++ b/src/pages/result/success/index.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+ 项目已创建成功
+
+
+ 可以联系负责人分发应用
+
+
+ $router.push('/detail/advanced')"
+ >
+ 查看进度
+
+ $router.push('/form/base')">
+ 再次创建
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/user/index.less b/src/pages/user/index.less
new file mode 100644
index 0000000..aa95d03
--- /dev/null
+++ b/src/pages/user/index.less
@@ -0,0 +1,298 @@
+@import '@/style/index';
+.user-panel {
+
+ @media (max-width: @screen-sm-max) {
+ .user-right {
+ min-width: 100%;
+ }
+ }
+
+ @media (min-width: @screen-md-min) {
+ .user-right {
+ min-width: 33.33%;
+ }
+ }
+ .user-right {
+ transition: width .3s linear;
+ &-greeting {
+ margin-bottom: 16px;
+ background: #fff;
+ border-radius: @border-radius;
+ }
+ &-trend {
+ margin-bottom: 16px;
+ background: #fff;
+ border-radius: @border-radius;
+ }
+ &-todo {
+ margin-bottom: 16px;
+ background: #fff;
+ border-radius: @border-radius;
+ }
+ }
+ .head-bar {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+
+ .title {
+ line-height: 24px;
+ font-family: PingFangSC-Medium;
+ font-size: 16px;
+ color: @text-level-1-color;
+ text-align: left;
+ }
+ .more {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 22px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-level-1-color;
+ cursor: pointer;
+
+ .t-icon {
+ vertical-align: bottom;
+ font-size: 20px;
+ }
+ &:hover {
+ color: @brand-color-8;
+ }
+ }
+ }
+
+ .user-left {
+ .user-top {
+ padding: 24px;
+ margin: 0 16px 16px 0;
+ background: #fff;
+ border-radius: @border-radius;
+
+ .account {
+ text-align: center;
+ margin-bottom: 48px;
+ color: @text-level-1-color;
+
+ .img {
+ display: block;
+ width: 122px;
+ height: 122px;
+ border-radius: @border-radius-50;
+ background: #EBEDF1;
+ margin-top: 16px;
+ margin-left: 50%;
+ transform: translateX(-50%);
+ }
+ .name {
+ line-height: 37px;
+ font-family: PingFangSC-Semibold;
+ font-size: 26px;
+ margin-top: 16px;
+ }
+ .position {
+ line-height: 24px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ margin-top: 8px;
+ }
+ }
+ .user-info {
+ line-height: 24px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-level-1-color;
+ .hiredate, .del, .mail {
+ display: flex;
+ }
+ .t-icon {
+ height: 24px;
+ margin-right: 8px;
+ }
+ .del {
+ margin: 16px 0;
+ }
+ }
+ }
+ .user-bottom {
+ padding: 24px 24px 0 24px;
+ margin: 0 16px 16px 0;
+ background: #fff;
+ border-radius: @border-radius;
+
+ .t-list-item {
+ height: 64px;
+ min-width: 230px;
+ margin: 8px 0 16px 0;
+ background: #F3F3F3;
+ border-radius: @border-radius;
+
+ .t-list-item__meta-avatar {
+ height: 32px;
+ width: 32px;
+ margin: auto;
+ }
+ .t-list-item__meta-content {
+ line-height: 22px;
+ margin-left: 10px;
+ padding: 5px 0;
+ }
+ .t-list-item__meta-title {
+ display: inline-block;
+ margin: 0 7px 0 0;
+ }
+ .t-list-item__meta-description {
+ display: inline-block;
+ color: @text-color-secondary;
+ font-size: 12px;
+ }
+ .t-list-item__action {
+ li {
+ margin-right: 16px;
+ cursor: pointer;
+ }
+ .t-icon {
+ color: @text-level-1-color;
+
+ &:hover {
+ color: @brand-color-8;
+ }
+ }
+ }
+ }
+ }
+ }
+ .user-right {
+ .user-top {
+ .user-right-greeting {
+ padding: 24px;
+ line-height: 28px;
+ font-family: PingFangSC-Semibold;
+ font-size: 20px;
+ color: @text-level-1-color;
+ text-align: left;
+ .regular {
+ vertical-align: bottom;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ }
+ }
+ .user-right-trend {
+ padding: 24px;
+
+ .t-list-item {
+ padding: 8px 0;
+ cursor: pointer;
+
+ .text {
+ display: flex;
+ line-height: 20px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-level-1-color;
+
+ .t-icon {
+ margin-right: 8px;
+ height: 20px;
+ font-size: 16px;
+ color: @text-level-3-color;
+ }
+ p {
+ display: inline-block;
+ }
+ }
+ .t-list-item__action {
+ line-height: 20px;
+ font-family: PingFangSC-Regular;
+ font-size: 12px;
+ color: @text-level-2-color;
+ }
+ &:hover {
+ .text {
+ color: @brand-color-8;
+
+ .t-icon {
+ color: @brand-color-8;
+ }
+ }
+ }
+ }
+ .t-list-item:last-child {
+ padding-bottom: 0;
+ }
+ }
+ .user-right-todo {
+ padding: 24px;
+
+ .empty-list {
+ margin-top: 18px;
+ line-height: 20px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-level-3-color;
+ text-align: center;
+
+ img {
+ margin-bottom: 2px;
+ width: 42px;
+ }
+ }
+ }
+ }
+ .user-bottom {
+ padding: 24px;
+ background: #fff;
+ border-radius: @border-radius;
+
+ .contract {
+ width: 340px;
+ height: 88px;
+ border-radius: @border-radius;
+ margin: 8px 0;
+ cursor: pointer;
+
+ &-type {
+ position: relative;
+ float: left;
+ margin: 13px 16px;
+
+ img {
+ width: 64px;
+ height: 64px;
+ }
+ }
+ &-title {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ line-height: 24px;
+ margin: 20px 0 6px 0;
+ font-family: PingFangSC-Medium;
+ font-size: 16px;
+ color: @text-level-1-color;
+ }
+ &-date {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ line-height: 22px;
+ font-family: PingFangSC-Regular;
+ font-size: 14px;
+ color: @text-level-3-color;
+ }
+ &:hover {
+ background: #f7f7f7;
+ }
+ }
+ .contract:last-child,
+ .contract:nth-last-child(2) {
+ margin-bottom: 0;
+ }
+ }
+ }
+ .user-bottom .user-right{
+ height: 447px;
+ background: #fff;
+ border-radius: @border-radius;
+ }
+}
diff --git a/src/router/index.ts b/src/router/index.ts
new file mode 100644
index 0000000..4569f35
--- /dev/null
+++ b/src/router/index.ts
@@ -0,0 +1,47 @@
+import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
+import routeConfig from '@/config/routes';
+
+const layoutModules = import.meta.glob('../layouts/*');
+const pagesModules = import.meta.glob('../pages/**/*.vue');
+const fristPagesModules = import.meta.glob('../pages/*.vue');
+
+const modules = Object.assign({}, layoutModules, fristPagesModules, pagesModules);
+
+const getMenuRoutes = (list) => {
+ if (!list) {
+ return [];
+ }
+ return list.map((item) => {
+ const { path = '', component, meta = { title: item.title }, redirect = '' } = item;
+ return {
+ path,
+ component: modules[component],
+ children: getMenuRoutes(item.children),
+ meta,
+ redirect,
+ };
+ });
+};
+
+const routes: Array = [
+ ...getMenuRoutes(routeConfig),
+ {
+ path: '',
+ redirect: '/dashboard/base',
+ component: () => import('@/pages/dashboard/base/index.vue'),
+ },
+];
+
+const router = createRouter({
+ history: createWebHistory(''),
+ routes,
+ scrollBehavior(to, from, savedPosition) {
+ return {
+ el: '#app',
+ top: 0,
+ behavior: 'smooth',
+ }
+ },
+})
+export default router
+
diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts
new file mode 100644
index 0000000..c458ab5
--- /dev/null
+++ b/src/shims-vue.d.ts
@@ -0,0 +1,6 @@
+declare module '*.vue' {
+ import { DefineComponent } from 'vue'
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/src/store/index.ts b/src/store/index.ts
new file mode 100644
index 0000000..9118eb2
--- /dev/null
+++ b/src/store/index.ts
@@ -0,0 +1,20 @@
+import { InjectionKey } from 'vue'
+import { createStore, Store } from 'vuex'
+import user from './modules/user';
+import notification from './modules/notification';
+import setting from './modules/setting';
+export interface State {
+ count: number
+}
+
+export const key: InjectionKey> = Symbol()
+
+export const store = createStore({
+ modules: {
+ user,
+ setting,
+ notification,
+ },
+})
+
+export default store;
diff --git a/src/store/modules/notification.ts b/src/store/modules/notification.ts
new file mode 100644
index 0000000..13e753f
--- /dev/null
+++ b/src/store/modules/notification.ts
@@ -0,0 +1,68 @@
+// 定义的state初始值
+const state = {
+ msgData: [
+ {
+ id: '123',
+ content: '腾讯大厦一楼改造施工项目 已通过审核!',
+ type: '合同动态',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ {
+ id: '124',
+ content: '三季度生产原材料采购项目 开票成功!',
+ type: '票务动态',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ {
+ id: '125',
+ content: '2021-01-01 10:00的【国家电网线下签约】会议即将开始,请提前10分钟前往 会议室1 进行签到!',
+ type: '会议通知',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ {
+ id: '126',
+ content: '一季度生产原材料采购项目 开票成功!',
+ type: '票务动态',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ {
+ id: '127',
+ content: '二季度生产原材料采购项目 开票成功!',
+ type: '票务动态',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ {
+ id: '128',
+ content: '三季度生产原材料采购项目 开票成功!',
+ type: '票务动态',
+ status: true,
+ date: '2021-01-01 08:00',
+ },
+ ],
+};
+
+const mutations = {
+ setMsgData(state, data) {
+ state.msgData = data;
+ },
+};
+
+const getters = {
+ unreadMsg: (state) => state.msgData.filter((item) => item.status),
+ readMsg: (state) => state.msgData.filter((item) => !item.status),
+};
+
+const actions = {};
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions,
+ getters,
+};
diff --git a/src/style/font-family.less b/src/style/font-family.less
new file mode 100644
index 0000000..c677a52
--- /dev/null
+++ b/src/style/font-family.less
@@ -0,0 +1,6 @@
+@font-face {
+ font-family: "TencentSansW7";
+ src: url("data:application/font-woff;charset=utf-8;base64,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") format("woff");
+ font-weight: normal;
+ font-style: normal;
+ }
\ No newline at end of file
diff --git a/src/style/index.less b/src/style/index.less
new file mode 100644
index 0000000..6554dc3
--- /dev/null
+++ b/src/style/index.less
@@ -0,0 +1,167 @@
+@import "./common.less";
+@import "./variables.less";
+@import "./rewrite.less";
+@import "./font-family.less";
+@import "./sidenav.less";
+
+body {
+ color: @text-level-2-color;
+ font-family: -apple-system, BlinkMacSystemFont, @font-family;
+ font-size: @font-size-base;
+ line-height: 1.5;
+ -webkit-font-smoothing: antialiased;
+ padding: 0;
+ min-width: @screen-sm-min;
+ }
+ pre {
+ font-family: @font-family;
+ }
+
+ ul,
+ dl,
+ li,
+ dd,
+ dt {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ figure,
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6,
+ p {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin: 0;
+ }
+
+ * {
+ box-sizing: border-box;
+ }
+
+ .@{prefix}-text-ellipsis {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .@{prefix}-text-tip {
+ font-size: 12px;
+ color: @text-level-3-color;
+ }
+
+ .@{prefix}-pic {
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 100%;
+ }
+
+ .@{prefix}-main-link {
+ color: @text-level-1-color;
+ text-decoration: none;
+ cursor: pointer;
+
+ &:hover {
+ color: @text-level-1-color;
+ }
+
+ &:active {
+ color: @text-level-1-color;
+ }
+
+ &--active {
+ color: #000;
+ }
+
+ &:focus {
+ text-decoration: none;
+ }
+ }
+
+ .@{prefix}-link {
+ color: @primary-color;
+
+ text-decoration: none;
+ margin-right: @spacer-3;
+
+ cursor: pointer;
+
+ &:hover {
+ color: @primary-color;
+ }
+
+ &:active {
+ color: @primary-color;
+ }
+
+ &--active {
+ color: @primary-color;
+ }
+
+ &:focus {
+ text-decoration: none;
+ }
+ }
+
+ // 布局元素调整
+ .@{prefix}-wrapper {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+ .@{prefix}-sidenav-layout {
+
+ &-relative {
+ height: 100%;
+ }
+ }
+ .@{prefix}-content-layout {
+ margin: @spacer-3;
+ }
+
+ .@{prefix}-footer-layout {
+ padding: 0;
+ margin-bottom: @spacer-2;
+ }
+
+ .@{prefix}-footer {
+ color: rgba(0, 0, 0, 0.3);
+ line-height: 20px;
+ text-align: center;
+ }
+
+ .@{prefix}-icon-container {
+ width: 16px;
+ height: 16px;
+ margin-left: 4px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .@{prefix}-flat-icon {
+ width: 10px;
+ height: 3px;
+ background: rgba(0,0,0,0.60);
+ }
+
+ .@{prefix}-up-triangle {
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 0 6px 8px 6px;
+ border-color: transparent transparent #00A870 transparent;
+ }
+
+ .@{prefix}-down-triangle {
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 8px 6px 0 6px;
+ border-color: #E34D59 transparent transparent transparent;
+ }
\ No newline at end of file
diff --git a/src/style/sidenav.less b/src/style/sidenav.less
new file mode 100644
index 0000000..d5686b3
--- /dev/null
+++ b/src/style/sidenav.less
@@ -0,0 +1,96 @@
+@import './variables.less';
+@import './font-family.less';
+
+.@{prefix} {
+ &-sidebar-layout {
+ height: 100%;
+ }
+
+ &-sidebar-compact {
+ width: 64px;
+ .@{prefix}-sidenav-logo-wrapper {
+ padding-left: 16px;
+ }
+ }
+ &-sidebar-layout-side {
+ z-index: 100;
+ }
+
+ &-sidenav{
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ z-index: 10;
+ transition: all .3s;
+ min-height: 100%;
+
+ &-mix {
+ top: 64px;
+
+ &-fixed {
+ top: 64px;
+ z-index: 0;
+ }
+ }
+
+ &-no-fixed {
+ position: relative;
+ z-index: 1;
+ }
+
+ &-no-logo {
+ z-index: 1;
+ }
+
+ &-logo-wrapper {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ }
+ &-logo-t-logo {
+ width: 32px;
+ }
+ &-logo-tdesign-logo {
+ width: 112px;
+ }
+ &-logo-normal {
+ font-family: TencentSansKoreanW7;
+ color: @primary-color;
+ font-size: @font-size-l;
+ transition: all .3s;
+ }
+ }
+
+
+ &-sidenav-placeholder {
+ flex: 1 1 232px;
+ min-width: 232px;
+ transition: all .3s;
+
+ &-hidden {
+ flex: 1 1 72px;
+ min-width: 72px;
+ transition: all .3s;
+ }
+ }
+
+}
+.t-menu--dark .t-menu__options:not(:empty) .t-icon-menu-unfold {
+ color: rgba(255, 255, 255, 0.55)
+}
+
+.logo-container {
+ cursor: pointer;
+ display: inline-flex;
+ height: 64px;
+ margin-left: 24px;
+ }
+
+ .optional-icon {
+ color: #000000;
+ cursor: pointer;
+
+ &:hover {
+ color: @primary-color;
+ }
+ }
\ No newline at end of file
diff --git a/src/utils/date.ts b/src/utils/date.ts
new file mode 100644
index 0000000..c6be642
--- /dev/null
+++ b/src/utils/date.ts
@@ -0,0 +1,6 @@
+// 获取常用时间
+import dayjs, { Dayjs } from 'dayjs';
+
+export const LAST_7_DAYS: [Dayjs, Dayjs] = [dayjs().subtract(7, 'day'), dayjs().subtract(1, 'day')];
+
+export const LAST_30_DAYS: [Dayjs, Dayjs] = [dayjs().subtract(30, 'day'), dayjs().subtract(1, 'day')];
diff --git a/src/utils/request.js b/src/utils/request.js
new file mode 100644
index 0000000..e276b96
--- /dev/null
+++ b/src/utils/request.js
@@ -0,0 +1,57 @@
+import axios from 'axios';
+import proxy from '../config/proxy';
+
+const env = import.meta.env.MODE || 'development';
+
+const host = env === 'mock' ? '/' : proxy[env].host; // 如果是mock模式 就不配置host 会走本地Mock拦截
+
+const CODE = {
+ LOGIN_TIMEOUT: 1000,
+ REQUEST_SUCCESS: 0,
+ REQUEST_FOBID: 1001,
+};
+
+const instance = axios.create({
+ baseURL: host,
+ timeout: 1000,
+ withCredentials: true,
+});
+
+instance.interceptors.request.use((config) => config);
+
+instance.defaults.retry = 3;
+
+instance.interceptors.response.use(
+ (response) => {
+ if (response.status === 200) {
+ const { data } = response;
+ if (data.code === CODE.REQUEST_SUCCESS) {
+ return data;
+ }
+ return response;
+ }
+ },
+ (err) => {
+ const { config } = err;
+
+ if (!config || !config.retry) return Promise.reject(err);
+
+ config.retryCount = config.retryCount || 0;
+
+ if (config.retryCount >= config.retry) {
+ return Promise.reject(err);
+ }
+
+ config.retryCount += 1;
+
+ const backoff = new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ }, config.retryDelay || 1);
+ });
+
+ return backoff.then(() => instance(config));
+ },
+);
+
+export default instance;
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..5de7b38
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": false,
+ "jsx": "preserve",
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "lib": ["esnext", "dom"],
+ "noEmit": true,
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/config/proxy.ts", "src/pages/detail/base/index.js"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..c66be59
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,27 @@
+import { defineConfig } from 'vite'
+import { viteMockServe } from 'vite-plugin-mock';
+const HttpProxyAgent = require('http-proxy-agent');
+import vueJsx from '@vitejs/plugin-vue-jsx';
+
+import vue from '@vitejs/plugin-vue'
+const path = require('path');
+
+import proxy from './src/config/proxy';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ base: './',
+ resolve: {
+ alias: {
+ '~': path.resolve(__dirname, './'),
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+ plugins: [
+ vue(),
+ vueJsx()
+ ],
+ server: {
+ port: 3002,
+ },
+})