提交 f42e00c7 作者: 方治民

feat: 完成网络请求适配(与 Web 端保持用法一致)、更新 pont 模板增加示例接口、代码格式化统一等

上级 8cb757d9
......@@ -6,7 +6,7 @@ end_of_line=lf
insert_final_newline=true
indent_style=space
indent_size=4
max_line_length = 100
max_line_length = 120
[*.{yml,yaml}]
indent_style = space
......
# API 接口地址
VITE_GLOB_API_URL=http://localhost:8080
VITE_GLOB_API_URL=http://localhost:8181
# API 接口地址前缀
VITE_GLOB_API_URL_PREFIX=/api
......@@ -14,3 +14,5 @@ dist
Dockerfile
/example
unpackage
types/auto-imports.d.ts
......@@ -10,16 +10,22 @@ module.exports = {
jsx: true,
},
},
extends: [
'prettier',
'plugin:prettier/recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
],
extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-extra-semi': 'off',
'vue/script-setup-uses-vars': 'error',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'vue/custom-event-name-casing': 'off',
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'no-alert': 'error',
'vue/html-self-closing': 0,
'vue/html-indent': ['error', 4],
......
......@@ -31,3 +31,5 @@ pnpm-debug.log*
.vite
.hbuilderx
unpackage
.mocks/
\ No newline at end of file
......@@ -9,3 +9,5 @@
/public/*
manifest.json
types/auto-imports.d.ts
......@@ -22,10 +22,13 @@
<!-- prettier-ignore -->
- [x] 项目构建,文档编写
- [x] [conventional-changelog](https://www.cnblogs.com/mengfangui/p/12634845.html)
- [ ] 完善网络请求相关配置
- [ ] 集成 [Pont](https://github.com/alibaba/pont)
- [x] [changelog](https://www.cnblogs.com/mengfangui/p/12634845.html)
- [x] 完善网络请求相关配置
- [x] 集成 [Pont](https://github.com/alibaba/pont)
- [ ] 适配上传/下载接口的自动化生成模板(包装 uni.uploadFile 与 uni.downloadFile 方法实现)
- [ ] 集成 vue-i18n
- [ ] 完善页面主体布局
- [ ] 设计模块化权限控制
- [ ] 接入 [消息推送](https://uniapp.dcloud.net.cn/unipush.html)
- [ ] 接入 [APP 升级中心](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html)
- [ ] 跟进官方更新进度,将 uni-app 依赖升级到 3.0 正式版,[日志](https://uniapp.dcloud.io/release-note-alpha.html)
/**
* Get the configuration file variable name
* @param env
*/
export const getConfigFileName = (env: Record<string, any>) => {
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '')
}
......@@ -13,9 +13,11 @@ export function configAutoImportPlugin(): Plugin {
imports: [
'vue',
'uni-app',
// '@vueuse/core',
{ '/@/config/app': ['$app'] },
{ '/@/api/types': ['API'] },
{
'/@/config/app': ['$app'],
'/@/api/services': ['defs'],
'/@/api/services/mods': ['API'],
},
],
})
}
......@@ -4,12 +4,7 @@ import { configAutoImportPlugin } from './autoImport'
import pkg from '../../package.json'
export function createVitePlugins(viteEnv: ViteEnv) {
const {
VITE_GLOB_APP_NAME,
VITE_GLOB_APP_DESCRIPTION,
VITE_GLOB_API_URL,
VITE_GLOB_API_URL_PREFIX,
} = viteEnv
const { VITE_GLOB_APP_NAME, VITE_GLOB_APP_DESCRIPTION, VITE_GLOB_API_URL, VITE_GLOB_API_URL_PREFIX } = viteEnv
// 以红色字体输出信息
const color = '\x1b[91m'
......
......@@ -10,6 +10,8 @@
- ⭐Prettier - Code formatter
- ⭐EditorConfig
- ⭐TODO Highlight
- ⭐Volar
-[pont](https://marketplace.visualstudio.com/items?itemName=jasonHzq.vscode-pont) 接口自动化工具,**必装**
- ESLint
- stylelint
......@@ -27,7 +29,6 @@
- Path Intellisense
- Turbo Console Log
- Vetur/Volar (eg: 两者二选一, Volar 对于 Vue3+TS 相对较友好, **本项目采用 Volar**)
- Ant-Design-Vue-Helper
- GitLens
......
......@@ -75,9 +75,11 @@
"@dcloudio/uni-mp-weixin": "^3.0.0-alpha-3040220220310005",
"@dcloudio/uni-quickapp-webview": "^3.0.0-alpha-3040220220310005",
"@vueuse/core": "^8.1.2",
"axios": "^0.26.1",
"dayjs": "^1.11.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"qs": "^6.10.3",
"vue": "^3.2.31"
},
"devDependencies": {
......@@ -91,6 +93,7 @@
"@types/lodash-es": "^4.17.6",
"@types/mockjs": "^1.0.6",
"@types/prettier": "^2.4.4",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"commitizen": "^4.2.4",
......@@ -105,6 +108,7 @@
"less": "^4.1.2",
"lint-staged": "^12.3.7",
"npm-run-all": "^4.1.5",
"pont-engine": "^1.2.0",
"postcss": "^8.4.12",
"postcss-html": "^1.3.0",
"postcss-less": "^6.0.0",
......
{
"originUrl": "http://localhost:8181/api/v2/api-docs",
"templatePath": "./pont.template",
"outDir": "./src/api/services",
"surrounding": "typeScript",
"mocks": {
"enable": true,
"basePath": "",
"port": 3101,
"wrapper": "{\"status\": 200, \"body\": {response}, \"message\": \"OK\"}"
},
"templateType": "fetch",
"prettierConfig": {
"printWidth": 120,
"semi": false,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "all",
"proseWrap": "never",
"endOfLine": "lf"
}
}
import { Interface, BaseClass, Property, CodeGenerator } from 'pont-engine'
// 接口 API 前缀
// 通常与项目的 env 配置中的 VITE_GLOB_API_URL_PREFIX 相同
const API_URL_PREFIX = '/api'
export default class BasicGenerator extends CodeGenerator {
getParams(inter: Interface, paramsCode: string) {
let requestParams = inter.getRequestParams(this.surrounding)
const prettier = require('prettier')
if (prettier.format(paramsCode, { parser: 'typescript' }).includes('{}')) {
requestParams = requestParams.replace('params', 'params?')
}
return `${requestParams.replace(
'options?: any',
`config?: http.RequestConfig<Params${requestParams.includes('form') ? ' | FormData' : ''}>`,
)}, options?: http.RequestOptions`
}
getInterfaceContentInDeclaration(inter: Interface) {
const paramsCode = inter.getParamsCode('Params')
const requestParams = this.getParams(inter, paramsCode)
return `
export ${paramsCode}
export type Response = ${inter.responseType.replace(/defs.Result\<(.*)\>/, '$1')};
export const init: Response;
export function request(${requestParams}): Promise<Response>;
`
}
getBaseClassInDeclaration(base: BaseClass) {
const originProps = base.properties
base.properties = base.properties.map((prop) => {
return new Property({
...prop,
required: false,
})
})
const result = super.getBaseClassInDeclaration(base)
base.properties = originProps
return result
}
getInterfaceContent(inter: Interface) {
const method = inter.method.toUpperCase()
const paramsCode = inter.getParamsCode('Params', this.surrounding)
const requestParams = this.getParams(inter, paramsCode)
return `
/**
* @desc ${inter.description}
*/
import * as defs from '../../baseClass';
import { defHttp } from '/@/utils/http/axios'
export ${paramsCode}
export const init = ${inter.response.getInitialValue()};
export function request(${requestParams}) {
return defHttp.request({
url: "${inter.path.replace(API_URL_PREFIX, '')}",
method: '${method}',
${
method === 'GET'
? 'params'
: `data: ${requestParams.includes('form') ? 'form || params' : 'params'}`
},
...config,
}, options);
}
`
}
reviseModName(modName: string) {
// .replace(/\//g, '.').replace(/^\./, '').replace(/\./g, '_') 转换 / .为下划线
// exp: /api/v1/users => api_v1_users
// exp: api.v1.users => api_v1_users
return modName.replace(/\//g, '.').replace(/^\./, '').replace(/\./g, '_')
}
/** 获取所有模块的 index 入口文件 */
getModsIndex() {
let conclusion = `
export const API = {
${this.dataSource.mods.map((mod) => this.reviseModName(mod.name)).join(', \n')}
};
`
// dataSource name means multiple dataSource
if (this.dataSource.name) {
conclusion = `
export const ${this.dataSource.name} = {
${this.dataSource.mods.map((mod) => this.reviseModName(mod.name)).join(', \n')}
};
`
}
return `
${this.dataSource.mods
.map((mod) => {
const modName = this.reviseModName(mod.name)
return `import * as ${modName} from './${modName}';`
})
.join('\n')}
${conclusion}
`
}
/** 获取接口类和基类的总的 index 入口文件代码 */
getIndex() {
let conclusion = `
import * as defs from './baseClass';
import './mods/';
export { defs };
`
// dataSource name means multiple dataSource
if (this.dataSource.name) {
conclusion = `
import { ${this.dataSource.name} as defs } from './baseClass';
export { ${this.dataSource.name} } from './mods/';
export { defs };
`
}
return conclusion
}
}
module.exports = {
printWidth: 100,
printWidth: 120,
semi: false,
tabWidth: 4,
vueIndentScriptAndStyle: true,
......@@ -8,12 +8,4 @@ module.exports = {
proseWrap: 'never',
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'lf',
overrides: [
{
files: ['*.{yml,yaml,styl}'],
options: {
tabWidth: 2,
},
},
],
}
export class LoginVo {
/** token */
token = ''
/** 主键 */
userId = undefined
}
export class MenuVo {
/** 子权限 */
children = []
/** 组件 */
component = ''
/** 元数据 */
meta = undefined
/** 名称 */
name = ''
/** 路径 */
path = ''
/** 重定向 */
redirect = ''
}
export class PageVo {
/** 数据 */
data = []
/** 数据最新时间 */
latest = ''
/** 数据总数 */
total = undefined
}
export class PermissionVo {
/** 子权限 */
children = []
/** 组件 */
component = ''
/** 是否启用 */
enable = false
/** 是否隐藏 */
hidden = false
/** 图标 */
icon = ''
/** 主键 */
id = undefined
/** 元数据 */
meta = undefined
/** 名称 */
name = ''
/** 路径 */
path = ''
/** 父级ID */
pid = undefined
/** 序号 */
serial = undefined
/** 权限类型 */
type = 'DIR'
/** 标识 */
uid = ''
}
export class Result {
/** 内容 */
body = new LoginVo()
/** 业务标识码 */
code = undefined
/** 详细信息 */
details = ''
/** 异常信息 */
error = ''
/** 消息 */
message = ''
/** 状态码 */
status = undefined
/** 耗时 */
times = ''
/** 响应时间 */
timestamp = ''
}
export class RoleVo {
/** 主键 */
id = undefined
/** 名称 */
name = ''
/** 权限 */
permissions = []
/** 标识 */
uid = ''
}
export class UserInfo {
/** 头像 */
avatar = ''
/** 介绍 */
desc = ''
/** 用户主页 */
homePath = ''
/** 真实姓名 */
realName = ''
/** 角色 */
roles = []
/** 主键 */
userId = undefined
/** 用户名 */
username = ''
}
export class UserVo {
/** 头像 */
avatar = ''
/** 最后登录时间 */
createTime = ''
/** 是否删除 */
deleted = false
/** 邮箱 */
email = ''
/** 是否启用 */
enabled = false
/** 主键 */
id = undefined
/** 最后登录IP地址 */
lastLoginIp = ''
/** 最后登录时间 */
lastLoginTime = ''
/** 手机号 */
mobile = ''
/** 真实姓名 */
realName = ''
/** 职称 */
title = ''
/** 用户名 */
username = ''
}
import * as defs from './baseClass'
import './mods/'
export { defs }
/**
* @description
*/
import * as login from './login'
import * as logout from './logout'
import * as register from './register'
export { login, logout, register }
/**
* @desc 登录
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 账号(支持用户名/手机号/邮箱) */
account: string
/** 密码 */
password: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/auth/login',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 登出
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/auth/logout',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 注册
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 头像 */
avatar?: string
/** 邮箱 */
email?: string
/** 是否启用 */
enable?: boolean
/** 简介 */
introduction?: string
/** 手机号 */
mobile: string
/** 密码 */
password: string
/** 真实姓名 */
realName: string
/** 用户名 */
username: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/auth/register',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc fail
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/hello/fail',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc hello
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/hello/',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @description
*/
import * as hello from './hello'
import * as fail from './fail'
import * as page from './page'
export { hello, fail, page }
/**
* @desc page
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 当前页数 */
pageNo: number
/** 分页条数 */
pageSize: number
/** 排序字段 */
sortField?: string
/** 排序方向(ASC|DESC) */
sortOrder?: 'ASC' | 'DESC'
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/hello/page',
method: 'GET',
params,
...config,
},
options,
)
}
import * as auth from './auth'
import * as hello from './hello'
import * as minio from './minio'
import * as permission from './permission'
import * as role from './role'
import * as user from './user'
export const API = {
auth,
hello,
minio,
permission,
role,
user,
}
/**
* @description
*/
import * as upload from './upload'
export { upload }
/**
* @desc 文件上传
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(
params?: Params,
form: FormData,
config?: http.RequestConfig<Params | FormData>,
options?: http.RequestOptions,
) {
return defHttp.request(
{
url: '/common/minio/upload',
method: 'POST',
data: form || params,
...config,
},
options,
)
}
/**
* @desc 新增
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 组件 */
component?: string
/** 是否启用 */
enable?: boolean
/** 是否隐藏 */
hidden?: boolean
/** 图标 */
icon?: string
/** 元数据 */
meta?: string
/** 名称 */
name: string
/** 路径 */
path?: string
/** 父级ID */
pid?: number
/** 重定向 */
redirect?: string
/** 序号 */
serial?: number
/** 权限类型 */
type: 'DIR' | 'MENU' | 'BUTTON'
/** 标识 */
uid: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/add',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 删除
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/deleted',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/find',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @description
*/
import * as add from './add'
import * as deleted from './deleted'
import * as find from './find'
import * as modify from './modify'
import * as page from './page'
import * as tree from './tree'
export { add, deleted, find, modify, page, tree }
/**
* @desc 修改
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 组件 */
component?: string
/** 是否启用 */
enable?: boolean
/** 是否隐藏 */
hidden?: boolean
/** 图标 */
icon?: string
/** id */
id: number
/** 元数据 */
meta?: string
/** 名称 */
name: string
/** 路径 */
path?: string
/** 父级ID */
pid?: number
/** 重定向 */
redirect?: string
/** 序号 */
serial?: number
/** 权限类型 */
type: 'DIR' | 'MENU' | 'BUTTON'
/** 标识 */
uid: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/modify',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 分页查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 当前页数 */
pageNo: number
/** 分页条数 */
pageSize: number
/** 排序字段 */
sortField?: string
/** 排序方向(ASC|DESC) */
sortOrder?: 'ASC' | 'DESC'
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/page',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 树结构查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 父级 id */
pid?: number
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/permission/tree',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 新增
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 名称 */
name: string
/** 标识 */
uid: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/add',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 分配权限
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
/** ids 多个以逗号分割 */
ids: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/assign',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 删除
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/deleted',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/find',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @description
*/
import * as add from './add'
import * as assign from './assign'
import * as deleted from './deleted'
import * as find from './find'
import * as modify from './modify'
import * as page from './page'
import * as selector from './selector'
export { add, assign, deleted, find, modify, page, selector }
/**
* @desc 修改
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
/** 名称 */
name: string
/** 标识 */
uid: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/modify',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 分页查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 当前页数 */
pageNo: number
/** 分页条数 */
pageSize: number
/** 排序字段 */
sortField?: string
/** 排序方向(ASC|DESC) */
sortOrder?: 'ASC' | 'DESC'
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/page',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 选项查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/manage/role/selector',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 分配角色
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** id */
id: number
/** ids 多个以逗号分割 */
ids: string
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/user/manage/assign',
method: 'POST',
data: params,
...config,
},
options,
)
}
/**
* @desc 获取用户菜单
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/user/getMenuList',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 获取用户权限
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/user/getPermCode',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @desc 获取登录用户信息
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {}
export const init = new defs.Result()
export function request(params?: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/user/getUserInfo',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* @description
*/
import * as getMenuList from './getMenuList'
import * as getPermCode from './getPermCode'
import * as getUserInfo from './getUserInfo'
import * as assign from './assign'
import * as page from './page'
export { getMenuList, getPermCode, getUserInfo, assign, page }
/**
* @desc 分页查询
*/
import * as defs from '../../baseClass'
import { defHttp } from '/@/utils/http/axios'
export class Params {
/** 当前页数 */
pageNo: number
/** 分页条数 */
pageSize: number
/** 排序字段 */
sortField?: string
/** 排序方向(ASC|DESC) */
sortOrder?: 'ASC' | 'DESC'
}
export const init = new defs.Result()
export function request(params: Params, config?: http.RequestConfig<Params>, options?: http.RequestOptions) {
return defHttp.request(
{
url: '/user/manage/page',
method: 'GET',
params,
...config,
},
options,
)
}
/**
* 通用响应内容包装
*/
namespace API {
export interface Result<T = any> {
/**
* 状态码
*/
status: Status
/**
* 消息
*/
message: string
/**
* 响应时间
*/
timestamp: string
/**
* 接口耗时(不含网络通信时间)
*/
times: string
/**
* 自定义错误码
*/
code: number
/**
* 详细信息
*/
details?: string
/**
* 异常信息
*/
error?: string
/**
* 响应内容
*/
body: T
}
export interface Result<T = any> {
/**
* 状态码
*/
status: Status
/**
* 消息
*/
message: string
/**
* 响应时间
*/
timestamp: string
/**
* 接口耗时(不含网络通信时间)
*/
times: string
/**
* 自定义错误码
*/
code: number
/**
* 详细信息
*/
details?: string
/**
* 异常信息
*/
error?: string
/**
* 响应内容
*/
body: T
}
export enum Status {
/**
* 成功
*/
OK = 200,
/**
* 用户认证失败
*/
NON_AUTHORITATIVE_INFORMATION = 203,
/**
* 失败的请求,通常是一些验证错误(当出现该状态码时,将产生对应的业务错误编码,可以使用 Result.details 进行交互提醒)
*/
FAIL = 400,
/**
* 鉴权失败
*/
UNAUTHORIZED = 401,
/**
* Token 错误/失效
*/
FORBIDDEN = 403,
/**
* 找不到资源
*/
NOT_FOUND = 404,
/**
* 不支持的请求类型
*/
METHOD_NOT_ALLOWED = 405,
/**
* 服务器错误
*/
INTERNAL_SERVER_ERROR = 500,
/**
* 未知错误
*/
UNKNOWN_ERROR = 500,
/**
* API 未实现
*/
NOT_IMPLEMENTED = 501,
/**
* 服务异常(网关提醒)
*/
BAD_GATEWAY = 502,
/**
* 服务暂停(网关提醒)
*/
SERVICE_UNAVAILABLE = 503,
}
export enum Status {
/**
* 成功
*/
OK = 200,
/**
* 用户认证失败
*/
NON_AUTHORITATIVE_INFORMATION = 203,
/**
* 失败的请求,通常是一些验证错误(当出现该状态码时,将产生对应的业务错误编码,可以使用 Result.details 进行交互提醒)
*/
FAIL = 400,
/**
* 鉴权失败
*/
UNAUTHORIZED = 401,
/**
* Token 错误/失效
*/
FORBIDDEN = 403,
/**
* 找不到资源
*/
NOT_FOUND = 404,
/**
* 不支持的请求类型
*/
METHOD_NOT_ALLOWED = 405,
/**
* 服务器错误
*/
INTERNAL_SERVER_ERROR = 500,
/**
* 未知错误
*/
UNKNOWN_ERROR = 500,
/**
* API 未实现
*/
NOT_IMPLEMENTED = 501,
/**
* 服务异常(网关提醒)
*/
BAD_GATEWAY = 502,
/**
* 服务暂停(网关提醒)
*/
SERVICE_UNAVAILABLE = 503,
}
export function toMessage(status: Status): string {
switch (status) {
case Status.OK:
return '成功'
case Status.FAIL:
return '失败'
case Status.UNAUTHORIZED:
return '用户认证失败'
case Status.FORBIDDEN:
return '拒绝访问'
case Status.NOT_FOUND:
return '找不到资源'
case Status.INTERNAL_SERVER_ERROR:
return '服务器错误'
case Status.NOT_IMPLEMENTED:
return '未实现'
case Status.BAD_GATEWAY:
return '网关错误'
case Status.SERVICE_UNAVAILABLE:
return '服务暂停'
default:
return '未知错误'
}
export function toMessage(status: Status): string {
switch (status) {
case Status.OK:
return '成功'
case Status.FAIL:
return '失败'
case Status.UNAUTHORIZED:
return '用户认证失败'
case Status.FORBIDDEN:
return '拒绝访问'
case Status.NOT_FOUND:
return '找不到资源'
case Status.INTERNAL_SERVER_ERROR:
return '服务器错误'
case Status.NOT_IMPLEMENTED:
return '未实现'
case Status.BAD_GATEWAY:
return '网关错误'
case Status.SERVICE_UNAVAILABLE:
return '服务暂停'
default:
return '未知错误'
}
}
export { API }
// token key
export const TOKEN_KEY = 'TOKEN__'
export const LOCALE_KEY = 'LOCALE__'
// user info key
export const USER_INFO_KEY = 'USER__INFO__'
// role info key
export const ROLES_KEY = 'ROLES__KEY__'
// project config key
export const PROJ_CFG_KEY = 'PROJ__CFG__KEY__'
// lock info
export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__'
export const MULTIPLE_TABS_KEY = 'MULTIPLE_TABS__KEY__'
export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__'
// base global local key
export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__'
// base global session key
export const APP_SESSION_CACHE_KEY = 'COMMON__SESSION__KEY__'
export enum CacheTypeEnum {
SESSION,
LOCAL,
}
/**
* @description: Request result set
*/
export enum ResultEnum {}
/**
* @description: request method
*/
export enum RequestEnum {
GET = 'GET',
POST = 'POST',
PUT = 'PUT',
DELETE = 'DELETE',
}
/**
* @description: contentType
*/
export enum ContentTypeEnum {
// json
JSON = 'application/json;charset=UTF-8',
// form-data qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8',
}
const Message = {
success: (msg: string) => {
uni.showToast({
title: msg,
icon: 'success',
})
},
error: (msg: string) => {
uni.showToast({
title: msg,
icon: 'error',
})
},
}
const createErrorModal = (options: { title: string; content: string }) => {
uni.showModal({
title: options.title,
content: options.content,
showCancel: false,
})
}
/**
* @description: message
*/
export function useMessage() {
return {
createMessage: Message,
createErrorModal,
}
}
import type { GlobConfig } from '/#/config'
import { getAppEnvConfig } from '/@/utils/env'
export const useGlobSetting = (): Readonly<GlobConfig> => {
const {
VITE_GLOB_APP_NAME,
VITE_GLOB_APP_DESCRIPTION,
VITE_GLOB_API_URL,
VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL,
} = getAppEnvConfig()
// Take global configuration
const glob: Readonly<GlobConfig> = {
name: VITE_GLOB_APP_NAME,
description: VITE_GLOB_APP_DESCRIPTION,
apiUrl: VITE_GLOB_API_URL,
urlPrefix: VITE_GLOB_API_URL_PREFIX,
uploadUrl: VITE_GLOB_UPLOAD_URL,
}
return glob as Readonly<GlobConfig>
}
<script setup lang="ts">
const title = ref('Hello World')
// TODO: 测试接口
API.hello.hello.request().then((body) => {
console.log(body)
})
API.hello.page
.request({
pageNo: 1,
pageSize: 10,
})
.then((body) => {
console.log(body)
})
</script>
<template>
......
import { isDevMode } from '/@/utils/env'
// System default cache time, in seconds
export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7
// aes encryption key
export const cacheCipher = {
key: '_11111000001111@',
iv: '@11111000001111_',
}
// Whether the system cache is encrypted using aes
export const enableStorageEncryption = !isDevMode()
import { TOKEN_KEY } from '/@/enums/cacheEnum'
export function getToken() {
return getAuthCache(TOKEN_KEY)
}
export function getAuthCache(key: string): string | null {
try {
const value = uni.getStorageSync(key)
if (value) {
return value
}
} catch (e) {}
return null
}
export function setAuthCache(key: string, value: string) {
try {
uni.setStorageSync(key, value)
} catch (e) {}
}
export function clearAuthCache() {
try {
uni.clearStorageSync()
} catch (e) {}
}
import pkg from '../../package.json'
import { getConfigFileName } from '../../build/getConfigFileName'
export function getCommonStoragePrefix() {
return `${pkg.name}__${getEnv()}`.toUpperCase()
}
// Generate cache key according to version
export function getStorageShortName() {
return `${getCommonStoragePrefix()}${`__${pkg.version}`}__`.toUpperCase()
}
export function getAppEnvConfig() {
const ENV_NAME = getConfigFileName(import.meta.env)
const ENV = (import.meta.env.DEV
? // Get the global configuration (the configuration will be extracted independently when packaging)
(import.meta.env as unknown as ViteEnv)
: window[ENV_NAME as any]) as unknown as ViteEnv
const {
VITE_GLOB_APP_NAME,
VITE_GLOB_APP_DESCRIPTION,
VITE_GLOB_API_URL,
VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL,
} = ENV
return {
VITE_GLOB_APP_NAME,
VITE_GLOB_APP_DESCRIPTION,
VITE_GLOB_API_URL,
VITE_GLOB_API_URL_PREFIX,
VITE_GLOB_UPLOAD_URL,
}
}
/**
* @description: Development mode
*/
export const devMode = 'development'
/**
* @description: Production mode
*/
export const prodMode = 'production'
/**
* @description: Get environment variables
* @returns:
* @example:
*/
export function getEnv(): string {
return import.meta.env.MODE
}
/**
* @description: Is it a development mode
* @returns:
* @example:
*/
export function isDevMode(): boolean {
return import.meta.env.DEV
}
/**
* @description: Is it a production mode
* @returns:
* @example:
*/
export function isProdMode(): boolean {
return import.meta.env.PROD
}
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosError, AxiosPromise } from 'axios'
import type { RequestOptions, Result, UploadFileParams } from '/#/axios'
import type { CreateAxiosOptions } from './axiosTransform'
import axios from 'axios'
import qs from 'qs'
import { AxiosCanceler } from './axiosCancel'
import { isFunction } from '/@/utils/is'
import { cloneDeep } from 'lodash-es'
import { ContentTypeEnum } from '/@/enums/httpEnum'
import { RequestEnum } from '/@/enums/httpEnum'
/**
* 覆盖实现,使用 uni.request 实现网络请求
* @param config 请求配置
* @returns 请求结果
*/
axios.defaults.adapter = function (config: CreateAxiosOptions): AxiosPromise<any> {
return new Promise((resolve, reject) => {
uni.request({
method: config.method.toUpperCase() as RequestEnum,
url: config.url,
data: config.data || config.params,
header: config.headers,
responseType: config.responseType,
timeout: config.timeout,
dataType: 'json',
success: (response) => {
resolve({
config,
data: response.data,
headers: response.header,
status: response.statusCode,
statusText: '',
})
},
fail: (response) => {
reject({
config,
response: response.errMsg,
})
},
})
})
}
export * from './axiosTransform'
/**
* @description: axios module
*/
export class VAxios {
private axiosInstance: AxiosInstance
private readonly options: CreateAxiosOptions
constructor(options: CreateAxiosOptions) {
this.options = options
this.axiosInstance = axios.create(options)
this.setupInterceptors()
}
/**
* @description: Create axios instance
*/
private createAxios(config: CreateAxiosOptions): void {
this.axiosInstance = axios.create(config)
}
private getTransform() {
const { transform } = this.options
return transform
}
getAxios(): AxiosInstance {
return this.axiosInstance
}
/**
* @description: Reconfigure axios
*/
configAxios(config: CreateAxiosOptions) {
if (!this.axiosInstance) {
return
}
this.createAxios(config)
}
/**
* @description: Set general header
*/
setHeader(headers: any): void {
if (!this.axiosInstance) {
return
}
Object.assign(this.axiosInstance.defaults.headers, headers)
}
/**
* @description: Interceptor configuration
*/
private setupInterceptors() {
const transform = this.getTransform()
if (!transform) {
return
}
const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } =
transform
const axiosCanceler = new AxiosCanceler()
// Request interceptor configuration processing
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
// If cancel repeat request is turned on, then cancel repeat request is prohibited
// @ts-ignore
const { ignoreCancelToken } = config.requestOptions
const ignoreCancel =
ignoreCancelToken !== undefined ? ignoreCancelToken : this.options.requestOptions?.ignoreCancelToken
!ignoreCancel && axiosCanceler.addPending(config)
if (requestInterceptors && isFunction(requestInterceptors)) {
config = requestInterceptors(config, this.options)
}
return config
}, undefined)
// Request interceptor error capture
requestInterceptorsCatch &&
isFunction(requestInterceptorsCatch) &&
this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch)
// Response result interceptor processing
this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
res && axiosCanceler.removePending(res.config)
if (responseInterceptors && isFunction(responseInterceptors)) {
res = responseInterceptors(res)
}
return res
}, undefined)
// Response result interceptor error capture
responseInterceptorsCatch &&
isFunction(responseInterceptorsCatch) &&
this.axiosInstance.interceptors.response.use(undefined, (error) => {
// @ts-ignore
responseInterceptorsCatch(this.axiosInstance, error)
})
}
/**
* @description: File Upload
*/
uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
const formData = new window.FormData()
const customFilename = params.name || 'file'
if (params.filename) {
formData.append(customFilename, params.file, params.filename)
} else {
formData.append(customFilename, params.file)
}
if (params.data) {
Object.keys(params.data).forEach((key) => {
const value = params.data![key]
if (Array.isArray(value)) {
value.forEach((item) => {
formData.append(`${key}[]`, item)
})
return
}
formData.append(key, params.data![key])
})
}
return this.axiosInstance.request<T>({
...config,
method: 'POST',
data: formData,
headers: {
'Content-type': ContentTypeEnum.FORM_DATA,
// @ts-ignore
ignoreCancelToken: true,
},
})
}
// support form-data
supportFormData(config: AxiosRequestConfig) {
const headers = config.headers || this.options.headers
const contentType = headers?.['Content-Type'] || headers?.['content-type']
if (
contentType !== ContentTypeEnum.FORM_URLENCODED ||
!Reflect.has(config, 'data') ||
config.method?.toUpperCase() === RequestEnum.GET
) {
return config
}
return {
...config,
data: qs.stringify(config.data, { arrayFormat: 'brackets' }),
}
}
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
return this.request({ ...config, method: 'GET' }, options)
}
post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
return this.request({ ...config, method: 'POST' }, options)
}
put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
return this.request({ ...config, method: 'PUT' }, options)
}
delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
return this.request({ ...config, method: 'DELETE' }, options)
}
request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
let conf: CreateAxiosOptions = cloneDeep(config)
const transform = this.getTransform()
const { requestOptions } = this.options
const opt: RequestOptions = Object.assign({}, requestOptions, options)
const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {}
if (beforeRequestHook && isFunction(beforeRequestHook)) {
conf = beforeRequestHook(conf, opt)
}
conf.requestOptions = opt
conf = this.supportFormData(conf)
return new Promise((resolve, reject) => {
this.axiosInstance
.request<any, AxiosResponse<Result>>(conf)
.then((res: AxiosResponse<Result>) => {
if (transformRequestHook && isFunction(transformRequestHook)) {
try {
const ret = transformRequestHook(res, opt)
resolve(ret)
} catch (err) {
reject(err || new Error('request error!'))
}
return
}
resolve(res as unknown as Promise<T>)
})
.catch((e: Error | AxiosError) => {
if (requestCatchHook && isFunction(requestCatchHook)) {
reject(requestCatchHook(e, opt))
return
}
if (axios.isAxiosError(e)) {
// rewrite error message from axios in here
}
reject(e)
})
})
}
}
import type { AxiosRequestConfig, Canceler } from 'axios'
import axios from 'axios'
import { isFunction } from '/@/utils/is'
// Used to store the identification and cancellation function of each request
let pendingMap = new Map<string, Canceler>()
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&')
export class AxiosCanceler {
/**
* Add request
* @param {Object} config
*/
addPending(config: AxiosRequestConfig) {
this.removePending(config)
const url = getPendingUrl(config)
config.cancelToken =
config.cancelToken ||
new axios.CancelToken((cancel) => {
if (!pendingMap.has(url)) {
// If there is no current request in pending, add it
pendingMap.set(url, cancel)
}
})
}
/**
* @description: Clear all pending
*/
removeAllPending() {
pendingMap.forEach((cancel) => {
cancel && isFunction(cancel) && cancel()
})
pendingMap.clear()
}
/**
* Removal request
* @param {Object} config
*/
removePending(config: AxiosRequestConfig) {
const url = getPendingUrl(config)
if (pendingMap.has(url)) {
// If there is a current request identifier in pending,
// the current request needs to be cancelled and removed
const cancel = pendingMap.get(url)
cancel && cancel(url)
pendingMap.delete(url)
}
}
/**
* @description: reset
*/
reset(): void {
pendingMap = new Map<string, Canceler>()
}
}
import { AxiosError, AxiosInstance } from 'axios'
/**
* 请求重试机制
*/
export class AxiosRetry {
/**
* 重试
*/
retry(AxiosInstance: AxiosInstance, error: AxiosError) {
const { config } = error.response
// @ts-ignore
const { waitTime, count } = config?.requestOptions?.retryRequest
// @ts-ignore
config.__retryCount = config.__retryCount || 0
// @ts-ignore
if (config.__retryCount >= count) {
return Promise.reject(error)
}
// @ts-ignore
config.__retryCount += 1
return this.delay(waitTime).then(() => AxiosInstance(config))
}
/**
* 延迟
*/
private delay(waitTime: number) {
return new Promise((resolve) => setTimeout(resolve, waitTime))
}
}
/**
* Data processing class, can be configured according to the project
*/
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
import type { RequestOptions, Result } from '/#/axios'
export interface CreateAxiosOptions extends AxiosRequestConfig {
authenticationScheme?: string
transform?: AxiosTransform
requestOptions?: RequestOptions
}
export abstract class AxiosTransform {
/**
* @description: Process configuration before request
* @description: Process configuration before request
*/
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig
/**
* @description: Request successfully processed
*/
transformRequestHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any
/**
* @description: 请求失败处理
*/
requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>
/**
* @description: 请求之前的拦截器
*/
requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => AxiosRequestConfig
/**
* @description: 请求之后的拦截器
*/
responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>
/**
* @description: 请求之前的拦截器错误处理
*/
requestInterceptorsCatch?: (error: Error) => void
/**
* @description: 请求之后的拦截器错误处理
*/
responseInterceptorsCatch?: (axiosInstance: AxiosResponse, error: Error) => void
}
import type { ErrorMessageMode } from '/#/axios'
import { useMessage } from '/@/hooks/app/useMessage'
import * as HTTP from '/@/api/types'
const { createMessage, createErrorModal } = useMessage()
export function checkStatus(status: number, _msg: string, errorMessageMode: ErrorMessageMode = 'message'): void {
const errMessage = HTTP.toMessage(status)
if (errMessage) {
if (errorMessageMode === 'modal') {
createErrorModal({ title: '错误提示', content: errMessage })
} else if (errorMessageMode === 'message') {
createMessage.error(errMessage)
}
}
}
import { isObject, isString } from '/@/utils/is'
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
export function joinTimestamp<T extends boolean>(join: boolean, restful: T): T extends true ? string : object
export function joinTimestamp(join: boolean, restful = false): string | object {
if (!join) {
return restful ? '' : {}
}
const now = new Date().getTime()
if (restful) {
return `?_t=${now}`
}
return { _t: now }
}
/**
* @description: Format request parameter time
*/
export function formatRequestDate(params: Recordable) {
if (Object.prototype.toString.call(params) !== '[object Object]') {
return
}
for (const key in params) {
const format = params[key]?.format ?? null
if (format && typeof format === 'function') {
params[key] = params[key].format(DATE_TIME_FORMAT)
}
if (isString(key)) {
const value = params[key]
if (value) {
try {
params[key] = isString(value) ? value.trim() : value
} catch (error: any) {
throw new Error(error)
}
}
}
if (isObject(params[key])) {
formatRequestDate(params[key])
}
}
}
import type { App, Plugin } from 'vue'
import { unref } from 'vue'
import { isObject } from '/@/utils/is'
export const noop = () => {}
/**
* @description: Set ui mount node
*/
export function getPopupContainer(node?: HTMLElement): HTMLElement {
return (node?.parentNode as HTMLElement) ?? document.body
}
/**
* Add the object as a parameter to the URL
* @param baseUrl url
* @param obj
* @returns {string}
* eg:
* let obj = {a: '3', b: '4'}
* setObjToUrlParams('www.baidu.com', obj)
* ==>www.baidu.com?a=3&b=4
*/
export function setObjToUrlParams(baseUrl: string, obj: any): string {
let parameters = ''
for (const key in obj) {
parameters += key + '=' + encodeURIComponent(obj[key]) + '&'
}
parameters = parameters.replace(/&$/, '')
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters
}
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
let key: string
for (key in target) {
src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key])
}
return src
}
// dynamic use hook props
export function getDynamicProps<T, U>(props: T): Partial<U> {
const ret: Recordable = {}
Object.keys(props).map((key) => {
ret[key] = unref((props as Recordable)[key])
})
return ret as Partial<U>
}
export const withInstall = <T>(component: T, alias?: string) => {
const comp = component as any
comp.install = (app: App) => {
app.component(comp.name || comp.displayName, component)
if (alias) {
app.config.globalProperties[alias] = component
}
}
return component as T & Plugin
}
const toString = Object.prototype.toString
export function is(val: unknown, type: string) {
return toString.call(val) === `[object ${type}]`
}
export function isDef<T = unknown>(val?: T): val is T {
return typeof val !== 'undefined'
}
export function isUnDef<T = unknown>(val?: T): val is T {
return !isDef(val)
}
export function isObject(val: any): val is Record<any, any> {
return val !== null && is(val, 'Object')
}
export function isEmpty<T = unknown>(val: T): val is T {
if (isArray(val) || isString(val)) {
return val.length === 0
}
if (val instanceof Map || val instanceof Set) {
return val.size === 0
}
if (isObject(val)) {
return Object.keys(val).length === 0
}
return false
}
export function isDate(val: unknown): val is Date {
return is(val, 'Date')
}
export function isNull(val: unknown): val is null {
return val === null
}
export function isNullAndUnDef(val: unknown): val is null | undefined {
return isUnDef(val) && isNull(val)
}
export function isNullOrUnDef(val: unknown): val is null | undefined {
return isUnDef(val) || isNull(val)
}
export function isNumber(val: unknown): val is number {
return is(val, 'Number')
}
export function isPromise<T = any>(val: unknown): val is Promise<T> {
return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch)
}
export function isString(val: unknown): val is string {
return is(val, 'String')
}
export function isFunction(val: unknown): val is Function {
return typeof val === 'function'
}
export function isBoolean(val: unknown): val is boolean {
return is(val, 'Boolean')
}
export function isRegExp(val: unknown): val is RegExp {
return is(val, 'RegExp')
}
export function isArray(val: any): val is Array<any> {
return val && Array.isArray(val)
}
export function isWindow(val: any): val is Window {
return typeof window !== 'undefined' && is(val, 'Window')
}
export function isElement(val: unknown): val is Element {
return isObject(val) && !!val.tagName
}
export function isMap(val: unknown): val is Map<any, any> {
return is(val, 'Map')
}
export const isServer = typeof window === 'undefined'
export const isClient = !isServer
export function isUrl(path: string): boolean {
const reg =
/(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/
return reg.test(path)
}
const projectName = import.meta.env.VITE_GLOB_APP_NAME
export function warn(message: string) {
console.warn(`[${projectName} warn]:${message}`)
}
export function error(message: string) {
throw new Error(`[${projectName} error]:${message}`)
}
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"noLib": false,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"strictFunctionTypes": false,
"jsx": "preserve",
"baseUrl": ".",
"allowJs": true,
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["@dcloudio/types"],
"baseUrl": ".",
"resolveJsonModule": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"experimentalDecorators": true,
"lib": ["dom", "esnext"],
"noImplicitAny": false,
"skipLibCheck": true,
"strictNullChecks": false,
"strictPropertyInitialization": false,
"types": ["vite/client", "@dcloudio/types"],
"removeComments": true,
"paths": {
"/@/*": ["src/*"],
"/#/*": ["types/*"]
......@@ -23,7 +35,11 @@
"src/**/*.tsx",
"src/**/*.vue",
"types/**/*.d.ts",
"build/**/*.ts"
"types/**/*.ts",
"build/**/*.ts",
"build/**/*.d.ts",
"mock/**/*.ts",
"vite.config.ts"
],
"exclude": ["node_modules", "unpackage"]
"exclude": ["node_modules", "unpackage", "dist", "**/*.js"]
}
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
const $app: typeof import('/@/config/app')['$app']
const API: typeof import('/@/api/types')['API']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onError: typeof import('@dcloudio/uni-app')['onError']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onHide: typeof import('@dcloudio/uni-app')['onHide']
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
const onMounted: typeof import('vue')['onMounted']
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
const onReady: typeof import('@dcloudio/uni-app')['onReady']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onResize: typeof import('@dcloudio/uni-app')['onResize']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
const onShow: typeof import('@dcloudio/uni-app')['onShow']
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const $app: typeof import('/@/config/app')['$app']
const API: typeof import('/@/api/services/mods')['API']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defs: typeof import('/@/api/services')['defs']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onError: typeof import('@dcloudio/uni-app')['onError']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onHide: typeof import('@dcloudio/uni-app')['onHide']
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
const onMounted: typeof import('vue')['onMounted']
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
const onReady: typeof import('@dcloudio/uni-app')['onReady']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onResize: typeof import('@dcloudio/uni-app')['onResize']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
const onShow: typeof import('@dcloudio/uni-app')['onShow']
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
}
export {}
export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined
export type RequestOptions = http.RequestOptions
export interface RetryRequest {
isOpenRetry: boolean
count: number
waitTime: number
}
export type Result<T = any> = defs.Result<T>
// multipart/form-data: upload file
export interface UploadFileParams {
// Other parameters
data?: Recordable
// File parameter interface field name
name?: string
// file name
file: File | Blob
// file name
filename?: string
[key: string]: any
}
export interface GlobConfig {
// APP 名称
name: string
// APP 描述
description: string
// API 接口地址
apiUrl: string
// API 接口地址前缀
urlPrefix?: string
// 文件上传地址
uploadUrl?: string
}
declare type Recordable<T = any> = Record<string, T>
import type { AxiosRequestConfig } from 'axios'
interface ImportMetaEnv extends ViteEnv {
__: unknown
}
declare global {
type Recordable<T = any> = Record<string, T>
interface ImportMetaEnv extends ViteEnv {
__: unknown
}
interface ViteEnv {
// APP 名称
VITE_GLOB_APP_NAME: string
// APP 描述
VITE_GLOB_APP_DESCRIPTION?: string
// API 接口地址
VITE_GLOB_API_URL: string
// API 接口地址前缀
VITE_GLOB_API_URL_PREFIX?: string
// 公共文件上传 API URL
VITE_GLOB_UPLOAD_URL?: string
}
declare interface ViteEnv {
// APP 名称
VITE_GLOB_APP_NAME: string
// APP 描述
VITE_GLOB_APP_DESCRIPTION?: string
// API 接口地址
VITE_GLOB_API_URL: string
// API 接口地址前缀
VITE_GLOB_API_URL_PREFIX?: string
// 公共文件上传 API URL
VITE_GLOB_UPLOAD_URL?: string
// 扩展类型,用于在 pont 生成的 api.d.ts 内部使用
namespace http {
declare interface RequestOptions {
// Splicing request parameters to url
joinParamsToUrl?: boolean
// Format request parameter time
formatDate?: boolean
// Whether to process the request result
isTransformResponse?: boolean
// Whether to return native response headers
// For example: use this attribute when you need to get the response headers
isReturnNativeResponse?: boolean
// Whether to join url
joinPrefix?: boolean
// Interface address, use the default apiUrl if you leave it blank
apiUrl?: string
// 请求拼接路径
urlPrefix?: string
// Error message prompt type
errorMessageMode?: ErrorMessageMode
// Whether to add a timestamp
joinTime?: boolean
ignoreCancelToken?: boolean
// Whether to send token in header
withToken?: boolean
// 请求重试机制
retryRequest?: RetryRequest
}
type RequestConfig<T = any> = AxiosRequestConfig<T>
}
}
export {}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论