feat 多商户适配中

This commit is contained in:
DaxPay
2024-09-23 19:27:15 +08:00
parent 91945d4399
commit 2ba1318212
31 changed files with 6459 additions and 5406 deletions

View File

@@ -21,7 +21,7 @@ VITE_GLOB_UPLOAD_URL =
VITE_GLOB_IMG_URL = VITE_GLOB_IMG_URL =
# 接口前缀 # 接口前缀
VITE_GLOB_API_URL_PREFIX = /server VITE_GLOB_API_URL_PREFIX = /

View File

@@ -4,7 +4,7 @@
# 网站根目录(与PC部署在一起, 所以根目录不可以为 /) 和 接口 (server) 前缀 这个是独立部署模式 # 网站根目录(与PC部署在一起, 所以根目录不可以为 /) 和 接口 (server) 前缀 这个是独立部署模式
VITE_PUBLIC_PATH=/h5 VITE_PUBLIC_PATH=/h5
VITE_GLOB_API_URL_PREFIX=/server VITE_GLOB_API_URL_PREFIX=
# 是否删除console # 是否删除console
VITE_DROP_CONSOLE=true VITE_DROP_CONSOLE=true

View File

@@ -10,14 +10,16 @@
## 🍒 项目地址 ## 🍒 项目地址
| 项目 | GITEE | GITHUB | | 项目 | GITEE | GITHUB |
|---------|---------------------------------------------|-------------------------------------------------| | ----------- | ------------------------------------------- | ----------------------------------------------- |
| 后端地址 | [GITEE](https://gitee.com/dromara/dax-pay) | [GITHUB](https://github.com/dromara/dax-pay) | | 后端地址 | [GITEE](https://gitee.com/dromara/dax-pay) | [GITHUB](https://github.com/dromara/dax-pay) |
| Web前端地址 | [GITEE](https://gitee.com/bootx/dax-pay-ui) | [GITHUB](https://github.com/xxm1995/dax-pay-ui) | | Web前端地址 | [GITEE](https://gitee.com/bootx/dax-pay-ui) | [GITHUB](https://github.com/xxm1995/dax-pay-ui) |
| H5前端地址 | [GITEE](https://gitee.com/bootx/dax-pay-h5) | [GITHUB](https://github.com/xxm1995/dax-pay-h5) | | H5前端地址 | [GITEE](https://gitee.com/bootx/dax-pay-h5) | [GITHUB](https://github.com/xxm1995/dax-pay-h5) |
## 🏬 系统演示 ## 🏬 系统演示
### 管理平台: ### 管理平台:
> 注:演示账号部分功能修改删除权限未开放。 > 注:演示账号部分功能修改删除权限未开放。
地址https://daxpay.demo.bootx.cn 地址https://daxpay.demo.bootx.cn
@@ -27,6 +29,7 @@
密码123456 密码123456
### 网关接口 ### 网关接口
> 注:接口平台只开放支付网关相关的接口,不开放系统其他接口。 > 注:接口平台只开放支付网关相关的接口,不开放系统其他接口。
地址: https://daxpay.server.bootx.cn/doc.html 地址: https://daxpay.server.bootx.cn/doc.html
@@ -36,6 +39,7 @@
密码: 123456 密码: 123456
### 收银台演示 ### 收银台演示
> 请勿大额支付,可以通过后台管理端进行退款 > 请勿大额支付,可以通过后台管理端进行退款
电脑收银台地址: https://daxpay.demo.bootx.cn/#/cashier 电脑收银台地址: https://daxpay.demo.bootx.cn/#/cashier

View File

@@ -6,7 +6,7 @@ import { viteMockServe } from 'vite-plugin-mock'
export function configMockPlugin(isBuild: boolean, prodMock: boolean) { export function configMockPlugin(isBuild: boolean, prodMock: boolean) {
return viteMockServe({ return viteMockServe({
ignore: /^\_/, ignore: /^_/,
mockPath: 'mock', mockPath: 'mock',
localEnabled: !isBuild, localEnabled: !isBuild,
prodEnabled: isBuild && prodMock, prodEnabled: isBuild && prodMock,

View File

@@ -19,10 +19,7 @@
} }
// 设置主题色变量 // 设置主题色变量
document.documentElement.style.setProperty( document.documentElement.style.setProperty('--app-theme-color', appTheme)
'--app-theme-color',
appTheme,
)
})() })()
</script> </script>
<style> <style>

View File

@@ -1,25 +1,10 @@
{ {
"name": "vue3-vant4-mobile", "name": "daxpay-h5",
"type": "module", "type": "module",
"version": "2.1.0", "version": "3.0.0",
"private": true,
"packageManager": "pnpm@8.6.10",
"author": {
"name": "xiangshu233",
"email": "xiangshu233@outlook.com",
"url": "https://github.com/xiangshu233"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/xiangshu233/vue3-vant4-mobile.git"
},
"bugs": {
"url": "https://github.com/xiangshu233/vue3-vant4-mobile/issues"
},
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0", "node": ">=18.12.0",
"pnpm": ">=8.6.10" "pnpm": ">=9.0.2"
}, },
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
@@ -40,60 +25,58 @@
}, },
"dependencies": { "dependencies": {
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@unocss/reset": "^0.58.5", "@unocss/reset": "^0.58.9",
"@vueuse/core": "^10.7.0", "@vueuse/core": "^10.11.1",
"axios": "^1.4.0", "axios": "^1.7.7",
"date-fns": "^3.0.6", "date-fns": "^3.6.0",
"echarts": "^5.4.3",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.1.7", "pinia": "^2.2.2",
"pinia-plugin-persist": "^1.0.0", "pinia-plugin-persist": "^1.0.0",
"qs": "^6.11.2", "qs": "^6.13.0",
"vant": "^4.8.1", "vant": "^4.9.7",
"vue": "^3.3.13", "vue": "^3.5.8",
"vue-router": "4.2.5" "vue-router": "4.2.5"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^2.6.3", "@antfu/eslint-config": "^2.27.3",
"@commitlint/cli": "^18.4.3", "@commitlint/cli": "^18.6.1",
"@commitlint/config-conventional": "^18.4.3", "@commitlint/config-conventional": "^18.6.3",
"@iconify/json": "^2.2.188", "@iconify/json": "^2.2.252",
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
"@types/mockjs": "^1.0.10", "@types/mockjs": "^1.0.10",
"@types/node": "^20.10.5", "@types/node": "^20.16.5",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/qs": "^6.9.11", "@types/qs": "^6.9.16",
"@unocss/eslint-plugin": "^0.58.4", "@unocss/eslint-plugin": "^0.58.9",
"@unocss/preset-icons": "^0.58.5", "@unocss/preset-icons": "^0.58.9",
"@unocss/preset-rem-to-px": "^0.58.5", "@unocss/preset-rem-to-px": "^0.58.9",
"@unocss/transformer-directives": "^0.58.4", "@unocss/transformer-directives": "^0.58.9",
"@unocss/transformer-variant-group": "^0.58.4", "@unocss/transformer-variant-group": "^0.58.9",
"@vitejs/plugin-vue": "^5.0.0", "@vitejs/plugin-vue": "^5.1.4",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.20",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cz-git": "^1.8.0", "cz-git": "^1.9.4",
"dotenv": "^16.3.1", "dotenv": "^16.4.5",
"eslint": "^8.56.0", "eslint": "^8.57.1",
"eslint-plugin-format": "^0.1.0", "eslint-plugin-format": "^0.1.2",
"esno": "^0.16.3", "esno": "^0.16.3",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"less": "^4.2.0", "less": "^4.2.0",
"lint-staged": "^15.2.0", "lint-staged": "^15.2.10",
"only-allow": "^1.2.1", "only-allow": "^1.2.1",
"picocolors": "^1.0.0", "picocolors": "^1.1.0",
"postcss": "^8.4.32", "postcss": "^8.4.47",
"postcss-mobile-forever": "^4.0.0", "postcss-mobile-forever": "^4.1.6",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^4.9.1", "rollup": "^4.22.4",
"rollup-plugin-visualizer": "^5.11.0", "rollup-plugin-visualizer": "^5.12.0",
"simple-git-hooks": "^2.9.0", "simple-git-hooks": "^2.11.1",
"typescript": "^5.3.3", "typescript": "^5.6.2",
"unocss": "^0.58.5", "unocss": "^0.58.9",
"unplugin-auto-import": "^0.17.5", "unplugin-auto-import": "^0.17.8",
"unplugin-vue-components": "^0.26.0", "unplugin-vue-components": "^0.26.0",
"vite": "^5.0.10", "vite": "5.2.6",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2", "vite-plugin-html": "^3.2.2",
"vite-plugin-mock": "^2.9.8", "vite-plugin-mock": "^2.9.8",

11176
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,86 +0,0 @@
import { Result } from '#/axios'
import { http } from '@/utils/http/axios'
/**
* 获取文件预览地址
*/
export const getFilePreviewUrl = (id) => {
return http.request<Result<string>>({
url: `/file/getFilePreviewUrl`,
method: 'get',
params: { id },
})
}
/**
* 获取文件预览地址前缀
*/
export const getFilePreviewUrlPrefix = () => {
return http.request<Result<string>>({
method: 'get',
url: `/file/getFilePreviewUrlPrefix`,
})
}
/**
* 获取文件下载地址
*/
export const getFileDownloadUrl = (id) => {
return http.request<Result<string>>({
method: 'get',
url: `/file/getFileDownloadUrl`,
params: { id },
})
}
/**
* 上传文件信息
*/
export interface UpdateFileInfo {
// id
id?: number
// 文件访问地址
url?: string
// 文件大小,单位字节
size?: string
// 文件名称
filename?: string
// 原始文件名
originalFilename?: string
// 基础存储路径
basePath?: string
// 存储路径
path?: string
// 文件扩展名
ext?: string
// MIME类型
contentType?: string
// 存储平台
platform?: string
// 缩略图访问路径
thUrl?: string
// 缩略图名称
thFilename?: string
// 缩略图大小,单位字节
thSize?: string
// 缩略图MIME类型
thContentType?: string
// 文件所属对象id
objectId?: string
// 文件所属对象类型,例如用户头像,评价图片
objectType?: string
// 文件元数据
metadata?: string
// 文件用户元数据
userMetadata?: string
// 缩略图元数据
thMetadata?: string
// 缩略图用户元数据
thUserMetadata?: string
// 附加属性
attr?: string
// 文件ACL
fileAcl?: string
// 缩略图文件ACL
thFileAcl?: string
}

View File

@@ -1,5 +1,5 @@
import { http } from '@/utils/http/axios' import { http } from '@/utils/http/axios'
import { Result } from '#/axios' import type { Result } from '#/axios'
export interface BasicResponseModel<T = any> { export interface BasicResponseModel<T = any> {
code: number code: number

View File

@@ -1,14 +0,0 @@
// token key
export const TOKEN_KEY = 'TOKEN'
// user info key
export const USER_INFO_KEY = 'USER__INFO__'
// role info key
export const ROLES_KEY = 'ROLES__KEY__'
// base global local key
export const BASE_LOCAL_CACHE_KEY = 'LOCAL__CACHE__KEY__'
// base global session key
export const BASE_SESSION_CACHE_KEY = 'SESSION__CACHE__KEY__'

View File

@@ -1,11 +1,9 @@
/* eslint-disable ts/no-duplicate-enum-values */
export enum PageEnum { export enum PageEnum {
// 登录 // 登录
BASE_LOGIN = '/login', BASE_LOGIN = '/login',
BASE_LOGIN_NAME = 'Login', BASE_LOGIN_NAME = 'Login',
// 首页 // 首页
BASE_HOME = '/dashboard', BASE_HOME = '/dashboard',
BASE_HOME_REDIRECT = '/dashboard',
// 错误 // 错误
ERROR_PAGE_NAME = 'ErrorPage', ERROR_PAGE_NAME = 'ErrorPage',
} }

View File

@@ -10,11 +10,10 @@ export function useGlobSetting(): Readonly<GlobConfig> {
VITE_GLOB_APP_SHORT_NAME, VITE_GLOB_APP_SHORT_NAME,
VITE_GLOB_API_URL_PREFIX, VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL, VITE_GLOB_UPLOAD_URL,
VITE_GLOB_PROD_MOCK,
VITE_GLOB_IMG_URL, VITE_GLOB_IMG_URL,
} = getAppEnvConfig() } = getAppEnvConfig()
if (!/[a-zA-Z\_]*/.test(VITE_GLOB_APP_SHORT_NAME)) { if (!/[a-z_]*/i.test(VITE_GLOB_APP_SHORT_NAME)) {
warn( warn(
`VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`, `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`,
) )
@@ -28,7 +27,6 @@ export function useGlobSetting(): Readonly<GlobConfig> {
shortName: VITE_GLOB_APP_SHORT_NAME, shortName: VITE_GLOB_APP_SHORT_NAME,
urlPrefix: VITE_GLOB_API_URL_PREFIX, urlPrefix: VITE_GLOB_API_URL_PREFIX,
uploadUrl: VITE_GLOB_UPLOAD_URL, uploadUrl: VITE_GLOB_UPLOAD_URL,
prodMock: VITE_GLOB_PROD_MOCK,
imgUrl: VITE_GLOB_IMG_URL, imgUrl: VITE_GLOB_IMG_URL,
} }
return glob as Readonly<GlobConfig> return glob as Readonly<GlobConfig>

View File

@@ -1,122 +0,0 @@
import type { EChartsOption } from 'echarts'
import type { Ref } from 'vue'
import type { Fn } from '@vueuse/core'
import { tryOnUnmounted, useDebounceFn } from '@vueuse/core'
import { computed, nextTick, ref, unref, watch } from 'vue'
import { useTimeoutFn } from '@/hooks/core/useTimeout'
import { useEventListener } from '@/hooks/event/useEventListener'
import { useBreakpoint } from '@/hooks/event/useBreakpoint'
import { useDesignSettingStore } from '@/store/modules/designSetting'
import echarts from '@/utils/lib/echarts'
export function useECharts(
elRef: Ref<HTMLDivElement>,
theme: 'light' | 'dark' | 'default' = 'default',
) {
const designStore = useDesignSettingStore()
const getDarkMode = computed(() => {
return theme === 'default' ? designStore.getDarkMode : theme
})
let chartInstance: echarts.ECharts | null = null
let resizeFn: Fn = resize
const cacheOptions = ref({})
let removeResizeFn: Fn = () => {}
resizeFn = useDebounceFn(resize, 200)
const getOptions = computed((): EChartsOption => {
if (getDarkMode.value !== 'dark') {
return cacheOptions.value
}
return {
backgroundColor: 'transparent',
...cacheOptions.value,
}
})
function initCharts(t = theme) {
const el = unref(elRef)
if (!el || !unref(el)) {
return
}
chartInstance = echarts.init(el, t)
const { removeEvent } = useEventListener({
el: window,
name: 'resize',
listener: resizeFn,
})
removeResizeFn = removeEvent
const { widthRef, screenEnum } = useBreakpoint()
if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
useTimeoutFn(() => {
resizeFn()
}, 30)
}
}
function setOptions(options: EChartsOption, clear = true) {
cacheOptions.value = options
if (unref(elRef)?.offsetHeight === 0) {
useTimeoutFn(() => {
setOptions(unref(getOptions))
}, 30)
return
}
nextTick(() => {
useTimeoutFn(() => {
if (!chartInstance) {
initCharts(getDarkMode.value as 'default')
if (!chartInstance) {
return
}
}
clear && chartInstance?.clear()
chartInstance?.setOption(unref(getOptions))
}, 30)
})
}
function resize() {
chartInstance?.resize()
}
watch(
() => getDarkMode.value,
(theme) => {
if (chartInstance) {
chartInstance.dispose()
initCharts(theme as 'default')
setOptions(cacheOptions.value)
}
},
)
tryOnUnmounted(() => {
if (!chartInstance) {
return
}
removeResizeFn()
chartInstance.dispose()
chartInstance = null
})
function getInstance(): echarts.ECharts | null {
if (!chartInstance) {
initCharts(getDarkMode.value as 'default')
}
return chartInstance
}
return {
setOptions,
resize,
echarts,
getInstance,
}
}

View File

@@ -24,12 +24,3 @@ export const ErrorPageRoute: RouteRecordRaw = {
}, },
], ],
} }
export const RootRoute: RouteRecordRaw = {
path: '/',
name: 'Root',
redirect: PageEnum.BASE_HOME,
meta: {
title: 'Root',
},
}

