first commit
106
.commitlintrc.cjs
Normal file
@ -0,0 +1,106 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
const scopes = fs
|
||||
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name.replace(/s$/, ''))
|
||||
|
||||
// precomputed scope
|
||||
const scopeComplete = execSync('git status --porcelain || true')
|
||||
.toString()
|
||||
.trim()
|
||||
.split('\n')
|
||||
.find((r) => ~r.indexOf('M src'))
|
||||
?.replace(/(\/)/g, '%%')
|
||||
?.match(/src%%((\w|-)*)/)?.[1]
|
||||
?.replace(/s$/, '')
|
||||
|
||||
module.exports = {
|
||||
ignores: [(commit) => commit.includes('init')],
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'body-leading-blank': [2, 'always'],
|
||||
'footer-leading-blank': [1, 'always'],
|
||||
'header-max-length': [2, 'always', 108],
|
||||
'subject-empty': [2, 'never'],
|
||||
'type-empty': [2, 'never'],
|
||||
'subject-case': [0],
|
||||
'type-enum': [
|
||||
2,
|
||||
'always',
|
||||
[
|
||||
'feat',
|
||||
'fix',
|
||||
'perf',
|
||||
'style',
|
||||
'docs',
|
||||
'test',
|
||||
'refactor',
|
||||
'build',
|
||||
'ci',
|
||||
'chore',
|
||||
'revert',
|
||||
'wip',
|
||||
'workflow',
|
||||
'types',
|
||||
'release',
|
||||
],
|
||||
],
|
||||
},
|
||||
prompt: {
|
||||
/** @use `pnpm commit :f` */
|
||||
alias: {
|
||||
f: 'docs: fix typos',
|
||||
r: 'docs: update README',
|
||||
s: 'style: update code format',
|
||||
b: 'build: bump dependencies',
|
||||
c: 'chore: update config',
|
||||
},
|
||||
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
|
||||
defaultScope: scopeComplete,
|
||||
scopes: [...scopes, 'mock'],
|
||||
allowEmptyIssuePrefixs: false,
|
||||
allowCustomIssuePrefixs: false,
|
||||
|
||||
// English
|
||||
typesAppend: [
|
||||
{ value: 'wip', name: 'wip: work in process' },
|
||||
{ value: 'workflow', name: 'workflow: workflow improvements' },
|
||||
{ value: 'types', name: 'types: type definition file changes' },
|
||||
],
|
||||
|
||||
// 中英文对照版
|
||||
// messages: {
|
||||
// type: '选择你要提交的类型 :',
|
||||
// scope: '选择一个提交范围 (可选):',
|
||||
// customScope: '请输入自定义的提交范围 :',
|
||||
// subject: '填写简短精炼的变更描述 :\n',
|
||||
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
|
||||
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
|
||||
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
|
||||
// customFooterPrefixs: '输入自定义issue前缀 :',
|
||||
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
||||
// confirmCommit: '是否提交或修改commit ?',
|
||||
// },
|
||||
// types: [
|
||||
// { value: 'feat', name: 'feat: 新增功能' },
|
||||
// { value: 'fix', name: 'fix: 修复缺陷' },
|
||||
// { value: 'docs', name: 'docs: 文档变更' },
|
||||
// { value: 'style', name: 'style: 代码格式' },
|
||||
// { value: 'refactor', name: 'refactor: 代码重构' },
|
||||
// { value: 'perf', name: 'perf: 性能优化' },
|
||||
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
|
||||
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
|
||||
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
|
||||
// { value: 'revert', name: 'revert: 回滚 commit' },
|
||||
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
|
||||
// { value: 'wip', name: 'wip: 正在开发中' },
|
||||
// { value: 'workflow', name: 'workflow: 工作流程改进' },
|
||||
// { value: 'types', name: 'types: 类型定义文件修改' },
|
||||
// ],
|
||||
// emptyScopesAlias: 'empty: 不填写',
|
||||
// customScopesAlias: 'custom: 自定义',
|
||||
},
|
||||
}
|
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*] # 表示所有文件适用
|
||||
charset = utf-8 # 设置文件字符集为 utf-8
|
||||
indent_style = space # 缩进风格(tab | space)
|
||||
indent_size = 2 # 缩进大小
|
||||
end_of_line = lf # 控制换行类型(lf | cr | crlf)
|
||||
trim_trailing_whitespace = true # 去除行首的任意空白字符
|
||||
insert_final_newline = true # 始终在文件末尾插入一个新行
|
||||
|
||||
[*.md] # 表示仅 md 文件适用以下规则
|
||||
max_line_length = off # 关闭最大行长度限制
|
||||
trim_trailing_whitespace = false # 关闭末尾空格修剪
|
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
src/uni_modules/
|
101
.eslintrc-auto-import.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"globals": {
|
||||
"Component": true,
|
||||
"ComponentPublicInstance": true,
|
||||
"ComputedRef": true,
|
||||
"EffectScope": true,
|
||||
"ExtractDefaultPropTypes": true,
|
||||
"ExtractPropTypes": true,
|
||||
"ExtractPublicPropTypes": true,
|
||||
"InjectionKey": true,
|
||||
"PropType": true,
|
||||
"Ref": true,
|
||||
"VNode": true,
|
||||
"WritableComputedRef": true,
|
||||
"computed": true,
|
||||
"createApp": true,
|
||||
"customRef": true,
|
||||
"defineAsyncComponent": true,
|
||||
"defineComponent": true,
|
||||
"effectScope": true,
|
||||
"getCurrentInstance": true,
|
||||
"getCurrentScope": true,
|
||||
"h": true,
|
||||
"inject": true,
|
||||
"isProxy": true,
|
||||
"isReactive": true,
|
||||
"isReadonly": true,
|
||||
"isRef": true,
|
||||
"markRaw": true,
|
||||
"nextTick": true,
|
||||
"onActivated": true,
|
||||
"onAddToFavorites": true,
|
||||
"onBackPress": true,
|
||||
"onBeforeMount": true,
|
||||
"onBeforeUnmount": true,
|
||||
"onBeforeUpdate": true,
|
||||
"onDeactivated": true,
|
||||
"onError": true,
|
||||
"onErrorCaptured": true,
|
||||
"onHide": true,
|
||||
"onLaunch": true,
|
||||
"onLoad": true,
|
||||
"onMounted": true,
|
||||
"onNavigationBarButtonTap": true,
|
||||
"onNavigationBarSearchInputChanged": true,
|
||||
"onNavigationBarSearchInputClicked": true,
|
||||
"onNavigationBarSearchInputConfirmed": true,
|
||||
"onNavigationBarSearchInputFocusChanged": true,
|
||||
"onPageNotFound": true,
|
||||
"onPageScroll": true,
|
||||
"onPullDownRefresh": true,
|
||||
"onReachBottom": true,
|
||||
"onReady": true,
|
||||
"onRenderTracked": true,
|
||||
"onRenderTriggered": true,
|
||||
"onResize": true,
|
||||
"onScopeDispose": true,
|
||||
"onServerPrefetch": true,
|
||||
"onShareAppMessage": true,
|
||||
"onShareTimeline": true,
|
||||
"onShow": true,
|
||||
"onTabItemTap": true,
|
||||
"onThemeChange": true,
|
||||
"onUnhandledRejection": true,
|
||||
"onUnload": true,
|
||||
"onUnmounted": true,
|
||||
"onUpdated": true,
|
||||
"provide": true,
|
||||
"reactive": true,
|
||||
"readonly": true,
|
||||
"ref": true,
|
||||
"resolveComponent": true,
|
||||
"shallowReactive": true,
|
||||
"shallowReadonly": true,
|
||||
"shallowRef": true,
|
||||
"toRaw": true,
|
||||
"toRef": true,
|
||||
"toRefs": true,
|
||||
"toValue": true,
|
||||
"triggerRef": true,
|
||||
"unref": true,
|
||||
"useAttrs": true,
|
||||
"useCssModule": true,
|
||||
"useCssVars": true,
|
||||
"useRequest": true,
|
||||
"useSlots": true,
|
||||
"useUpload": true,
|
||||
"useUpload2": true,
|
||||
"watch": true,
|
||||
"watchEffect": true,
|
||||
"watchPostEffect": true,
|
||||
"watchSyncEffect": true,
|
||||
"DirectiveBinding": true,
|
||||
"MaybeRef": true,
|
||||
"MaybeRefOrGetter": true,
|
||||
"onWatcherCleanup": true,
|
||||
"useId": true,
|
||||
"useModel": true,
|
||||
"useTemplateRef": true
|
||||
}
|
||||
}
|
97
.eslintrc.cjs
Normal file
@ -0,0 +1,97 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/vue3-essential',
|
||||
// eslint-plugin-import 插件, @see https://www.npmjs.com/package/eslint-plugin-import
|
||||
'plugin:import/recommended',
|
||||
// eslint-config-airbnb-base 插件 已经改用 eslint-config-standard 插件
|
||||
'standard',
|
||||
// 1. 接入 prettier 的规则
|
||||
'prettier',
|
||||
'plugin:prettier/recommended',
|
||||
'./.eslintrc-auto-import.json',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
files: ['.eslintrc.{js,cjs}'],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'vue',
|
||||
// 2. 加入 prettier 的 eslint 插件
|
||||
'prettier',
|
||||
// eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript
|
||||
'import',
|
||||
],
|
||||
rules: {
|
||||
// 3. 注意要加上这一句,开启 prettier 自动修复的功能
|
||||
'prettier/prettier': 'error',
|
||||
// turn on errors for missing imports
|
||||
'import/no-unresolved': 'off',
|
||||
// 对后缀的检测,否则 import 一个ts文件也会报错,需要手动添加'.ts', 增加了下面的配置后就不用了
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'ignorePackages',
|
||||
{ js: 'never', jsx: 'never', ts: 'never', tsx: 'never' },
|
||||
],
|
||||
// 只允许1个默认导出,关闭,否则不能随意export xxx
|
||||
'import/prefer-default-export': ['off'],
|
||||
'no-console': ['off'],
|
||||
// 'no-unused-vars': ['off'],
|
||||
// '@typescript-eslint/no-unused-vars': ['off'],
|
||||
// 解决vite.config.ts报错问题
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-shadow': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'no-undef': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
// 避免 `eslint` 对于 `typescript` 函数重载的误报
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
},
|
||||
// eslint-import-resolver-typescript 插件,@see https://www.npmjs.com/package/eslint-import-resolver-typescript
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {},
|
||||
},
|
||||
},
|
||||
globals: {
|
||||
$t: true,
|
||||
uni: true,
|
||||
UniApp: true,
|
||||
wx: true,
|
||||
WechatMiniprogram: true,
|
||||
getCurrentPages: true,
|
||||
UniHelper: true,
|
||||
Page: true,
|
||||
App: true,
|
||||
NodeJS: true,
|
||||
},
|
||||
}
|
41
.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
.hbuilderx
|
||||
|
||||
.stylelintcache
|
||||
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
|
||||
# lock 文件还是不要了,我主要的版本写死就好了
|
||||
# pnpm-lock.yaml
|
||||
# package-lock.json
|
||||
|
||||
# TIPS:如果某些文件已经加入了版本管理,现在重新加入 .gitignore 是不生效的,需要执行下面的操作
|
||||
# `git rm -r --cached .` 然后提交 commit 即可。
|
||||
|
||||
# git rm -r --cached file1 file2 ## 针对某些文件
|
||||
# git rm -r --cached dir1 dir2 ## 针对某些文件夹
|
||||
# git rm -r --cached . ## 针对所有文件
|
||||
|
||||
# 更新 uni-app 官方版本
|
||||
# npx @dcloudio/uvm@latest
|
5
.husky/commit-msg
Normal file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
# Run the commit-msg hook
|
||||
npx --no-install commitlint --edit
|
5
.husky/pre-commit
Normal file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
# Run the pre-commit hook
|
||||
npx --no-install -- lint-staged
|
6
.npmrc
Normal file
@ -0,0 +1,6 @@
|
||||
# registry = https://registry.npmjs.org
|
||||
registry = https://registry.npmmirror.com
|
||||
|
||||
strict-peer-dependencies=false
|
||||
auto-install-peers=true
|
||||
shamefully-hoist=true
|
12
.prettierignore
Normal file
@ -0,0 +1,12 @@
|
||||
# unplugin-auto-import 生成的类型文件,每次提交都改变,所以加入这里吧,与 .gitignore 配合使用
|
||||
auto-import.d.ts
|
||||
|
||||
# vite-plugin-uni-pages 生成的类型文件,每次切换分支都一堆不同的,所以直接 .gitignore
|
||||
uni-pages.d.ts
|
||||
|
||||
# 插件生成的文件
|
||||
src/pages.json
|
||||
src/manifest.json
|
||||
|
||||
# 忽略自动生成文件
|
||||
src/service/app/**
|
19
.prettierrc.cjs
Normal file
@ -0,0 +1,19 @@
|
||||
// @see https://prettier.io/docs/en/options
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
printWidth: 100,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: false,
|
||||
trailingComma: 'all',
|
||||
endOfLine: 'auto',
|
||||
htmlWhitespaceSensitivity: 'ignore',
|
||||
overrides: [
|
||||
{
|
||||
files: '*.json',
|
||||
options: {
|
||||
trailingComma: 'none',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
1
.stylelintignore
Normal file
@ -0,0 +1 @@
|
||||
src/uni_modules/
|
58
.stylelintrc.cjs
Normal file
@ -0,0 +1,58 @@
|
||||
// .stylelintrc.cjs
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
// stylelint-config-standard 替换成了更宽松的 stylelint-config-recommended
|
||||
'stylelint-config-recommended',
|
||||
// stylelint-config-standard-scss 替换成了更宽松的 stylelint-config-recommended-scss
|
||||
'stylelint-config-recommended-scss',
|
||||
'stylelint-config-recommended-vue/scss',
|
||||
'stylelint-config-html/vue',
|
||||
'stylelint-config-recess-order',
|
||||
],
|
||||
plugins: ['stylelint-prettier'],
|
||||
overrides: [
|
||||
// 扫描 .vue/html 文件中的<style>标签内的样式
|
||||
{
|
||||
files: ['**/*.{vue,html}'],
|
||||
customSyntax: 'postcss-html',
|
||||
},
|
||||
{
|
||||
files: ['**/*.{css,scss}'],
|
||||
customSyntax: 'postcss-scss',
|
||||
},
|
||||
],
|
||||
// 自定义规则
|
||||
rules: {
|
||||
'prettier/prettier': true,
|
||||
// 允许 global 、export 、v-deep等伪类
|
||||
'selector-pseudo-class-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignorePseudoClasses: ['global', 'export', 'v-deep', 'deep'],
|
||||
},
|
||||
],
|
||||
'unit-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreUnits: ['rpx'],
|
||||
},
|
||||
],
|
||||
// 处理小程序page标签不认识的问题
|
||||
'selector-type-no-unknown': [
|
||||
true,
|
||||
{
|
||||
ignoreTypes: ['page'],
|
||||
},
|
||||
],
|
||||
'comment-empty-line-before': 'never', // never|always|always-multi-line|never-multi-line
|
||||
'custom-property-empty-line-before': 'never',
|
||||
'no-empty-source': null,
|
||||
'comment-no-empty': null,
|
||||
'no-duplicate-selectors': null,
|
||||
'scss/comment-no-empty': null,
|
||||
'selector-class-pattern': null,
|
||||
'font-family-no-missing-generic-family-keyword': null,
|
||||
},
|
||||
}
|
17
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"vue.volar",
|
||||
"stylelint.vscode-stylelint",
|
||||
"esbenp.prettier-vscode",
|
||||
"antfu.unocss",
|
||||
"antfu.iconify",
|
||||
"evils.uniapp-vscode",
|
||||
"uni-helper.uni-helper-vscode",
|
||||
"uni-helper.uni-app-schemas-vscode",
|
||||
"uni-helper.uni-highlight-vscode",
|
||||
"uni-helper.uni-ui-snippets-vscode",
|
||||
"uni-helper.uni-app-snippets-vscode",
|
||||
"mrmlnc.vscode-json5",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
]
|
||||
}
|
60
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
{
|
||||
// 默认格式化工具选择prettier
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
// 保存的时候自动格式化
|
||||
"editor.formatOnSave": true,
|
||||
//开启自动修复
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit",
|
||||
"source.fixAll.stylelint": "explicit"
|
||||
},
|
||||
// 配置stylelint检查的文件类型范围
|
||||
"stylelint.validate": ["css", "scss", "vue", "html"], // 与package.json的scripts对应
|
||||
"stylelint.enable": true,
|
||||
"css.validate": false,
|
||||
"less.validate": false,
|
||||
"scss.validate": false,
|
||||
"[shellscript]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[dotenv]": {
|
||||
"editor.defaultFormatter": "foxundermoon.shell-format"
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
// 配置语言的文件关联
|
||||
"files.associations": {
|
||||
"pages.json": "jsonc", // pages.json 可以写注释
|
||||
"manifest.json": "jsonc" // manifest.json 可以写注释
|
||||
},
|
||||
"cSpell.words": [
|
||||
"Aplipay",
|
||||
"climblee",
|
||||
"commitlint",
|
||||
"dcloudio",
|
||||
"iconfont",
|
||||
"qrcode",
|
||||
"refresherrefresh",
|
||||
"scrolltolower",
|
||||
"tabbar",
|
||||
"Toutiao",
|
||||
"unibest",
|
||||
"uvui",
|
||||
"Wechat",
|
||||
"WechatMiniprogram",
|
||||
"Weixin"
|
||||
],
|
||||
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||
"explorer.fileNesting.enabled": true,
|
||||
"explorer.fileNesting.expand": false,
|
||||
"explorer.fileNesting.patterns": {
|
||||
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc"
|
||||
}
|
||||
}
|
56
.vscode/vue3.code-snippets
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
// Place your unibest 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
|
||||
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
|
||||
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
|
||||
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
|
||||
// Placeholders with the same ids are connected.
|
||||
// Example:
|
||||
// "Print to console": {
|
||||
// "scope": "javascript,typescript",
|
||||
// "prefix": "log",
|
||||
// "body": [
|
||||
// "console.log('$1');",
|
||||
// "$2"
|
||||
// ],
|
||||
// "description": "Log output to console"
|
||||
// }
|
||||
"Print unibest Vue3 SFC": {
|
||||
"scope": "vue",
|
||||
"prefix": "v3",
|
||||
"body": [
|
||||
"<route lang=\"json5\" type=\"page\">",
|
||||
"{",
|
||||
" layout: 'default',",
|
||||
" style: {",
|
||||
" navigationBarTitleText: '$1',",
|
||||
" },",
|
||||
"}",
|
||||
"</route>\n",
|
||||
"<template>",
|
||||
" <view class=\"\">$2</view>",
|
||||
"</template>\n",
|
||||
"<script lang=\"ts\" setup>",
|
||||
"//$3",
|
||||
"</script>\n",
|
||||
"<style lang=\"scss\" scoped>",
|
||||
"//$4",
|
||||
"</style>\n",
|
||||
],
|
||||
},
|
||||
"Print unibest style": {
|
||||
"scope": "vue",
|
||||
"prefix": "st",
|
||||
"body": ["<style lang=\"scss\" scoped>", "//", "</style>\n"],
|
||||
},
|
||||
"Print unibest script": {
|
||||
"scope": "vue",
|
||||
"prefix": "sc",
|
||||
"body": ["<script lang=\"ts\" setup>", "//$3", "</script>\n"],
|
||||
},
|
||||
"Print unibest template": {
|
||||
"scope": "vue",
|
||||
"prefix": "te",
|
||||
"body": ["<template>", " <view class=\"\">$1</view>", "</template>\n"],
|
||||
},
|
||||
}
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 菲鸽
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
94
README.md
Normal file
@ -0,0 +1,94 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/feige996/unibest">
|
||||
<img width="160" src="./src/static/logo.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://github.com/feige996/unibest" target="_blank">unibest - 最好的 uniapp 开发框架</a>
|
||||
</h1>
|
||||
|
||||
<div align="center">
|
||||
旧仓库 codercup 进不去了,star 也拿不回来,这里也展示一下那个地址的 star.
|
||||
|
||||
[](https://github.com/codercup/unibest)
|
||||
[](https://github.com/codercup/unibest)
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/feige996/unibest)
|
||||
[](https://github.com/feige996/unibest)
|
||||
[](https://gitee.com/feige996/unibest/stargazers)
|
||||
[](https://gitee.com/feige996/unibest/members)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
`unibest` —— 最好的 `uniapp` 开发模板,由 `uniapp` + `Vue3` + `Ts` + `Vite5` + `UnoCss` + `wot-ui` + `z-paging` 构成,使用了最新的前端技术栈,无需依靠 `HBuilderX`,通过命令行方式运行 `web`、`小程序` 和 `App`(编辑器推荐 `VSCode`,可选 `webstorm`)。
|
||||
|
||||
`unibest` 内置了 `约定式路由`、`layout布局`、`请求封装`、`请求拦截`、`登录拦截`、`UnoCSS`、`i18n多语言` 等基础功能,提供了 `代码提示`、`自动格式化`、`统一配置`、`代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 ( `unibest 的由来`)。
|
||||
|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://unibest.tech/" target="_blank">📖 文档地址(new)</a>
|
||||
<span style="margin:0 10px;">|</span>
|
||||
<a href="https://feige996.github.io/hello-unibest/" target="_blank">📱 DEMO 地址</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
注意旧的地址 [codercup](https://github.com/codercup/unibest) 我进不去了,使用新的 [feige996](https://github.com/feige996/unibest)。PR和 issue 也请使用新地址,否则无法合并。
|
||||
|
||||
## 平台兼容性
|
||||
|
||||
| H5 | IOS | 安卓 | 微信小程序 | 字节小程序 | 快手小程序 | 支付宝小程序 | 钉钉小程序 | 百度小程序 |
|
||||
| --- | --- | ---- | ---------- | ---------- | ---------- | ------------ | ---------- | ---------- |
|
||||
| √ | √ | √ | √ | √ | √ | √ | √ | √ |
|
||||
|
||||
注意每种 `UI框架` 支持的平台有所不同,详情请看各 `UI框架` 的官网,也可以看 `unibest` 文档。
|
||||
|
||||
## ⚙️ 环境
|
||||
|
||||
- node>=18
|
||||
- pnpm>=7.30
|
||||
- Vue Official>=2.1.10
|
||||
- TypeScript>=5.0
|
||||
|
||||
## 📂 快速开始
|
||||
|
||||
执行 `pnpm create unibest` 创建项目
|
||||
|
||||
执行 `pnpm i` 安装依赖
|
||||
|
||||
执行 `pnpm dev` 运行 `H5`
|
||||
|
||||
## 📦 运行(支持热更新)
|
||||
|
||||
- web平台: `pnpm dev:h5`, 然后打开 [http://localhost:9000/](http://localhost:9000/)。
|
||||
- weixin平台:`pnpm dev:mp-weixin` 然后打开微信开发者工具,导入本地文件夹,选择本项目的`dist/dev/mp-weixin` 文件。
|
||||
- APP平台:`pnpm dev:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/dev/app` 文件夹,选择运行到模拟器(开发时优先使用),或者运行的安卓/ios基座。
|
||||
|
||||
## 🔗 发布
|
||||
|
||||
- web平台: `pnpm build:h5`,打包后的文件在 `dist/build/h5`,可以放到web服务器,如nginx运行。如果最终不是放在根目录,可以在 `manifest.config.ts` 文件的 `h5.router.base` 属性进行修改。
|
||||
- weixin平台:`pnpm build:mp-weixin`, 打包后的文件在 `dist/build/mp-weixin`,然后通过微信开发者工具导入,并点击右上角的“上传”按钮进行上传。
|
||||
- APP平台:`pnpm build:app`, 然后打开 `HBuilderX`,导入刚刚生成的`dist/build/app` 文件夹,选择发行 - APP云打包。
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT](https://opensource.org/license/mit/)
|
||||
|
||||
Copyright (c) 2025 菲鸽
|
||||
|
||||
## 捐赠
|
||||
|
||||
<p align='center'>
|
||||
<img alt="special sponsor appwrite" src="./screenshots/pay-1.png" height="330" style="display:inline-block; height:330px;">
|
||||
<img alt="special sponsor appwrite" src="./screenshots/pay-2.png" height="330" style="display:inline-block; height:330px; margin-left:10px;">
|
||||
</p>
|
25
env/.env
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
VITE_APP_TITLE = 'unibest'
|
||||
VITE_APP_PORT = 9000
|
||||
|
||||
VITE_UNI_APPID = 'H57F2ACE4'
|
||||
VITE_WX_APPID = 'wxa2abb91f64032a2b'
|
||||
|
||||
# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
|
||||
VITE_APP_PUBLIC_BASE=/
|
||||
|
||||
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
|
||||
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
|
||||
|
||||
# 有些同学可能需要在微信小程序里面根据 develop、trial、release 分别设置上传地址,参考代码如下。
|
||||
# 下面的变量如果没有设置,会默认使用 VITE_SERVER_BASEURL or VITE_UPLOAD_BASEURL
|
||||
VITE_SERVER_BASEURL__WEIXIN_DEVELOP = 'https://ukw0y1.laf.run'
|
||||
VITE_SERVER_BASEURL__WEIXIN_TRIAL = 'https://ukw0y1.laf.run'
|
||||
VITE_SERVER_BASEURL__WEIXIN_RELEASE = 'https://ukw0y1.laf.run'
|
||||
|
||||
VITE_UPLOAD_BASEURL__WEIXIN_DEVELOP = 'https://ukw0y1.laf.run/upload'
|
||||
VITE_UPLOAD_BASEURL__WEIXIN_TRIAL = 'https://ukw0y1.laf.run/upload'
|
||||
VITE_UPLOAD_BASEURL__WEIXIN_RELEASE = 'https://ukw0y1.laf.run/upload'
|
||||
|
||||
# h5是否需要配置代理
|
||||
VITE_APP_PROXY=false
|
||||
VITE_APP_PROXY_PREFIX = '/api'
|
6
env/.env.development
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'development'
|
||||
# 是否去除console 和 debugger
|
||||
VITE_DELETE_CONSOLE = false
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = true
|
6
env/.env.production
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'development'
|
||||
# 是否去除console 和 debugger
|
||||
VITE_DELETE_CONSOLE = true
|
||||
# 是否开启sourcemap
|
||||
VITE_SHOW_SOURCEMAP = false
|
4
env/.env.test
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
|
||||
NODE_ENV = 'development'
|
||||
# 是否去除console 和 debugger
|
||||
VITE_DELETE_CONSOLE = false
|
BIN
favicon.ico
Normal file
After Width: | Height: | Size: 14 KiB |
26
index.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<html build-time="%BUILD_TIME%">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
|
||||
<script>
|
||||
var coverSupport =
|
||||
'CSS' in window &&
|
||||
typeof CSS.supports === 'function' &&
|
||||
(CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') +
|
||||
'" />',
|
||||
)
|
||||
</script>
|
||||
<title>unibest</title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
134
manifest.config.ts
Normal file
@ -0,0 +1,134 @@
|
||||
// manifest.config.ts
|
||||
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
|
||||
import path from 'node:path'
|
||||
import { loadEnv } from 'vite'
|
||||
|
||||
// 获取环境变量的范例
|
||||
const env = loadEnv(process.env.NODE_ENV!, path.resolve(process.cwd(), 'env'))
|
||||
const {
|
||||
VITE_APP_TITLE,
|
||||
VITE_UNI_APPID,
|
||||
VITE_WX_APPID,
|
||||
VITE_APP_PUBLIC_BASE,
|
||||
VITE_FALLBACK_LOCALE,
|
||||
} = env
|
||||
|
||||
export default defineManifestConfig({
|
||||
name: VITE_APP_TITLE,
|
||||
appid: VITE_UNI_APPID,
|
||||
description: '',
|
||||
versionName: '1.0.0',
|
||||
versionCode: '100',
|
||||
transformPx: false,
|
||||
locale: VITE_FALLBACK_LOCALE, // 'zh-Hans'
|
||||
h5: {
|
||||
router: {
|
||||
base: VITE_APP_PUBLIC_BASE,
|
||||
},
|
||||
},
|
||||
/* 5+App特有相关 */
|
||||
'app-plus': {
|
||||
usingComponents: true,
|
||||
nvueStyleCompiler: 'uni-app',
|
||||
compilerVersion: 3,
|
||||
compatible: {
|
||||
ignoreVersion: true,
|
||||
},
|
||||
splashscreen: {
|
||||
alwaysShowBeforeRender: true,
|
||||
waiting: true,
|
||||
autoclose: true,
|
||||
delay: 0,
|
||||
},
|
||||
/* 模块配置 */
|
||||
modules: {},
|
||||
/* 应用发布信息 */
|
||||
distribute: {
|
||||
/* android打包配置 */
|
||||
android: {
|
||||
minSdkVersion: 30,
|
||||
targetSdkVersion: 30,
|
||||
abiFilters: ['armeabi-v7a', 'arm64-v8a'],
|
||||
permissions: [
|
||||
'<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>',
|
||||
'<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>',
|
||||
'<uses-permission android:name="android.permission.VIBRATE"/>',
|
||||
'<uses-permission android:name="android.permission.READ_LOGS"/>',
|
||||
'<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>',
|
||||
'<uses-feature android:name="android.hardware.camera.autofocus"/>',
|
||||
'<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>',
|
||||
'<uses-permission android:name="android.permission.CAMERA"/>',
|
||||
'<uses-permission android:name="android.permission.GET_ACCOUNTS"/>',
|
||||
'<uses-permission android:name="android.permission.READ_PHONE_STATE"/>',
|
||||
'<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>',
|
||||
'<uses-permission android:name="android.permission.WAKE_LOCK"/>',
|
||||
'<uses-permission android:name="android.permission.FLASHLIGHT"/>',
|
||||
'<uses-feature android:name="android.hardware.camera"/>',
|
||||
'<uses-permission android:name="android.permission.WRITE_SETTINGS"/>',
|
||||
],
|
||||
},
|
||||
/* ios打包配置 */
|
||||
ios: {},
|
||||
/* SDK配置 */
|
||||
sdkConfigs: {},
|
||||
/* 图标配置 */
|
||||
icons: {
|
||||
android: {
|
||||
hdpi: 'static/app/icons/72x72.png',
|
||||
xhdpi: 'static/app/icons/96x96.png',
|
||||
xxhdpi: 'static/app/icons/144x144.png',
|
||||
xxxhdpi: 'static/app/icons/192x192.png',
|
||||
},
|
||||
ios: {
|
||||
appstore: 'static/app/icons/1024x1024.png',
|
||||
ipad: {
|
||||
app: 'static/app/icons/76x76.png',
|
||||
'app@2x': 'static/app/icons/152x152.png',
|
||||
notification: 'static/app/icons/20x20.png',
|
||||
'notification@2x': 'static/app/icons/40x40.png',
|
||||
'proapp@2x': 'static/app/icons/167x167.png',
|
||||
settings: 'static/app/icons/29x29.png',
|
||||
'settings@2x': 'static/app/icons/58x58.png',
|
||||
spotlight: 'static/app/icons/40x40.png',
|
||||
'spotlight@2x': 'static/app/icons/80x80.png',
|
||||
},
|
||||
iphone: {
|
||||
'app@2x': 'static/app/icons/120x120.png',
|
||||
'app@3x': 'static/app/icons/180x180.png',
|
||||
'notification@2x': 'static/app/icons/40x40.png',
|
||||
'notification@3x': 'static/app/icons/60x60.png',
|
||||
'settings@2x': 'static/app/icons/58x58.png',
|
||||
'settings@3x': 'static/app/icons/87x87.png',
|
||||
'spotlight@2x': 'static/app/icons/80x80.png',
|
||||
'spotlight@3x': 'static/app/icons/120x120.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
quickapp: {},
|
||||
/* 小程序特有相关 */
|
||||
'mp-weixin': {
|
||||
appid: VITE_WX_APPID,
|
||||
setting: {
|
||||
urlCheck: false,
|
||||
},
|
||||
usingComponents: true,
|
||||
// __usePrivacyCheck__: true,
|
||||
},
|
||||
'mp-alipay': {
|
||||
usingComponents: true,
|
||||
styleIsolation: 'shared',
|
||||
},
|
||||
'mp-baidu': {
|
||||
usingComponents: true,
|
||||
},
|
||||
'mp-toutiao': {
|
||||
usingComponents: true,
|
||||
},
|
||||
uniStatistics: {
|
||||
enable: false,
|
||||
},
|
||||
vueVersion: '3',
|
||||
})
|
13
openapi-ts-request.config.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { GenerateServiceProps } from 'openapi-ts-request'
|
||||
|
||||
export default [
|
||||
{
|
||||
schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
|
||||
serversPath: './src/service/app',
|
||||
requestLibPath: `import request from '@/utils/request';\n import { CustomRequestOptions } from '@/interceptors/request';`,
|
||||
requestOptionsType: 'CustomRequestOptions',
|
||||
isGenReactQuery: true,
|
||||
reactQueryMode: 'vue',
|
||||
isGenJavaScript: false,
|
||||
},
|
||||
] as GenerateServiceProps[]
|
154
package.json
Normal file
@ -0,0 +1,154 @@
|
||||
{
|
||||
"name": "my-project",
|
||||
"type": "commonjs",
|
||||
"version": "2.6.3",
|
||||
"description": "unibest - 最好的 uniapp 开发模板",
|
||||
"author": {
|
||||
"name": "feige996",
|
||||
"zhName": "菲鸽",
|
||||
"email": "1020103647@qq.com",
|
||||
"github": "https://github.com/feige996",
|
||||
"gitee": "https://gitee.com/feige996"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/feige996/unibest",
|
||||
"repository-gitee": "https://gitee.com/feige996/unibest",
|
||||
"repository-deprecated": "https://github.com/codercup/unibest",
|
||||
"bugs": {
|
||||
"url": "https://github.com/feige996/unibest/issues"
|
||||
},
|
||||
"homepage": "https://feige996.github.io/unibest/",
|
||||
"engines": {
|
||||
"node": ">=18",
|
||||
"pnpm": ">=7.30"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"uvm": "npx @dcloudio/uvm@latest",
|
||||
"uvm-rm": "node ./scripts/postupgrade.js",
|
||||
"postuvm": "echo upgrade uni-app success!",
|
||||
"dev:app": "uni -p app",
|
||||
"dev:app-android": "uni -p app-android",
|
||||
"dev:app-ios": "uni -p app-ios",
|
||||
"dev:custom": "uni -p",
|
||||
"dev": "uni",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp": "uni -p mp-weixin",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-jd": "uni -p mp-jd",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:mp-xhs": "uni -p mp-xhs",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:app": "uni build -p app",
|
||||
"build:app-android": "uni build -p app-android",
|
||||
"build:app-ios": "uni build -p app-ios",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build",
|
||||
"build": "uni build",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp": "uni build -p mp-weixin",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-jd": "uni build -p mp-jd",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:mp-xhs": "uni build -p mp-xhs",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||
"prepare": "git init && husky install",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"cz": "czg",
|
||||
"openapi-ts-request": "openapi-ts"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.{html,vue,ts,cjs,json,md}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"**/*.{vue,css,scss,html}": [
|
||||
"stylelint --fix"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"bin-wrapper": "npm:bin-wrapper-china"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-app-harmony": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-components": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-h5": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-4020920240930001",
|
||||
"@tanstack/vue-query": "^5.62.16",
|
||||
"abortcontroller-polyfill": "^1.7.8",
|
||||
"dayjs": "1.11.10",
|
||||
"pinia": "2.0.36",
|
||||
"pinia-plugin-persistedstate": "3.2.1",
|
||||
"qs": "6.5.3",
|
||||
"vue": "3.4.21",
|
||||
"wot-design-uni": "^1.4.0",
|
||||
"z-paging": "^2.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.6.1",
|
||||
"@commitlint/config-conventional": "^18.6.3",
|
||||
"@dcloudio/types": "^3.4.14",
|
||||
"@dcloudio/uni-automator": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-4020920240930001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-4020920240930001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-4020920240930001",
|
||||
"@esbuild/darwin-arm64": "0.20.2",
|
||||
"@esbuild/darwin-x64": "0.20.2",
|
||||
"@iconify-json/carbon": "^1.2.4",
|
||||
"@rollup/rollup-darwin-x64": "^4.28.0",
|
||||
"@types/node": "^20.17.9",
|
||||
"@types/wechat-miniprogram": "^3.4.8",
|
||||
"@uni-helper/vite-plugin-uni-layouts": "^0.1.10",
|
||||
"@uni-helper/vite-plugin-uni-manifest": "^0.2.8",
|
||||
"@uni-helper/vite-plugin-uni-pages": "^0.2.28",
|
||||
"@uni-helper/vite-plugin-uni-platform": "^0.0.4",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^15.2.10",
|
||||
"openapi-ts-request": "^1.1.2",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-html": "^1.7.0",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"sass": "1.77.8",
|
||||
"stylelint": "^16.11.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recess-order": "^4.6.0",
|
||||
"stylelint-config-recommended": "^14.0.1",
|
||||
"stylelint-config-recommended-scss": "^14.1.0",
|
||||
"stylelint-config-recommended-vue": "^1.5.0",
|
||||
"stylelint-prettier": "^5.0.2",
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "^5.7.2",
|
||||
"unocss": "^0.58.9",
|
||||
"unocss-applet": "^0.7.8",
|
||||
"unplugin-auto-import": "^0.17.8",
|
||||
"vite": "5.2.8",
|
||||
"vite-plugin-restart": "^0.4.2",
|
||||
"vue-tsc": "^1.8.27"
|
||||
}
|
||||
}
|
43
pages.config.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
|
||||
|
||||
export default defineUniPages({
|
||||
globalStyle: {
|
||||
navigationStyle: 'default',
|
||||
navigationBarTitleText: 'unibest',
|
||||
navigationBarBackgroundColor: '#f8f8f8',
|
||||
navigationBarTextStyle: 'black',
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
easycom: {
|
||||
autoscan: true,
|
||||
custom: {
|
||||
'^wd-(.*)': 'wot-design-uni/components/wd-$1/wd-$1.vue',
|
||||
'^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)':
|
||||
'z-paging/components/z-paging$1/z-paging$1.vue',
|
||||
},
|
||||
},
|
||||
tabBar: {
|
||||
color: '#999999',
|
||||
selectedColor: '#018d71',
|
||||
backgroundColor: '#F8F8F8',
|
||||
borderStyle: 'black',
|
||||
height: '50px',
|
||||
fontSize: '10px',
|
||||
iconWidth: '24px',
|
||||
spacing: '3px',
|
||||
list: [
|
||||
{
|
||||
iconPath: 'static/tabbar/home.png',
|
||||
selectedIconPath: 'static/tabbar/homeHL.png',
|
||||
pagePath: 'pages/index/index',
|
||||
text: '首页',
|
||||
},
|
||||
{
|
||||
iconPath: 'static/tabbar/example.png',
|
||||
selectedIconPath: 'static/tabbar/exampleHL.png',
|
||||
pagePath: 'pages/about/about',
|
||||
text: '关于',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
11828
pnpm-lock.yaml
Normal file
BIN
screenshots/pay-1.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
screenshots/pay-2.png
Normal file
After Width: | Height: | Size: 134 KiB |
36
scripts/postupgrade.js
Normal file
@ -0,0 +1,36 @@
|
||||
// # 执行 `pnpm upgrade` 后会升级 `uniapp` 相关依赖
|
||||
// # 在升级完后,会自动添加很多无用依赖,这需要删除以减小依赖包体积
|
||||
// # 只需要执行下面的命令即可
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { exec } = require('child_process')
|
||||
|
||||
// 定义要执行的命令
|
||||
const dependencies = [
|
||||
'@dcloudio/uni-app-harmony',
|
||||
// TODO: 如果需要某个平台的小程序,请手动删除或注释掉
|
||||
'@dcloudio/uni-mp-alipay',
|
||||
'@dcloudio/uni-mp-baidu',
|
||||
'@dcloudio/uni-mp-jd',
|
||||
'@dcloudio/uni-mp-kuaishou',
|
||||
'@dcloudio/uni-mp-lark',
|
||||
'@dcloudio/uni-mp-qq',
|
||||
'@dcloudio/uni-mp-toutiao',
|
||||
'@dcloudio/uni-mp-xhs',
|
||||
'@dcloudio/uni-quickapp-webview',
|
||||
// i18n模板要注释掉下面的
|
||||
'vue-i18n',
|
||||
]
|
||||
|
||||
// 使用exec执行命令
|
||||
exec(`pnpm un ${dependencies.join(' ')}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
// 如果有错误,打印错误信息
|
||||
console.error(`执行出错: ${error}`)
|
||||
return
|
||||
}
|
||||
// 打印正常输出
|
||||
console.log(`stdout: ${stdout}`)
|
||||
// 如果有错误输出,也打印出来
|
||||
console.error(`stderr: ${stderr}`)
|
||||
})
|
59
src/App.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
|
||||
onLaunch(() => {
|
||||
console.log('App Launch')
|
||||
})
|
||||
onShow(() => {
|
||||
console.log('App Show')
|
||||
})
|
||||
onHide(() => {
|
||||
console.log('App Hide')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* stylelint-disable selector-type-no-unknown */
|
||||
button::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
swiper,
|
||||
scroll-view {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// 单行省略,优先使用 unocss: text-ellipsis
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 两行省略
|
||||
.ellipsis-2 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
// 三行省略
|
||||
.ellipsis-3 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
0
src/components/.gitkeep
Normal file
31
src/env.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-svg-loader" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
interface ImportMetaEnv {
|
||||
/** 网站标题,应用名称 */
|
||||
readonly VITE_APP_TITLE: string
|
||||
/** 服务端口号 */
|
||||
readonly VITE_SERVER_PORT: string
|
||||
/** 后台接口地址 */
|
||||
readonly VITE_SERVER_BASEURL: string
|
||||
/** H5是否需要代理 */
|
||||
readonly VITE_APP_PROXY: 'true' | 'false'
|
||||
/** H5是否需要代理,需要的话有个前缀 */
|
||||
readonly VITE_APP_PROXY_PREFIX: string // 一般是/api
|
||||
/** 上传图片地址 */
|
||||
readonly VITE_UPLOAD_BASEURL: string
|
||||
/** 是否清除console */
|
||||
readonly VITE_DELETE_CONSOLE: string
|
||||
// 更多环境变量...
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
0
src/hooks/.gitkeep
Normal file
44
src/hooks/useRequest.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { UnwrapRef } from 'vue'
|
||||
|
||||
type IUseRequestOptions<T> = {
|
||||
/** 是否立即执行 */
|
||||
immediate?: boolean
|
||||
/** 初始化数据 */
|
||||
initialData?: T
|
||||
}
|
||||
|
||||
/**
|
||||
* useRequest是一个定制化的请求钩子,用于处理异步请求和响应。
|
||||
* @param func 一个执行异步请求的函数,返回一个包含响应数据的Promise。
|
||||
* @param options 包含请求选项的对象 {immediate, initialData}。
|
||||
* @param options.immediate 是否立即执行请求,默认为false。
|
||||
* @param options.initialData 初始化数据,默认为undefined。
|
||||
* @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
|
||||
*/
|
||||
export default function useRequest<T>(
|
||||
func: () => Promise<IResData<T>>,
|
||||
options: IUseRequestOptions<T> = { immediate: false },
|
||||
) {
|
||||
const loading = ref(false)
|
||||
const error = ref(false)
|
||||
const data = ref<T>(options.initialData)
|
||||
const run = async () => {
|
||||
loading.value = true
|
||||
return func()
|
||||
.then((res) => {
|
||||
data.value = res.data as UnwrapRef<T>
|
||||
error.value = false
|
||||
return data.value
|
||||
})
|
||||
.catch((err) => {
|
||||
error.value = err
|
||||
throw err
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
options.immediate && run()
|
||||
return { loading, error, data, run }
|
||||
}
|
69
src/hooks/useUpload.ts
Normal file
@ -0,0 +1,69 @@
|
||||
// TODO: 别忘加更改环境变量的 VITE_UPLOAD_BASEURL 地址。
|
||||
import { getEnvBaseUploadUrl } from '@/utils'
|
||||
|
||||
const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}`
|
||||
|
||||
/**
|
||||
* useUpload 是一个定制化的请求钩子,用于处理上传图片。
|
||||
* @param formData 额外传递给后台的数据,如{name: '菲鸽'}。
|
||||
* @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
|
||||
*/
|
||||
export default function useUpload<T = string>(formData: Record<string, any> = {}) {
|
||||
const loading = ref(false)
|
||||
const error = ref(false)
|
||||
const data = ref<T>()
|
||||
const run = () => {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
|
||||
// 微信小程序在2023年10月17日之后,使用本API需要配置隐私协议
|
||||
uni.chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ['image'],
|
||||
success: (res) => {
|
||||
loading.value = true
|
||||
const tempFilePath = res.tempFiles[0].tempFilePath
|
||||
uploadFile<T>({ tempFilePath, formData, data, error, loading })
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('uni.chooseMedia err->', err)
|
||||
error.value = true
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
loading.value = true
|
||||
const tempFilePath = res.tempFilePaths[0]
|
||||
uploadFile<T>({ tempFilePath, formData, data, error, loading })
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('uni.chooseImage err->', err)
|
||||
error.value = true
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
|
||||
return { loading, error, data, run }
|
||||
}
|
||||
|
||||
function uploadFile<T>({ tempFilePath, formData, data, error, loading }) {
|
||||
uni.uploadFile({
|
||||
url: VITE_UPLOAD_BASEURL,
|
||||
filePath: tempFilePath,
|
||||
name: 'file',
|
||||
formData,
|
||||
success: (uploadFileRes) => {
|
||||
data.value = uploadFileRes.data as T
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('uni.uploadFile err->', err)
|
||||
error.value = true
|
||||
},
|
||||
complete: () => {
|
||||
loading.value = false
|
||||
},
|
||||
})
|
||||
}
|
3
src/interceptors/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { routeInterceptor } from './route'
|
||||
export { requestInterceptor } from './request'
|
||||
export { prototypeInterceptor } from './prototype'
|
13
src/interceptors/prototype.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const prototypeInterceptor = {
|
||||
install() {
|
||||
// 解决低版本手机不识别 array.at() 导致运行报错的问题
|
||||
if (typeof Array.prototype.at !== 'function') {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
Array.prototype.at = function (index: number) {
|
||||
if (index < 0) return this[this.length + index]
|
||||
if (index >= this.length) return undefined
|
||||
return this[index]
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
69
src/interceptors/request.ts
Normal file
@ -0,0 +1,69 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import qs from 'qs'
|
||||
import { useUserStore } from '@/store'
|
||||
import { platform } from '@/utils/platform'
|
||||
import { getEnvBaseUrl } from '@/utils'
|
||||
|
||||
export type CustomRequestOptions = UniApp.RequestOptions & {
|
||||
query?: Record<string, any>
|
||||
/** 出错时是否隐藏错误提示 */
|
||||
hideErrorToast?: boolean
|
||||
} & IUniUploadFileOptions // 添加uni.uploadFile参数类型
|
||||
|
||||
// 请求基准地址
|
||||
const baseUrl = getEnvBaseUrl()
|
||||
|
||||
// 拦截器配置
|
||||
const httpInterceptor = {
|
||||
// 拦截前触发
|
||||
invoke(options: CustomRequestOptions) {
|
||||
// 接口请求支持通过 query 参数配置 queryString
|
||||
if (options.query) {
|
||||
const queryStr = qs.stringify(options.query)
|
||||
if (options.url.includes('?')) {
|
||||
options.url += `&${queryStr}`
|
||||
} else {
|
||||
options.url += `?${queryStr}`
|
||||
}
|
||||
}
|
||||
// 非 http 开头需拼接地址
|
||||
if (!options.url.startsWith('http')) {
|
||||
// #ifdef H5
|
||||
// console.log(__VITE_APP_PROXY__)
|
||||
if (JSON.parse(__VITE_APP_PROXY__)) {
|
||||
// 自动拼接代理前缀
|
||||
options.url = import.meta.env.VITE_APP_PROXY_PREFIX + options.url
|
||||
} else {
|
||||
options.url = baseUrl + options.url
|
||||
}
|
||||
// #endif
|
||||
// 非H5正常拼接
|
||||
// #ifndef H5
|
||||
options.url = baseUrl + options.url
|
||||
// #endif
|
||||
// TIPS: 如果需要对接多个后端服务,也可以在这里处理,拼接成所需要的地址
|
||||
}
|
||||
// 1. 请求超时
|
||||
options.timeout = 10000 // 10s
|
||||
// 2. (可选)添加小程序端请求头标识
|
||||
options.header = {
|
||||
platform, // 可选,与 uniapp 定义的平台一致,告诉后台来源
|
||||
...options.header,
|
||||
}
|
||||
// 3. 添加 token 请求头标识
|
||||
const userStore = useUserStore()
|
||||
const { token } = userStore.userInfo as unknown as IUserInfo
|
||||
if (token) {
|
||||
options.header.Authorization = `Bearer ${token}`
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const requestInterceptor = {
|
||||
install() {
|
||||
// 拦截 request 请求
|
||||
uni.addInterceptor('request', httpInterceptor)
|
||||
// 拦截 uploadFile 文件上传
|
||||
uni.addInterceptor('uploadFile', httpInterceptor)
|
||||
},
|
||||
}
|
64
src/interceptors/route.ts
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* by 菲鸽 on 2024-03-06
|
||||
* 路由拦截,通常也是登录拦截
|
||||
* 可以设置路由白名单,或者黑名单,看业务需要选哪一个
|
||||
* 我这里应为大部分都可以随便进入,所以使用黑名单
|
||||
*/
|
||||
import { useUserStore } from '@/store'
|
||||
import { needLoginPages as _needLoginPages, getNeedLoginPages, getLastPage } from '@/utils'
|
||||
|
||||
// TODO Check
|
||||
const loginRoute = '/pages/login/index'
|
||||
|
||||
const isLogined = () => {
|
||||
const userStore = useUserStore()
|
||||
return userStore.isLogined
|
||||
}
|
||||
|
||||
const isDev = import.meta.env.DEV
|
||||
|
||||
// 黑名单登录拦截器 - (适用于大部分页面不需要登录,少部分页面需要登录)
|
||||
const navigateToInterceptor = {
|
||||
// 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同
|
||||
// 增加对相对路径的处理,BY 网友 @ideal
|
||||
invoke({ url }: { url: string }) {
|
||||
// console.log(url) // /pages/route-interceptor/index?name=feige&age=30
|
||||
let path = url.split('?')[0]
|
||||
|
||||
// 处理相对路径
|
||||
if (!path.startsWith('/')) {
|
||||
const currentPath = getLastPage().route
|
||||
const normalizedCurrentPath = currentPath.startsWith('/') ? currentPath : `/${currentPath}`
|
||||
const baseDir = normalizedCurrentPath.substring(0, normalizedCurrentPath.lastIndexOf('/'))
|
||||
path = `${baseDir}/${path}`
|
||||
}
|
||||
|
||||
let needLoginPages: string[] = []
|
||||
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
|
||||
if (isDev) {
|
||||
needLoginPages = getNeedLoginPages()
|
||||
} else {
|
||||
needLoginPages = _needLoginPages
|
||||
}
|
||||
const isNeedLogin = needLoginPages.includes(path)
|
||||
if (!isNeedLogin) {
|
||||
return true
|
||||
}
|
||||
const hasLogin = isLogined()
|
||||
if (hasLogin) {
|
||||
return true
|
||||
}
|
||||
const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
|
||||
uni.navigateTo({ url: redirectRoute })
|
||||
return false
|
||||
},
|
||||
}
|
||||
|
||||
export const routeInterceptor = {
|
||||
install() {
|
||||
uni.addInterceptor('navigateTo', navigateToInterceptor)
|
||||
uni.addInterceptor('reLaunch', navigateToInterceptor)
|
||||
uni.addInterceptor('redirectTo', navigateToInterceptor)
|
||||
uni.addInterceptor('switchTab', navigateToInterceptor)
|
||||
},
|
||||
}
|
17
src/layouts/default.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<wd-config-provider :themeVars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
|
||||
const themeVars: ConfigProviderThemeVars = {
|
||||
// colorTheme: 'red',
|
||||
// buttonPrimaryBgColor: '#07c160',
|
||||
// buttonPrimaryColor: '#07c160',
|
||||
}
|
||||
</script>
|
17
src/layouts/demo.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<wd-config-provider :themeVars="themeVars">
|
||||
<slot />
|
||||
<wd-toast />
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
|
||||
const themeVars: ConfigProviderThemeVars = {
|
||||
// colorTheme: 'red',
|
||||
// buttonPrimaryBgColor: '#07c160',
|
||||
// buttonPrimaryColor: '#07c160',
|
||||
}
|
||||
</script>
|
21
src/main.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import '@/style/index.scss'
|
||||
import { VueQueryPlugin } from '@tanstack/vue-query'
|
||||
import 'virtual:uno.css'
|
||||
import { createSSRApp } from 'vue'
|
||||
|
||||
import App from './App.vue'
|
||||
import { prototypeInterceptor, requestInterceptor, routeInterceptor } from './interceptors'
|
||||
import store from './store'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
app.use(store)
|
||||
app.use(routeInterceptor)
|
||||
app.use(requestInterceptor)
|
||||
app.use(prototypeInterceptor)
|
||||
app.use(VueQueryPlugin)
|
||||
|
||||
return {
|
||||
app,
|
||||
}
|
||||
}
|
111
src/manifest.json
Normal file
@ -0,0 +1,111 @@
|
||||
{
|
||||
"name": "unibest",
|
||||
"appid": "H57F2ACE4",
|
||||
"description": "",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"nvueStyleCompiler": "uni-app",
|
||||
"compilerVersion": 3,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
"modules": {},
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
],
|
||||
"minSdkVersion": 30,
|
||||
"targetSdkVersion": 30,
|
||||
"abiFilters": [
|
||||
"armeabi-v7a",
|
||||
"arm64-v8a"
|
||||
]
|
||||
},
|
||||
"ios": {},
|
||||
"sdkConfigs": {},
|
||||
"icons": {
|
||||
"android": {
|
||||
"hdpi": "static/app/icons/72x72.png",
|
||||
"xhdpi": "static/app/icons/96x96.png",
|
||||
"xxhdpi": "static/app/icons/144x144.png",
|
||||
"xxxhdpi": "static/app/icons/192x192.png"
|
||||
},
|
||||
"ios": {
|
||||
"appstore": "static/app/icons/1024x1024.png",
|
||||
"ipad": {
|
||||
"app": "static/app/icons/76x76.png",
|
||||
"app@2x": "static/app/icons/152x152.png",
|
||||
"notification": "static/app/icons/20x20.png",
|
||||
"notification@2x": "static/app/icons/40x40.png",
|
||||
"proapp@2x": "static/app/icons/167x167.png",
|
||||
"settings": "static/app/icons/29x29.png",
|
||||
"settings@2x": "static/app/icons/58x58.png",
|
||||
"spotlight": "static/app/icons/40x40.png",
|
||||
"spotlight@2x": "static/app/icons/80x80.png"
|
||||
},
|
||||
"iphone": {
|
||||
"app@2x": "static/app/icons/120x120.png",
|
||||
"app@3x": "static/app/icons/180x180.png",
|
||||
"notification@2x": "static/app/icons/40x40.png",
|
||||
"notification@3x": "static/app/icons/60x60.png",
|
||||
"settings@2x": "static/app/icons/58x58.png",
|
||||
"settings@3x": "static/app/icons/87x87.png",
|
||||
"spotlight@2x": "static/app/icons/80x80.png",
|
||||
"spotlight@3x": "static/app/icons/120x120.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compatible": {
|
||||
"ignoreVersion": true
|
||||
}
|
||||
},
|
||||
"quickapp": {},
|
||||
"mp-weixin": {
|
||||
"appid": "wxa2abb91f64032a2b",
|
||||
"setting": {
|
||||
"urlCheck": false
|
||||
},
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true,
|
||||
"styleIsolation": "shared"
|
||||
},
|
||||
"mp-baidu": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"mp-toutiao": {
|
||||
"usingComponents": true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion": "3",
|
||||
"h5": {
|
||||
"router": {
|
||||
"base": "/"
|
||||
}
|
||||
}
|
||||
}
|
20
src/pages-sub/demo/index.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<route lang="json5" type="page">
|
||||
{
|
||||
style: { navigationBarTitleText: '分包页面 标题' },
|
||||
}
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view class="text-center">
|
||||
<view class="m-8">http://localhost:9000/#/pages-sub/demo/index</view>
|
||||
<view class="text-green-500">分包页面demo</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// code here
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
58
src/pages.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"globalStyle": {
|
||||
"navigationStyle": "default",
|
||||
"navigationBarTitleText": "unibest",
|
||||
"navigationBarBackgroundColor": "#f8f8f8",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundColor": "#FFFFFF"
|
||||
},
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue",
|
||||
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue"
|
||||
}
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#999999",
|
||||
"selectedColor": "#018d71",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"borderStyle": "black",
|
||||
"height": "50px",
|
||||
"fontSize": "10px",
|
||||
"iconWidth": "24px",
|
||||
"spacing": "3px",
|
||||
"list": [
|
||||
{
|
||||
"iconPath": "static/tabbar/home.png",
|
||||
"selectedIconPath": "static/tabbar/homeHL.png",
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"iconPath": "static/tabbar/example.png",
|
||||
"selectedIconPath": "static/tabbar/exampleHL.png",
|
||||
"pagePath": "pages/about/about",
|
||||
"text": "关于"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"type": "home",
|
||||
"style": {
|
||||
"navigationStyle": "custom",
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/about/about",
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "关于"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": []
|
||||
}
|
36
src/pages/about/about.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<route lang="json5">
|
||||
{
|
||||
style: {
|
||||
navigationBarTitleText: '关于',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view
|
||||
class="bg-white overflow-hidden pt-2 px-4"
|
||||
:style="{ marginTop: safeAreaInsets?.top + 'px' }"
|
||||
>
|
||||
<view class="text-center text-3xl mt-8">
|
||||
鸽友们好,我是
|
||||
<text class="text-red-500">菲鸽</text>
|
||||
</view>
|
||||
<RequestComp />
|
||||
<UploadComp />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import RequestComp from './components/request.vue'
|
||||
import UploadComp from './components/upload.vue'
|
||||
|
||||
// 获取屏幕边界到安全区域距离
|
||||
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.test-css {
|
||||
// mt-4=>1rem=>16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
67
src/pages/about/components/request.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<route lang="json5">
|
||||
{
|
||||
layout: 'demo',
|
||||
style: {
|
||||
navigationBarTitleText: '请求',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view class="p-6 text-center">
|
||||
<view class="my-2">使用的是 laf 云后台</view>
|
||||
<view class="text-green-400">我的推荐码,可以获得佣金</view>
|
||||
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="my-2">
|
||||
<a class="my-2" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="my-2 text-left text-sm">{{ recommendUrl }}</view>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- http://localhost:9000/#/pages/index/request -->
|
||||
<wd-button @click="run" class="my-6">发送请求</wd-button>
|
||||
<view class="h-16">
|
||||
<view v-if="loading">loading...</view>
|
||||
<block v-else>
|
||||
<view class="text-xl">请求数据如下</view>
|
||||
<view class="text-green leading-8">{{ JSON.stringify(data) }}</view>
|
||||
</block>
|
||||
</view>
|
||||
<wd-button type="error" @click="reset" class="my-6" :disabled="!data">重置数据</wd-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo'
|
||||
import { findPetsByStatusQueryOptions } from '@/service/app'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
|
||||
const recommendUrl = ref('http://laf.run/signup?code=ohaOgIX')
|
||||
|
||||
// const initialData = {
|
||||
// name: 'initialData',
|
||||
// id: '1234',
|
||||
// }
|
||||
const initialData = undefined
|
||||
// 适合少部分全局性的接口————多个页面都需要的请求接口,额外编写一个 Service 层
|
||||
const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'), {
|
||||
immediate: true,
|
||||
initialData,
|
||||
})
|
||||
|
||||
// 使用 vue-query 的 useQuery 来请求数据,只做参考,是否使用请根据实际情况而定
|
||||
const {
|
||||
data: data2,
|
||||
error: error2,
|
||||
isLoading: isLoading2,
|
||||
refetch,
|
||||
} = useQuery(findPetsByStatusQueryOptions({ params: { status: ['available'] } }))
|
||||
|
||||
const reset = () => {
|
||||
data.value = initialData
|
||||
}
|
||||
</script>
|
30
src/pages/about/components/upload.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<route lang="json5" type="page">
|
||||
{
|
||||
layout: 'default',
|
||||
style: {
|
||||
navigationBarTitleText: '上传-状态一体化',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
|
||||
<template>
|
||||
<view class="p-4 text-center">
|
||||
<wd-button @click="run">选择图片并上传</wd-button>
|
||||
<view v-if="loading" class="text-blue h-10">上传...</view>
|
||||
<template v-else>
|
||||
<view class="m-2">上传后返回的接口数据:</view>
|
||||
<view class="m-2">{{ data }}</view>
|
||||
<view class="h-80 w-full">
|
||||
<image v-if="data" :src="data || data" mode="scaleToFill" />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const { loading, data, run } = useUpload({ user: '菲鸽' })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
58
src/pages/index/index.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
|
||||
<route lang="json5" type="home">
|
||||
{
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
navigationBarTitleText: '首页',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
<template>
|
||||
<view
|
||||
class="bg-white overflow-hidden pt-2 px-4"
|
||||
:style="{ marginTop: safeAreaInsets?.top + 'px' }"
|
||||
>
|
||||
<view class="mt-12">
|
||||
<image src="/static/logo.svg" alt="" class="w-28 h-28 block mx-auto" />
|
||||
</view>
|
||||
<view class="text-center text-4xl main-title-color mt-4">unibest</view>
|
||||
<view class="text-center text-2xl mt-2 mb-8">最好用的 uniapp 开发模板</view>
|
||||
|
||||
<view class="text-justify max-w-100 m-auto text-4 indent mb-2">{{ description }}</view>
|
||||
<view class="text-center mt-8">
|
||||
当前平台是:
|
||||
<text class="text-green-500">{{ PLATFORM.platform }}</text>
|
||||
</view>
|
||||
<view class="text-center mt-4">
|
||||
模板分支是:
|
||||
<text class="text-green-500">base</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { TestEnum } from '@/typings'
|
||||
import PLATFORM from '@/utils/platform'
|
||||
|
||||
defineOptions({
|
||||
name: 'Home',
|
||||
})
|
||||
|
||||
// 获取屏幕边界到安全区域距离
|
||||
const { safeAreaInsets } = uni.getSystemInfoSync()
|
||||
const author = ref('菲鸽')
|
||||
const description = ref(
|
||||
'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite4 + UnoCss + UniUI + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',
|
||||
)
|
||||
// 测试 uni API 自动引入
|
||||
onLoad(() => {
|
||||
console.log(author)
|
||||
console.log(TestEnum.A)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.main-title-color {
|
||||
color: #d14328;
|
||||
}
|
||||
</style>
|
13
src/service/app/displayEnumLabel.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import * as API from './types';
|
||||
|
||||
export function displayStatusEnum(field: API.IStatusEnum) {
|
||||
return { available: 'available', pending: 'pending', sold: 'sold' }[field];
|
||||
}
|
||||
|
||||
export function displayStatusEnum2(field: API.IStatusEnum2) {
|
||||
return { placed: 'placed', approved: 'approved', delivered: 'delivered' }[
|
||||
field
|
||||
];
|
||||
}
|
11
src/service/app/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
export * from './types';
|
||||
export * from './displayEnumLabel';
|
||||
|
||||
export * from './pet';
|
||||
export * from './pet.vuequery';
|
||||
export * from './store';
|
||||
export * from './store.vuequery';
|
||||
export * from './user';
|
||||
export * from './user.vuequery';
|
193
src/service/app/pet.ts
Normal file
@ -0,0 +1,193 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as API from './types';
|
||||
|
||||
/** Update an existing pet PUT /pet */
|
||||
export async function updatePet({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.Pet;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/pet', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Add a new pet to the store POST /pet */
|
||||
export async function addPet({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.Pet;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/pet', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Find pet by ID Returns a single pet GET /pet/${param0} */
|
||||
export async function getPetById({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getPetByIdParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { petId: param0, ...queryParams } = params;
|
||||
|
||||
return request<API.Pet>(`/pet/${param0}`, {
|
||||
method: 'GET',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Updates a pet in the store with form data POST /pet/${param0} */
|
||||
export async function updatePetWithForm({
|
||||
params,
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.updatePetWithFormParams;
|
||||
body: {
|
||||
/** Updated name of the pet */
|
||||
name?: string;
|
||||
/** Updated status of the pet */
|
||||
status?: string;
|
||||
};
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { petId: param0, ...queryParams } = params;
|
||||
|
||||
return request<unknown>(`/pet/${param0}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
params: { ...queryParams },
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Deletes a pet DELETE /pet/${param0} */
|
||||
export async function deletePet({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.deletePetParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { petId: param0, ...queryParams } = params;
|
||||
|
||||
return request<unknown>(`/pet/${param0}`, {
|
||||
method: 'DELETE',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** uploads an image POST /pet/${param0}/uploadImage */
|
||||
export async function uploadFile({
|
||||
params,
|
||||
body,
|
||||
file,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.uploadFileParams;
|
||||
body: {
|
||||
/** Additional data to pass to server */
|
||||
additionalMetadata?: string;
|
||||
};
|
||||
file?: File;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { petId: param0, ...queryParams } = params;
|
||||
const formData = new FormData();
|
||||
|
||||
if (file) {
|
||||
formData.append('file', file);
|
||||
}
|
||||
|
||||
Object.keys(body).forEach((ele) => {
|
||||
const item = (body as { [key: string]: any })[ele];
|
||||
|
||||
if (item !== undefined && item !== null) {
|
||||
if (typeof item === 'object' && !(item instanceof File)) {
|
||||
if (item instanceof Array) {
|
||||
item.forEach((f) => formData.append(ele, f || ''));
|
||||
} else {
|
||||
formData.append(ele, JSON.stringify(item));
|
||||
}
|
||||
} else {
|
||||
formData.append(ele, item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return request<API.ApiResponse>(`/pet/${param0}/uploadImage`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
params: { ...queryParams },
|
||||
data: formData,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Finds Pets by status Multiple status values can be provided with comma separated strings GET /pet/findByStatus */
|
||||
export async function findPetsByStatus({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.findPetsByStatusParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<API.Pet[]>('/pet/findByStatus', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Finds Pets by tags Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. GET /pet/findByTags */
|
||||
export async function findPetsByTags({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.findPetsByTagsParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<API.Pet[]>('/pet/findByTags', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
151
src/service/app/pet.vuequery.ts
Normal file
@ -0,0 +1,151 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import { queryOptions, useMutation } from '@tanstack/vue-query';
|
||||
import type { DefaultError } from '@tanstack/vue-query';
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as apis from './pet';
|
||||
import * as API from './types';
|
||||
|
||||
/** Update an existing pet PUT /pet */
|
||||
export function useUpdatePetMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.updatePet,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Add a new pet to the store POST /pet */
|
||||
export function useAddPetMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.addPet,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Find pet by ID Returns a single pet GET /pet/${param0} */
|
||||
export function getPetByIdQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getPetByIdParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.getPetById(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['getPetById', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Updates a pet in the store with form data POST /pet/${param0} */
|
||||
export function useUpdatePetWithFormMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.updatePetWithForm,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Deletes a pet DELETE /pet/${param0} */
|
||||
export function useDeletePetMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.deletePet,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** uploads an image POST /pet/${param0}/uploadImage */
|
||||
export function useUploadFileMutation(options?: {
|
||||
onSuccess?: (value?: API.ApiResponse) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.uploadFile,
|
||||
onSuccess(data: API.ApiResponse) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Finds Pets by status Multiple status values can be provided with comma separated strings GET /pet/findByStatus */
|
||||
export function findPetsByStatusQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.findPetsByStatusParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.findPetsByStatus(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['findPetsByStatus', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Finds Pets by tags Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. GET /pet/findByTags */
|
||||
export function findPetsByTagsQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.findPetsByTagsParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.findPetsByTags(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['findPetsByTags', options],
|
||||
});
|
||||
}
|
72
src/service/app/store.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as API from './types';
|
||||
|
||||
/** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */
|
||||
export async function getInventory({
|
||||
options,
|
||||
}: {
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<Record<string, unknown>>('/store/inventory', {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Place an order for a pet POST /store/order */
|
||||
export async function placeOrder({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.Order;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<API.Order>('/store/order', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */
|
||||
export async function getOrderById({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getOrderByIdParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { orderId: param0, ...queryParams } = params;
|
||||
|
||||
return request<API.Order>(`/store/order/${param0}`, {
|
||||
method: 'GET',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */
|
||||
export async function deleteOrder({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.deleteOrderParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { orderId: param0, ...queryParams } = params;
|
||||
|
||||
return request<unknown>(`/store/order/${param0}`, {
|
||||
method: 'DELETE',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
75
src/service/app/store.vuequery.ts
Normal file
@ -0,0 +1,75 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import { queryOptions, useMutation } from '@tanstack/vue-query';
|
||||
import type { DefaultError } from '@tanstack/vue-query';
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as apis from './store';
|
||||
import * as API from './types';
|
||||
|
||||
/** Returns pet inventories by status Returns a map of status codes to quantities GET /store/inventory */
|
||||
export function getInventoryQueryOptions(options: {
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.getInventory(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['getInventory', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Place an order for a pet POST /store/order */
|
||||
export function usePlaceOrderMutation(options?: {
|
||||
onSuccess?: (value?: API.Order) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.placeOrder,
|
||||
onSuccess(data: API.Order) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Find purchase order by ID For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions GET /store/order/${param0} */
|
||||
export function getOrderByIdQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getOrderByIdParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.getOrderById(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['getOrderById', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Delete purchase order by ID For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors DELETE /store/order/${param0} */
|
||||
export function useDeleteOrderMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.deleteOrder,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
128
src/service/app/types.ts
Normal file
@ -0,0 +1,128 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
|
||||
export type ApiResponse = {
|
||||
code?: number;
|
||||
type?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export type Category = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export type deleteOrderParams = {
|
||||
/** ID of the order that needs to be deleted */
|
||||
orderId: number;
|
||||
};
|
||||
|
||||
export type deletePetParams = {
|
||||
/** Pet id to delete */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
export type deleteUserParams = {
|
||||
/** The name that needs to be deleted */
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type findPetsByStatusParams = {
|
||||
/** Status values that need to be considered for filter */
|
||||
status: ('available' | 'pending' | 'sold')[];
|
||||
};
|
||||
|
||||
export type findPetsByTagsParams = {
|
||||
/** Tags to filter by */
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
export type getOrderByIdParams = {
|
||||
/** ID of pet that needs to be fetched */
|
||||
orderId: number;
|
||||
};
|
||||
|
||||
export type getPetByIdParams = {
|
||||
/** ID of pet to return */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
export type getUserByNameParams = {
|
||||
/** The name that needs to be fetched. Use user1 for testing. */
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type loginUserParams = {
|
||||
/** The user name for login */
|
||||
username: string;
|
||||
/** The password for login in clear text */
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type Order = {
|
||||
id?: number;
|
||||
petId?: number;
|
||||
quantity?: number;
|
||||
shipDate?: string;
|
||||
/** Order Status */
|
||||
status?: 'placed' | 'approved' | 'delivered';
|
||||
complete?: boolean;
|
||||
};
|
||||
|
||||
export type Pet = {
|
||||
id?: number;
|
||||
category?: Category;
|
||||
name: string;
|
||||
photoUrls: string[];
|
||||
tags?: Tag[];
|
||||
/** pet status in the store */
|
||||
status?: 'available' | 'pending' | 'sold';
|
||||
};
|
||||
|
||||
export enum StatusEnum {
|
||||
available = 'available',
|
||||
pending = 'pending',
|
||||
sold = 'sold',
|
||||
}
|
||||
|
||||
export type IStatusEnum = keyof typeof StatusEnum;
|
||||
|
||||
export enum StatusEnum2 {
|
||||
placed = 'placed',
|
||||
approved = 'approved',
|
||||
delivered = 'delivered',
|
||||
}
|
||||
|
||||
export type IStatusEnum2 = keyof typeof StatusEnum2;
|
||||
|
||||
export type Tag = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export type updatePetWithFormParams = {
|
||||
/** ID of pet that needs to be updated */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
export type updateUserParams = {
|
||||
/** name that need to be updated */
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type uploadFileParams = {
|
||||
/** ID of pet to update */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
export type User = {
|
||||
id?: number;
|
||||
username?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
phone?: string;
|
||||
/** User Status */
|
||||
userStatus?: number;
|
||||
};
|
150
src/service/app/user.ts
Normal file
@ -0,0 +1,150 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as API from './types';
|
||||
|
||||
/** Create user This can only be done by the logged in user. 返回值: successful operation POST /user */
|
||||
export async function createUser({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.User;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/user', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Get user by user name GET /user/${param0} */
|
||||
export async function getUserByName({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getUserByNameParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { username: param0, ...queryParams } = params;
|
||||
|
||||
return request<API.User>(`/user/${param0}`, {
|
||||
method: 'GET',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Updated user This can only be done by the logged in user. PUT /user/${param0} */
|
||||
export async function updateUser({
|
||||
params,
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.updateUserParams;
|
||||
body: API.User;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { username: param0, ...queryParams } = params;
|
||||
|
||||
return request<unknown>(`/user/${param0}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
params: { ...queryParams },
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Delete user This can only be done by the logged in user. DELETE /user/${param0} */
|
||||
export async function deleteUser({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.deleteUserParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
const { username: param0, ...queryParams } = params;
|
||||
|
||||
return request<unknown>(`/user/${param0}`, {
|
||||
method: 'DELETE',
|
||||
params: { ...queryParams },
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Creates list of users with given input array 返回值: successful operation POST /user/createWithArray */
|
||||
export async function createUsersWithArrayInput({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.User[];
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/user/createWithArray', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Creates list of users with given input array 返回值: successful operation POST /user/createWithList */
|
||||
export async function createUsersWithListInput({
|
||||
body,
|
||||
options,
|
||||
}: {
|
||||
body: API.User[];
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/user/createWithList', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Logs user into the system GET /user/login */
|
||||
export async function loginUser({
|
||||
params,
|
||||
options,
|
||||
}: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.loginUserParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<string>('/user/login', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** Logs out current logged in user session 返回值: successful operation GET /user/logout */
|
||||
export async function logoutUser({
|
||||
options,
|
||||
}: {
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return request<unknown>('/user/logout', {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
149
src/service/app/user.vuequery.ts
Normal file
@ -0,0 +1,149 @@
|
||||
/* eslint-disable */
|
||||
// @ts-ignore
|
||||
import { queryOptions, useMutation } from '@tanstack/vue-query';
|
||||
import type { DefaultError } from '@tanstack/vue-query';
|
||||
import request from '@/utils/request';
|
||||
import { CustomRequestOptions } from '@/interceptors/request';
|
||||
|
||||
import * as apis from './user';
|
||||
import * as API from './types';
|
||||
|
||||
/** Create user This can only be done by the logged in user. 返回值: successful operation POST /user */
|
||||
export function useCreateUserMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.createUser,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Get user by user name GET /user/${param0} */
|
||||
export function getUserByNameQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.getUserByNameParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.getUserByName(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['getUserByName', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Updated user This can only be done by the logged in user. PUT /user/${param0} */
|
||||
export function useUpdateUserMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.updateUser,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Delete user This can only be done by the logged in user. DELETE /user/${param0} */
|
||||
export function useDeleteUserMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.deleteUser,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Creates list of users with given input array 返回值: successful operation POST /user/createWithArray */
|
||||
export function useCreateUsersWithArrayInputMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.createUsersWithArrayInput,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Creates list of users with given input array 返回值: successful operation POST /user/createWithList */
|
||||
export function useCreateUsersWithListInputMutation(options?: {
|
||||
onSuccess?: (value?: unknown) => void;
|
||||
onError?: (error?: DefaultError) => void;
|
||||
}) {
|
||||
const { onSuccess, onError } = options || {};
|
||||
|
||||
const response = useMutation({
|
||||
mutationFn: apis.createUsersWithListInput,
|
||||
onSuccess(data: unknown) {
|
||||
onSuccess?.(data);
|
||||
},
|
||||
onError(error) {
|
||||
onError?.(error);
|
||||
},
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/** Logs user into the system GET /user/login */
|
||||
export function loginUserQueryOptions(options: {
|
||||
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
|
||||
params: API.loginUserParams;
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.loginUser(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['loginUser', options],
|
||||
});
|
||||
}
|
||||
|
||||
/** Logs out current logged in user session 返回值: successful operation GET /user/logout */
|
||||
export function logoutUserQueryOptions(options: {
|
||||
options?: CustomRequestOptions;
|
||||
}) {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey }) => {
|
||||
return apis.logoutUser(queryKey[1] as typeof options);
|
||||
},
|
||||
queryKey: ['logoutUser', options],
|
||||
});
|
||||
}
|
27
src/service/index/foo.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { http } from '@/utils/http'
|
||||
export interface IFooItem {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
/** GET 请求 */
|
||||
export const getFooAPI = (name: string) => {
|
||||
return http.get<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** GET 请求;支持 传递 header 的范例 */
|
||||
export const getFooAPI2 = (name: string) => {
|
||||
return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' })
|
||||
}
|
||||
|
||||
/** POST 请求 */
|
||||
export const postFooAPI = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** POST 请求;需要传递 query 参数的范例;微信小程序经常有同时需要query参数和body参数的场景 */
|
||||
export const postFooAPI2 = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name })
|
||||
}
|
||||
/** POST 请求;支持 传递 header 的范例 */
|
||||
export const postFooAPI3 = (name: string) => {
|
||||
return http.post<IFooItem>('/foo', { name }, { name }, { 'Content-Type-100': '100' })
|
||||
}
|
BIN
src/static/app/icons/1024x1024.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
src/static/app/icons/120x120.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/static/app/icons/144x144.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
src/static/app/icons/152x152.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/static/app/icons/167x167.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
src/static/app/icons/180x180.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
src/static/app/icons/192x192.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/static/app/icons/20x20.png
Normal file
After Width: | Height: | Size: 574 B |
BIN
src/static/app/icons/29x29.png
Normal file
After Width: | Height: | Size: 780 B |
BIN
src/static/app/icons/40x40.png
Normal file
After Width: | Height: | Size: 985 B |
BIN
src/static/app/icons/58x58.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/static/app/icons/60x60.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/static/app/icons/72x72.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/static/app/icons/76x76.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/static/app/icons/80x80.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src/static/app/icons/87x87.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
src/static/app/icons/96x96.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
0
src/static/images/.gitkeep
Normal file
33
src/static/logo.svg
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="_图层_2" data-name="图层 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.39 113.39">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1 {
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
fill: #d14328;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
fill: #2c8d3a;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="_图层_1-2" data-name="图层 1">
|
||||
<g>
|
||||
<rect class="cls-1" width="113.39" height="113.39" />
|
||||
<g>
|
||||
<path class="cls-3"
|
||||
d="M86.31,11.34H25.08c-8.14,0-14.74,6.6-14.74,14.74v61.23c0,8.14,6.6,14.74,14.74,14.74h61.23c.12,0,.24-.02,.37-.02-9.76-.2-17.64-8.18-17.64-17.99,0-.56,.03-1.12,.08-1.67H34.1c-1.57,0-2.83-1.27-2.83-2.83V32.43c0-.78,.63-1.42,1.42-1.42h9.17c.78,0,1.42,.63,1.42,1.42v36.52c0,.78,.63,1.42,1.42,1.42h22.02c.78,0,1.42-.63,1.42-1.42V32.43c0-.78,.63-1.42,1.42-1.42h9.17c.78,0,1.42,.63,1.42,1.42v34.99c2.13-.89,4.47-1.39,6.92-1.39,5.66,0,10.7,2.63,14.01,6.72V26.08c0-8.14-6.6-14.74-14.74-14.74Z" />
|
||||
<g>
|
||||
<path class="cls-2"
|
||||
d="M87.04,68.03c-8.83,0-16.01,7.18-16.01,16.01s7.18,16.01,16.01,16.01,16.01-7.18,16.01-16.01-7.18-16.01-16.01-16.01Zm-.27,24.84h-7.2v-3h1.18v-10.48h4.58v2.81h1.42c.84,0,1.46-.16,1.88-.48s.62-.87,.62-1.64c0-.69-.25-1.17-.74-1.45s-1.19-.42-2.09-.42h-6.84v-3h7.2c2.38,0,4.15,.38,5.31,1.15,1.16,.77,1.74,1.93,1.74,3.48,0,1.71-.83,2.93-2.5,3.64,1.07,.4,1.87,.95,2.39,1.65s.79,1.56,.79,2.58c0,3.44-2.58,5.16-7.73,5.16Z" />
|
||||
<path class="cls-2"
|
||||
d="M86.49,85.17h-1.16v4.7h1.8c.81,0,1.46-.18,1.94-.55s.72-.95,.72-1.73c0-.86-.25-1.48-.74-1.85s-1.35-.56-2.56-.56Z" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/static/tabbar/example.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/static/tabbar/exampleHL.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/static/tabbar/home.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/static/tabbar/homeHL.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/static/tabbar/personal.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src/static/tabbar/personalHL.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
17
src/store/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import { createPersistedState } from 'pinia-plugin-persistedstate' // 数据持久化
|
||||
|
||||
const store = createPinia()
|
||||
store.use(
|
||||
createPersistedState({
|
||||
storage: {
|
||||
getItem: uni.getStorageSync,
|
||||
setItem: uni.setStorageSync,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export default store
|
||||
|
||||
// 模块统一导出
|
||||
export * from './user'
|
35
src/store/user.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const initState = { nickname: '', avatar: '' }
|
||||
|
||||
export const useUserStore = defineStore(
|
||||
'user',
|
||||
() => {
|
||||
const userInfo = ref<IUserInfo>({ ...initState })
|
||||
|
||||
const setUserInfo = (val: IUserInfo) => {
|
||||
userInfo.value = val
|
||||
}
|
||||
|
||||
const clearUserInfo = () => {
|
||||
userInfo.value = { ...initState }
|
||||
}
|
||||
// 一般没有reset需求,不需要的可以删除
|
||||
const reset = () => {
|
||||
userInfo.value = { ...initState }
|
||||
}
|
||||
const isLogined = computed(() => !!userInfo.value.token)
|
||||
|
||||
return {
|
||||
userInfo,
|
||||
setUserInfo,
|
||||
clearUserInfo,
|
||||
isLogined,
|
||||
reset,
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: true,
|
||||
},
|
||||
)
|
28
src/style/iconfont.css
Normal file
@ -0,0 +1,28 @@
|
||||
@font-face {
|
||||
font-family: 'iconfont'; /* Project id 4543091 */
|
||||
src:
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOwAAsAAAAAB9AAAANjAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDHAqDBIJqATYCJAMQCwoABCAFhGcHPRvnBsgusG3kMyE15/44PsBX09waBHv0REDt97oHAQDFrOIyPirRiULQ+TJcXV0hCYTuVFcBC915/2vX/32Q80hkZ5PZGZ9snvwruVLloidKqYN6iKC53bOtbKwVLSIi3W6zCWZbs3VbER3j9JpGX3ySYcc94IQRTK5s4epS/jSqIgvg37qlY2/jwQN7D9ADpfRCmIknQByTscVZPTBr+hnnCKg2o4bjakvXEPjuY65DJGeJNtBUhn1JxOBuB2UZmUpBOXdsFp4oxOv4GHgs3h/+wRDcicqSZJG1q9kK1z/Af9NpqxjpC2QaAdpHlCFh4spcYXs5sMWpSk5wUj31G2dLQKVKkZ/w7f/8/i/A3JVUSZK9f7xIKJeU14IFpBI/Qfkkz46GT/CuaGREfCtKJUougWeQWHvVC5Lcz2BGS+SePR99vj3yjJx7h574tp7uWcOh4yfaTjS/245TT/vkQrN+a7RLkK8+Vd+bz+FSGh+9srDQKPeJ2s29z7ah4+efdoxefRbbGwfy7ht+SuIWukzsu1b6ePP+6kN1aamb47qsPim1Ia3xdEpDcl1dckPKGYnneI23+57r2W1Mmkqs6ajrChRCs5qyQ66rTVWhgZaG7toOeHm5cxn0sSQuNDEgcUTdNTSupKI1JRZih/JssAUKezPeOJJzbNozF6zWJuuVavVU5Tgtkop/SDzHa7ytvnCTq0PhkEfi4xLLtb0PuwyOAYqmrYQApFJyoJjTnfz+ve94vvv2f/yWgxl8Jd8Di2DRDPuob59mU/+VfDCROQyR8xSnmP9fXm7liagmN39OlmbvjqG0sMsJKrU0EFXogaRSH5bNY1CmxhyUq7QC1cY1T67RwuQk5CoM2RUQNLoEUb03kDS6h2XzcyjT7iOUa/QXqq1Hn6/GUBAaGcGcWJFlGUmCoVOp8kLvABHnVczGYiOE2SVEUH5OXj/TSnTCDjHAviAWcE4RZYaGWszNiKoayGSGTASeY+PcrMjNpVMvyREMDRoxBMYRVojFMkQiMOhohubdzxtAiOapMMbERpKMnQT9SL4ceQysVdJZVa9kEbsFogIcRyEUE2kN0mL7CDVIGhBzupWMEHA5bDvipgq5hKJcKef8ivbx1kC15KgcYkghhzLxYNntxoKCReJ82jAHAAA=')
|
||||
format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4543091_njpo5b95nl.woff?t=1715485842402') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4543091_njpo5b95nl.ttf?t=1715485842402') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: 'iconfont' !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-my:before {
|
||||
content: '\e78c';
|
||||
}
|
||||
|
||||
.icon-package:before {
|
||||
content: '\e9c2';
|
||||
}
|
||||
|
||||
.icon-chat:before {
|
||||
content: '\e600';
|
||||
}
|
18
src/style/index.scss
Normal file
@ -0,0 +1,18 @@
|
||||
// @import './iconfont.css';
|
||||
|
||||
.test {
|
||||
// 可以通过 @apply 多个样式封装整体样式
|
||||
@apply mt-4 ml-4;
|
||||
|
||||
padding-top: 4px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
:root,
|
||||
page {
|
||||
// 修改按主题色
|
||||
// --wot-color-theme: #37c2bc;
|
||||
|
||||
// 修改按钮背景色
|
||||
// --wot-button-primary-bg-color: green;
|
||||
}
|
187
src/types/auto-import.d.ts
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
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 getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
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 onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||
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 toValue: typeof import('vue')['toValue']
|
||||
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 useId: typeof import('vue')['useId']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useNavbarWeixin: (typeof import('../hooks/useNavbarWeixin'))['default']
|
||||
const useRequest: typeof import('../hooks/useRequest')['default']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||
const useUpload: typeof import('../hooks/useUpload')['default']
|
||||
const useUpload2: typeof import('../hooks/useUpload2')['default']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
// for vue template auto import
|
||||
import { UnwrapRef } from 'vue'
|
||||
declare module 'vue' {
|
||||
interface GlobalComponents {}
|
||||
interface ComponentCustomProperties {
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
|
||||
readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']>
|
||||
readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']>
|
||||
readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']>
|
||||
readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']>
|
||||
readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']>
|
||||
readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']>
|
||||
readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']>
|
||||
readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']>
|
||||
readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']>
|
||||
readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']>
|
||||
readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']>
|
||||
readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']>
|
||||
readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']>
|
||||
readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']>
|
||||
readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']>
|
||||
readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']>
|
||||
readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']>
|
||||
readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
|
||||
readonly useRequest: UnwrapRef<typeof import('../hooks/useRequest')['default']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
||||
readonly useUpload: UnwrapRef<typeof import('../hooks/useUpload')['default']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
23
src/types/global.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
declare const __UNI_PLATFORM__:
|
||||
| 'h5'
|
||||
| 'app'
|
||||
| 'mp-alipay'
|
||||
| 'mp-baidu'
|
||||
| 'mp-jd'
|
||||
| 'mp-kuaishou'
|
||||
| 'mp-lark'
|
||||
| 'mp-qq'
|
||||
| 'mp-toutiao'
|
||||
| 'mp-weixin'
|
||||
| 'quickapp-webview'
|
||||
| 'quickapp-webview-huawei'
|
||||
| 'quickapp-webview-union'
|
||||
|
||||
declare const __VITE_APP_PROXY__: 'true' | 'false'
|
||||
|
||||
declare namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
template: any
|
||||
block: any
|
||||
}
|
||||
}
|
8
src/types/shims-uni.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/// <reference types='@dcloudio/types' />
|
||||
import 'vue'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance
|
||||
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
23
src/types/uni-pages.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by vite-plugin-uni-pages
|
||||
|
||||
interface NavigateToOptions {
|
||||
url: "/pages/index/index" |
|
||||
"/pages/about/about";
|
||||
}
|
||||
interface RedirectToOptions extends NavigateToOptions {}
|
||||
|
||||
interface SwitchTabOptions {
|
||||
url: "/pages/index/index" | "/pages/about/about"
|
||||
}
|
||||
|
||||
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;
|
||||
|
||||
declare interface Uni {
|
||||
navigateTo(options: UniNamespace.NavigateToOptions & NavigateToOptions): void;
|
||||
redirectTo(options: UniNamespace.RedirectToOptions & RedirectToOptions): void;
|
||||
switchTab(options: UniNamespace.SwitchTabOptions & SwitchTabOptions): void;
|
||||
reLaunch(options: UniNamespace.ReLaunchOptions & ReLaunchOptions): void;
|
||||
}
|
28
src/typings.d.ts
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// 全局要用的类型放到这里
|
||||
|
||||
declare global {
|
||||
type IResData<T> = {
|
||||
code: number
|
||||
msg: string
|
||||
data: T
|
||||
}
|
||||
|
||||
// uni.uploadFile文件上传参数
|
||||
type IUniUploadFileOptions = {
|
||||
file?: File
|
||||
files?: UniApp.UploadFileOptionFiles[]
|
||||
filePath?: string
|
||||
name?: string
|
||||
formData?: any
|
||||
}
|
||||
|
||||
type IUserInfo = {
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
/** 微信的 openid,非微信没有这个字段 */
|
||||
openid?: string
|
||||
token?: string
|
||||
}
|
||||
}
|
||||
|
||||
export {} // 防止模块污染
|
6
src/typings.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// 枚举定义
|
||||
|
||||
export enum TestEnum {
|
||||
A = '1',
|
||||
B = '2',
|
||||
}
|
77
src/uni.scss
Normal file
@ -0,0 +1,77 @@
|
||||
/* stylelint-disable comment-empty-line-before */
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color: #333; // 基本色
|
||||
$uni-text-color-inverse: #fff; // 反色
|
||||
$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable: #c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color: #fff;
|
||||
$uni-bg-color-grey: #f8f8f8;
|
||||
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
|
||||
$uni-bg-color-mask: rgb(0 0 0 / 40%); // 遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color: #c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm: 12px;
|
||||
$uni-font-size-base: 14px;
|
||||
$uni-font-size-lg: 16;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm: 20px;
|
||||
$uni-img-size-base: 26px;
|
||||
$uni-img-size-lg: 40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2c405a; // 文章标题颜色
|
||||
$uni-font-size-title: 20px;
|
||||
$uni-color-subtitle: #555; // 二级标题颜色
|
||||
$uni-font-size-subtitle: 18px;
|
||||
$uni-color-paragraph: #3f536e; // 文章段落颜色
|
||||
$uni-font-size-paragraph: 15px;
|
0
src/uni_modules/.gitkeep
Normal file
89
src/utils/http.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { CustomRequestOptions } from '@/interceptors/request'
|
||||
|
||||
export const http = <T>(options: CustomRequestOptions) => {
|
||||
// 1. 返回 Promise 对象
|
||||
return new Promise<IResData<T>>((resolve, reject) => {
|
||||
uni.request({
|
||||
...options,
|
||||
dataType: 'json',
|
||||
// #ifndef MP-WEIXIN
|
||||
responseType: 'json',
|
||||
// #endif
|
||||
// 响应成功
|
||||
success(res) {
|
||||
// 状态码 2xx,参考 axios 的设计
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
// 2.1 提取核心数据 res.data
|
||||
resolve(res.data as IResData<T>)
|
||||
} else if (res.statusCode === 401) {
|
||||
// 401错误 -> 清理用户信息,跳转到登录页
|
||||
// userStore.clearUserInfo()
|
||||
// uni.navigateTo({ url: '/pages/login/login' })
|
||||
reject(res)
|
||||
} else {
|
||||
// 其他错误 -> 根据后端错误信息轻提示
|
||||
!options.hideErrorToast &&
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as IResData<T>).msg || '请求错误',
|
||||
})
|
||||
reject(res)
|
||||
}
|
||||
},
|
||||
// 响应失败
|
||||
fail(err) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '网络错误,换个网络试试',
|
||||
})
|
||||
reject(err)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 请求
|
||||
* @param url 后台地址
|
||||
* @param query 请求query参数
|
||||
* @param header 请求头,默认为json格式
|
||||
* @returns
|
||||
*/
|
||||
export const httpGet = <T>(
|
||||
url: string,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
method: 'GET',
|
||||
header,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 请求
|
||||
* @param url 后台地址
|
||||
* @param data 请求body参数
|
||||
* @param query 请求query参数,post请求也支持query,很多微信接口都需要
|
||||
* @param header 请求头,默认为json格式
|
||||
* @returns
|
||||
*/
|
||||
export const httpPost = <T>(
|
||||
url: string,
|
||||
data?: Record<string, any>,
|
||||
query?: Record<string, any>,
|
||||
header?: Record<string, any>,
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
data,
|
||||
method: 'POST',
|
||||
header,
|
||||
})
|
||||
}
|
||||
|
||||
http.get = httpGet
|
||||
http.post = httpPost
|