View File

@@ -1,4 +1,5 @@
import { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
import { PageEnum } from '@/enums/pageEnum'
const Layout = () => import('@/layout/index.vue') const Layout = () => import('@/layout/index.vue')
@@ -8,6 +9,7 @@ const Layout = () => import('@/layout/index.vue')
export const BusinessRoute: RouteRecordRaw = { export const BusinessRoute: RouteRecordRaw = {
path: '/', path: '/',
name: '', name: '',
redirect: PageEnum.BASE_HOME,
component: Layout, component: Layout,
children: [ children: [
{ {

View File

@@ -1,4 +1,4 @@
import { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
const Layout = () => import('@/layout/index.vue') const Layout = () => import('@/layout/index.vue')
@@ -6,8 +6,8 @@ const Layout = () => import('@/layout/index.vue')
* 演示模块路由 * 演示模块路由
*/ */
export const DemoRoute: RouteRecordRaw = { export const DemoRoute: RouteRecordRaw = {
path: '/', path: '/demo',
name: '', name: 'demo',
component: Layout, component: Layout,
children: [ children: [
{ {

View File

@@ -3,7 +3,7 @@ import type { RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import { createRouterGuards } from './router-guards' import { createRouterGuards } from './router-guards'
import routeModuleList from './modules' import routeModuleList from './modules'
import { ErrorPageRoute, RootRoute } from '@/router/base' import { ErrorPageRoute } from '@/router/base'
import { useRouteStoreWidthOut } from '@/store/modules/route' import { useRouteStoreWidthOut } from '@/store/modules/route'
// 菜单 // 菜单
@@ -13,7 +13,6 @@ import { DemoRoute } from '@/router/demo'
// 普通路由 // 普通路由
export const constantRouter: RouteRecordRaw[] = [ export const constantRouter: RouteRecordRaw[] = [
DemoRoute, DemoRoute,
RootRoute,
ErrorPageRoute, ErrorPageRoute,
BusinessRoute, BusinessRoute,
] ]

View File

@@ -19,7 +19,7 @@ export function getBoundingClientRect(element: Element): DOMRect | number {
} }
function trim(string: string) { function trim(string: string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '') return (string || '').replace(/^\s+|\s+$/g, '')
} }
/* istanbul ignore next */ /* istanbul ignore next */

View File

@@ -33,7 +33,7 @@ export function getAppEnvConfig() {
VITE_GLOB_IMG_URL, VITE_GLOB_IMG_URL,
} = ENV } = ENV
if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) { if (!/^[a-z_]*$/i.test(VITE_GLOB_APP_SHORT_NAME)) {
warn( warn(
`VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`, `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`,
) )

View File

@@ -55,7 +55,6 @@ export class VAxios {
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> { request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
let conf: any = cloneDeep(config) let conf: any = cloneDeep(config)
const transform = this.getTransform() const transform = this.getTransform()
const { requestOptions } = this.options const { requestOptions } = this.options
const opt: RequestOptions = { ...requestOptions, ...options } const opt: RequestOptions = { ...requestOptions, ...options }
@@ -69,7 +68,6 @@ export class VAxios {
conf.requestOptions = opt conf.requestOptions = opt
// 支持 FormData // 支持 FormData
conf = this.supportFormData(conf) conf = this.supportFormData(conf)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.axiosInstance this.axiosInstance
.request<any, AxiosResponse<Result>>(conf) .request<any, AxiosResponse<Result>>(conf)

View File

@@ -1,10 +1,13 @@
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动 // axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
import type { AxiosResponse } from 'axios'
import axios from 'axios'
import { showDialog, showFailToast } from 'vant'
import { VAxios } from './Axios' import { VAxios } from './Axios'
import { AxiosTransform } from './axiosTransform' import type { AxiosTransform } from './axiosTransform'
import axios, { AxiosResponse } from 'axios'
import { checkStatus } from './checkStatus' import { checkStatus } from './checkStatus'
import { joinTimestamp, formatRequestDate } from './helper' import { formatRequestDate, joinTimestamp } from './helper'
import { RequestEnum, ResultEnum, ContentTypeEnum } from '@/enums/httpEnum' import type { CreateAxiosOptions, RequestOptions } from './types'
import { ContentTypeEnum, RequestEnum, ResultEnum } from '@/enums/httpEnum'
import { PageEnum } from '@/enums/pageEnum' import { PageEnum } from '@/enums/pageEnum'
import { useGlobSetting } from '@/hooks/setting' import { useGlobSetting } from '@/hooks/setting'
@@ -12,17 +15,14 @@ import { isString } from '@/utils/is/'
import { deepMerge, isUrl } from '@/utils' import { deepMerge, isUrl } from '@/utils'
import { setObjToUrlParams } from '@/utils/urlUtils' import { setObjToUrlParams } from '@/utils/urlUtils'
import { RequestOptions, CreateAxiosOptions } from './types'
import { useUserStoreWidthOut } from '@/store/modules/user' import { useUserStoreWidthOut } from '@/store/modules/user'
const globSetting = useGlobSetting()
const urlPrefix = globSetting.urlPrefix || ''
import router from '@/router' import router from '@/router'
import { storage } from '@/utils/Storage' import { storage } from '@/utils/Storage'
import { showFailToast, showDialog } from 'vant' import type { Result } from '#/axios'
import { Result } from '#/axios'
const globSetting = useGlobSetting()
const urlPrefix = globSetting.urlPrefix
/** /**
* @description: 数据处理,方便区分多种处理方式 * @description: 数据处理,方便区分多种处理方式
@@ -70,10 +70,12 @@ const transform: AxiosTransform = {
}).then(() => { }).then(() => {
// on close // on close
}) })
} else if (!hasSuccess && (errorMessageText || isShowErrorMessage)) { }
else if (!hasSuccess && (errorMessageText || isShowErrorMessage)) {
// 是否显示自定义信息提示 // 是否显示自定义信息提示
showFailToast(msg || errorMessageText || '操作失败!') showFailToast(msg || errorMessageText || '操作失败!')
} else if (!hasSuccess && options.errorMessageMode === 'modal') { }
else if (!hasSuccess && options.errorMessageMode === 'modal') {
// errorMessageMode=custom-modal的时候会显示modal错误弹窗而不是消息提示用于一些比较重要的错误 // errorMessageMode=custom-modal的时候会显示modal错误弹窗而不是消息提示用于一些比较重要的错误
showDialog({ showDialog({
title: '提示', title: '提示',
@@ -100,7 +102,9 @@ const transform: AxiosTransform = {
case ResultEnum.TOKEN_EXPIRED: case ResultEnum.TOKEN_EXPIRED:
const LoginName = PageEnum.BASE_LOGIN_NAME const LoginName = PageEnum.BASE_LOGIN_NAME
const LoginPath = PageEnum.BASE_LOGIN const LoginPath = PageEnum.BASE_LOGIN
if (router.currentRoute.value?.name === LoginName) return if (router.currentRoute.value?.name === LoginName) {
return
}
// 到登录页 // 到登录页
errorMsg = '登录超时,请重新登录!' errorMsg = '登录超时,请重新登录!'
showDialog({ showDialog({
@@ -122,7 +126,6 @@ const transform: AxiosTransform = {
// 请求之前处理config // 请求之前处理config
beforeRequestHook: (config, options) => { beforeRequestHook: (config, options) => {
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options
const isUrlStr = isUrl(config.url as string) const isUrlStr = isUrl(config.url as string)
if (!isUrlStr && joinPrefix) { if (!isUrlStr && joinPrefix) {
@@ -138,22 +141,25 @@ const transform: AxiosTransform = {
if (!isString(params)) { if (!isString(params)) {
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。 // 给 get 请求加上时间戳参数,避免从缓存中拿数据。
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false)) config.params = Object.assign(params || {}, joinTimestamp(joinTime, false))
} else { }
else {
// 兼容restful风格 // 兼容restful风格
config.url = config.url + params + `${joinTimestamp(joinTime, true)}` config.url = `${config.url + params}${joinTimestamp(joinTime, true)}`
config.params = undefined config.params = undefined
} }
} else { }
else {
if (!isString(params)) { if (!isString(params)) {
formatDate && formatRequestDate(params) formatDate && formatRequestDate(params)
if ( if (
Reflect.has(config, 'data') && Reflect.has(config, 'data')
config.data && && config.data
(Object.keys(config.data).length > 0 || config.data instanceof FormData) && (Object.keys(config.data).length > 0 || config.data instanceof FormData)
) { ) {
config.data = data config.data = data
config.params = params config.params = params
} else { }
else {
config.data = data config.data = data
// params 是添加到 url 的请求字符串中的,用于 get 请求 // params 是添加到 url 的请求字符串中的,用于 get 请求
config.params = params config.params = params
@@ -161,10 +167,11 @@ const transform: AxiosTransform = {
if (joinParamsToUrl) { if (joinParamsToUrl) {
config.url = setObjToUrlParams( config.url = setObjToUrlParams(
config.url as string, config.url as string,
Object.assign({}, config.params, config.data), { ...config.params, ...config.data },
) )
} }
} else { }
else {
// 兼容restful风格 // 兼容restful风格
config.url = config.url + params config.url = config.url + params
config.params = undefined config.params = undefined
@@ -192,11 +199,11 @@ const transform: AxiosTransform = {
responseInterceptorsCatch: (error: any) => { responseInterceptorsCatch: (error: any) => {
const { response, code, message } = error || {} const { response, code, message } = error || {}
// TODO 此处要根据后端接口返回格式修改 // TODO 此处要根据后端接口返回格式修改
const msg: string = const msg: string
response && response.data && response.data.message ? response.data.message : '' = response && response.data && response.data.message ? response.data.message : ''
const err: string = error.toString() const err: string = error.toString()
try { try {
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { if (code === 'ECONNABORTED' && message.includes('timeout')) {
showFailToast('接口请求超时,请刷新页面重试!') showFailToast('接口请求超时,请刷新页面重试!')
return return
} }
@@ -209,7 +216,8 @@ const transform: AxiosTransform = {
.catch(() => {}) .catch(() => {})
return Promise.reject(error) return Promise.reject(error)
} }
} catch (error) { }
catch (error) {
console.log(error) console.log(error)
throw new Error(error as any) throw new Error(error as any)
} }
@@ -217,10 +225,11 @@ const transform: AxiosTransform = {
const isCancel = axios.isCancel(error) const isCancel = axios.isCancel(error)
if (!isCancel) { if (!isCancel) {
checkStatus(error.response && error.response.status, msg) checkStatus(error.response && error.response.status, msg)
} else { }
else {
console.warn(error, '请求被取消!') console.warn(error, '请求被取消!')
} }
//return Promise.reject(error); // return Promise.reject(error);
return Promise.reject(response?.data) return Promise.reject(response?.data)
}, },
} }
@@ -257,7 +266,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
// 接口地址 // 接口地址
apiUrl: globSetting.apiUrl, apiUrl: globSetting.apiUrl,
// 接口拼接地址 // 接口拼接地址
urlPrefix: urlPrefix, urlPrefix,
// 是否加入时间戳 // 是否加入时间戳
joinTime: true, joinTime: true,
// 忽略重复请求 // 忽略重复请求

View File

@@ -91,9 +91,9 @@ export function hexToRgba(hex: string, opacity: number) {
opacity = opacity >= 0 && opacity <= 1 ? Number(opacity) : 1 opacity = opacity >= 0 && opacity <= 1 ? Number(opacity) : 1
return result return result
? `rgba(${ ? `rgba(${
[Number.parseInt(result[1], 16), Number.parseInt(result[2], 16), Number.parseInt(result[3], 16), opacity].join( [Number.parseInt(result[1], 16), Number.parseInt(result[2], 16), Number.parseInt(result[3], 16), opacity].join(
',', ',',
) )
})` })`
: hex : hex
} }

View File

@@ -1,57 +0,0 @@
import * as echarts from 'echarts/core'
import {
BarChart,
GaugeChart,
LineChart,
MapChart,
PictorialBarChart,
PieChart,
RadarChart,
} from 'echarts/charts'
import {
AriaComponent,
CalendarComponent,
DataZoomComponent,
GridComponent,
LegendComponent,
MarkLineComponent,
ParallelComponent,
PolarComponent,
RadarComponent,
TimelineComponent,
TitleComponent,
ToolboxComponent,
TooltipComponent,
VisualMapComponent,
} from 'echarts/components'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
GaugeChart,
SVGRenderer,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
MarkLineComponent,
])
export default echarts

View File

@@ -74,6 +74,7 @@ declare global {
const onStartTyping: typeof import('@vueuse/core')['onStartTyping'] const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
const onUnmounted: typeof import('vue')['onUnmounted'] const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated'] const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide'] const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal'] const provideLocal: typeof import('@vueuse/core')['provideLocal']
@@ -185,6 +186,7 @@ declare global {
const useFullscreen: typeof import('@vueuse/core')['useFullscreen'] const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGamepad: typeof import('@vueuse/core')['useGamepad'] const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useId: typeof import('vue')['useId']
const useIdle: typeof import('@vueuse/core')['useIdle'] const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage'] const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
@@ -201,6 +203,7 @@ declare global {
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMemoize: typeof import('@vueuse/core')['useMemoize'] const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory'] const useMemory: typeof import('@vueuse/core')['useMemory']
const useModel: typeof import('vue')['useModel']
const useMounted: typeof import('@vueuse/core')['useMounted'] const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse'] const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement'] const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
@@ -248,6 +251,7 @@ declare global {
const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
const useSupported: typeof import('@vueuse/core')['useSupported'] const useSupported: typeof import('@vueuse/core')['useSupported']
const useSwipe: typeof import('@vueuse/core')['useSwipe'] const useSwipe: typeof import('@vueuse/core')['useSwipe']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] const useTextSelection: typeof import('@vueuse/core')['useTextSelection']

18
types/axios.d.ts vendored
View File

@@ -2,19 +2,19 @@
* 通用响应类 * 通用响应类
*/ */
export interface Result<T = any> { export interface Result<T = any> {
code: number; code: number
type: 'success' | 'error' | 'warning'; type: 'success' | 'error' | 'warning'
msg: string; msg: string
traceId: string | null | undefined; traceId: string | null | undefined
data: T; data: T
} }
/** /**
* 分页响应类 * 分页响应类
*/ */
export interface PageResult<T = any> { export interface PageResult<T = any> {
current: number; current: number
records: Array<T>; records: Array<T>
size: number; size: number
total: number; total: number
} }

28
types/config.d.ts vendored
View File

@@ -1,26 +1,26 @@
export interface GlobConfig { export interface GlobConfig {
title: string; title: string
titleCN: string; titleCN: string
apiUrl: string; apiUrl: string
shortName: string; shortName: string
urlPrefix?: string; urlPrefix?: string
uploadUrl?: string; uploadUrl?: string
imgUrl?: string; imgUrl?: string
} }
export interface GlobEnvConfig { export interface GlobEnvConfig {
// 标题 // 标题
VITE_GLOB_APP_TITLE: string; VITE_GLOB_APP_TITLE: string
// 中文标题 // 中文标题
VITE_GLOB_APP_TITLE_CN: string; VITE_GLOB_APP_TITLE_CN: string
// 接口地址 // 接口地址
VITE_GLOB_API_URL: string; VITE_GLOB_API_URL: string
// 接口前缀 // 接口前缀
VITE_GLOB_API_URL_PREFIX?: string; VITE_GLOB_API_URL_PREFIX?: string
// Project abbreviation // Project abbreviation
VITE_GLOB_APP_SHORT_NAME: string; VITE_GLOB_APP_SHORT_NAME: string
// 图片上传地址 // 图片上传地址
VITE_GLOB_UPLOAD_URL?: string; VITE_GLOB_UPLOAD_URL?: string
// 图片前缀地址 // 图片前缀地址
VITE_GLOB_IMG_URL?: string; VITE_GLOB_IMG_URL?: string
} }

74
types/global.d.ts vendored
View File

@@ -1,9 +1,9 @@
import type { import type {
VNodeChild,
ComponentPublicInstance, ComponentPublicInstance,
FunctionalComponent, FunctionalComponent,
VNodeChild,
PropType as VuePropType, PropType as VuePropType,
} from 'vue'; } from 'vue'
// declare global 在具有 import 或 export 声明全局范围内的事物的文件中使用。 // declare global 在具有 import 或 export 声明全局范围内的事物的文件中使用。
// 这在包含 import 或 export 因为此类文件被视为模块的文件中是必需的,并且在模块中声明的任何内容都在模块范围内。 // 这在包含 import 或 export 因为此类文件被视为模块的文件中是必需的,并且在模块中声明的任何内容都在模块范围内。
@@ -12,64 +12,64 @@ import type {
declare global { declare global {
const __APP_INFO__: { const __APP_INFO__: {
pkg: { pkg: {
name: string; name: string
version: string; version: string
dependencies: Recordable<string>; dependencies: Recordable<string>
devDependencies: Recordable<string>; devDependencies: Recordable<string>
}; }
lastBuildTime: string; lastBuildTime: string
}; }
// vue // vue
type PropType<T> = VuePropType<T>; type PropType<T> = VuePropType<T>
type VueNode = VNodeChild | JSX.Element; type VueNode = VNodeChild | JSX.Element
export type Writable<T> = { export type Writable<T> = {
-readonly [P in keyof T]: T[P]; -readonly [P in keyof T]: T[P];
}; }
type Nullable<T> = T | null; type Nullable<T> = T | null
type NonNullable<T> = T extends null | undefined ? never : T; type NonNullable<T> = T extends null | undefined ? never : T
type Recordable<T = any> = Record<string, T>; type Recordable<T = any> = Record<string, T>
type ReadonlyRecordable<T = any> = { interface ReadonlyRecordable<T = any> {
readonly [key: string]: T; readonly [key: string]: T
}; }
type Indexable<T = any> = { interface Indexable<T = any> {
[key: string]: T; [key: string]: T
}; }
type DeepPartial<T> = { type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>; [P in keyof T]?: DeepPartial<T[P]>;
}; }
type TimeoutHandle = ReturnType<typeof setTimeout>; type TimeoutHandle = ReturnType<typeof setTimeout>
type IntervalHandle = ReturnType<typeof setInterval>; type IntervalHandle = ReturnType<typeof setInterval>
interface ChangeEvent extends Event { interface ChangeEvent extends Event {
target: HTMLInputElement; target: HTMLInputElement
} }
interface WheelEvent { interface WheelEvent {
path?: EventTarget[]; path?: EventTarget[]
} }
interface ImportMetaEnv extends ViteEnv { interface ImportMetaEnv extends ViteEnv {
__: unknown; __: unknown
} }
interface ViteEnv { interface ViteEnv {
VITE_PORT: number; VITE_PORT: number
VITE_PUBLIC_PATH: string; VITE_PUBLIC_PATH: string
VITE_GLOB_APP_TITLE: string; VITE_GLOB_APP_TITLE: string
VITE_GLOB_APP_SHORT_NAME: string; VITE_GLOB_APP_SHORT_NAME: string
VITE_DROP_CONSOLE: boolean; VITE_DROP_CONSOLE: boolean
VITE_GLOB_IMG_URL: string; VITE_GLOB_IMG_URL: string
VITE_PROXY: [string, string][]; VITE_PROXY: [string, string][]
VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'; VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean; VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean
} }
} }
declare module 'vue' { declare module 'vue' {
export type JSXComponent<Props = any> = export type JSXComponent<Props = any> =
| { new (): ComponentPublicInstance<Props> } | { new (): ComponentPublicInstance<Props> }
| FunctionalComponent<Props>; | FunctionalComponent<Props>
} }

26
types/index.d.ts vendored
View File

@@ -1,29 +1,29 @@
declare interface Fn<T = any, R = T> { declare interface Fn<T = any, R = T> {
(...arg: T[]): R; (...arg: T[]): R
} }
declare interface PromiseFn<T = any, R = T> { declare interface PromiseFn<T = any, R = T> {
(...arg: T[]): Promise<R>; (...arg: T[]): Promise<R>
} }
declare type RefType<T> = T | null; declare type RefType<T> = T | null
// 就是数组里的 value 是这个对象类型 // 就是数组里的 value 是这个对象类型
declare type LabelValueOptions = { declare type LabelValueOptions = {
label: string; label: string
value: any; value: any
disabled: boolean; disabled: boolean
[key: string]: string | number | boolean; [key: string]: string | number | boolean
}[]; }[]
declare type EmitType = (event: string, ...args: any[]) => void; declare type EmitType = (event: string, ...args: any[]) => void
declare type TargetContext = '_self' | '_blank'; declare type TargetContext = '_self' | '_blank'
declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> { declare interface ComponentElRef<T extends HTMLElement = HTMLDivElement> {
$el: T; $el: T
} }
declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null; declare type ComponentRef<T extends HTMLElement = HTMLDivElement> = ComponentElRef<T> | null
declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>; declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>

7
types/modules.d.ts vendored
View File

@@ -1,7 +1,8 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare module '*.vue' { declare module '*.vue' {
import { DefineComponent } from 'vue'; import type { DefineComponent } from 'vue'
const Component: DefineComponent<{}, {}, any>;
export default Component; const Component: DefineComponent<{}, {}, any>
export default Component
} }

18
types/web.d.ts vendored
View File

@@ -1,13 +1,13 @@
import { PageResult } from "@/types/axios"; import type { PageResult } from '@/types/axios'
/** /**
* 分页参数 * 分页参数
*/ */
export interface PageParam { export interface PageParam {
// 每页数量 // 每页数量
size: number; size: number
// 当前页数 // 当前页数
current: number; current: number
} }
/** /**
@@ -15,24 +15,24 @@ export interface PageParam {
*/ */
export interface TablePageModel<T = any> { export interface TablePageModel<T = any> {
// 分页参数 // 分页参数
pages: PageParam; pages: PageParam
// 查询参数 // 查询参数
queryParam: object; queryParam: object
// 结果 // 结果
pagination: PageResult<T>; pagination: PageResult<T>
} }
/** /**
* 基础实体对象 * 基础实体对象
*/ */
export interface BaseEntity { export interface BaseEntity {
id?: number | string | null; id?: number | string | null
} }
/** /**
* 键值对对象 * 键值对对象
*/ */
export interface KeyValue { export interface KeyValue {
key: string; key: string
value: string; value: string
} }

View File

@@ -48,12 +48,12 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
alias: [ alias: [
// @/xxxx => src/xxxx // @/xxxx => src/xxxx
{ {
find: /\@\//, find: /@\//,
replacement: `${pathResolve('src')}/`, replacement: `${pathResolve('src')}/`,
}, },
// #/xxxx => types/xxxx // #/xxxx => types/xxxx
{ {
find: /\#\//, find: /#\//,
replacement: `${pathResolve('types')}/`, replacement: `${pathResolve('types')}/`,
}, },
], ],