新建
Some checks failed
Auto Merge Main to Other Branches / Merge main into i18n (push) Has been cancelled
Auto Merge Main to Other Branches / Merge main into base-sard-ui (push) Has been cancelled

This commit is contained in:
sjeam 2025-08-19 11:09:20 +08:00
parent 68d2a7e652
commit 57be2a10f4
121 changed files with 21062 additions and 0 deletions

3
.commitlintrc.cjs Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
}

13
.editorconfig Normal file
View 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 # 关闭末尾空格修剪

31
.github/release.yml vendored Normal file
View File

@ -0,0 +1,31 @@
categories:
- title: 🚀 新功能
labels: [feat, feature]
- title: 🛠️ 修复
labels: [fix, bugfix]
- title: 💅 样式
labels: [style]
- title: 📄 文档
labels: [docs]
- title: ⚡️ 性能
labels: [perf]
- title: 🧪 测试
labels: [test]
- title: ♻️ 重构
labels: [refactor]
- title: 📦 构建
labels: [build]
- title: 🚨 补丁
labels: [patch, hotfix]
- title: 🌐 发布
labels: [release, publish]
- title: 🔧 流程
labels: [ci, cd, workflow]
- title: ⚙️ 配置
labels: [config, chore]
- title: 📁 文件
labels: [file]
- title: 🎨 格式化
labels: [format]
- title: 🔀 其他
labels: [other, misc]

44
.github/workflows/auto-merge.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Auto Merge Main to Other Branches
on:
push:
branches:
- main
workflow_dispatch: # 手动触发
jobs:
merge-to-i18n:
name: Merge main into i18n
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
- name: Merge main into i18n
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout i18n
git merge main --no-ff -m "Auto merge main into i18n"
git push origin i18n
merge-to-base-sard-ui:
name: Merge main into base-sard-ui
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN_AUTO_MERGE }}
- name: Merge main into base-sard-ui
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git checkout base-sard-ui
git merge main --no-ff -m "Auto merge main into base-sard-ui"
git push origin base-sard-ui

119
.github/workflows/release-log.yml vendored Normal file
View File

@ -0,0 +1,119 @@
name: Auto Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
pull-requests: read
issues: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install yq
run: sudo snap install yq
- name: Generate changelog
id: changelog
env:
CONFIG_FILE: .github/release.yml
run: |
# 解析配置文件
declare -A category_map
while IFS=";" read -r title labels; do
for label in $labels; do
category_map[$label]="$title"
done
done < <(yq -o=tsv '.categories[] | [.title, (.labels | join(" "))] | join(";")' $CONFIG_FILE)
# 获取版本范围
mapfile -t tags < <(git tag -l --sort=-version:refname)
current_tag=${tags[0]}
previous_tag=${tags[1]:-}
if [[ -z "$previous_tag" ]]; then
commit_range="$current_tag"
echo "首次发布版本: $current_tag"
else
commit_range="$previous_tag..$current_tag"
echo "版本范围: $commit_range"
fi
# 获取所有符合规范的提交
commits=$(git log --pretty=format:"%s|%h" "$commit_range")
# 生成分类日志
declare -A log_entries
while IFS="|" read -r subject hash; do
# type=$(echo "$subject" | cut -d':' -f1 | tr -d ' ')
type=$(echo "$subject" | sed -E 's/^([[:alnum:]]+)(\(.*\))?:.*/\1/' | tr -d ' ')
found=0
for label in "${!category_map[@]}"; do
if [[ "$type" == "$label" ]]; then
entry="- ${subject} (${hash:0:7})"
log_entries[${category_map[$label]}]+="$entry"$'\n'
found=1
break
fi
done
if [[ $found -eq 0 ]]; then
entry="- ${subject} (${hash:0:7})"
log_entries["其他"]+="$entry"$'\n'
fi
done <<< "$commits"
# 统计提交数量
commit_count=$(git log --oneline "$commit_range" | wc -l)
# 统计受影响的文件数量
file_count=$(git diff --name-only "$commit_range" | wc -l)
# 统计贡献者信息
contributor_stats=$(git shortlog -sn "$commit_range")
contributor_notes=""
while IFS= read -r line; do
commits=$(echo "$line" | awk '{print $1}')
name=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ //')
contributor_notes+="- @${name} (${commits} commits)\n"
done <<< "$contributor_stats"
# 构建输出内容
release_notes="## 版本更新日志 ($current_tag)\n\n"
while IFS= read -r category; do
if [[ -n "${log_entries[$category]}" ]]; then
release_notes+="### $category\n${log_entries[$category]}\n"
fi
done < <(yq '.categories[].title' $CONFIG_FILE)
# 构建输出内容
release_notes="## 版本更新日志 ($current_tag)\n\n"
current_date=$(date +"%Y-%m-%d")
# 添加发布日期和下载统计信息
release_notes+=" ### 📅 发布日期: ${current_date}\n"
while IFS= read -r category; do
if [[ -n "${log_entries[$category]}" ]]; then
release_notes+="### $category\n${log_entries[$category]}\n"
fi
done < <(yq '.categories[].title' $CONFIG_FILE)
# 添加统计信息
release_notes+="### 📊 统计信息\n"
release_notes+="- 本次发布包含 ${commit_count} 个提交\n"
release_notes+="- 影响 ${file_count} 个文件\n\n"
# 添加贡献者信息
release_notes+="### 👥 贡献者\n"
release_notes+="感谢这些优秀的贡献者(按提交次数排序):\n"
release_notes+="${contributor_notes}\n"
release_notes+="---\n"
# 写入文件
echo -e "$release_notes" > changelog.md
echo "生成日志内容:"
cat changelog.md
- name: Create Release
uses: ncipollo/release-action@v1
with:
generateReleaseNotes: false
bodyFile: changelog.md
tag: ${{ github.ref_name }}

44
.gitignore vendored Normal file
View File

@ -0,0 +1,44 @@
# 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
.eslintcache
docs/.vitepress/dist
docs/.vitepress/cache
types
# 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

1
.husky/commit-msg Normal file
View File

@ -0,0 +1 @@
npx --no-install commitlint --edit "$1"

1
.husky/pre-commit Normal file
View File

@ -0,0 +1 @@
npx lint-staged --allow-empty

6
.npmrc Normal file
View 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

14
.prettierignore Normal file
View File

@ -0,0 +1,14 @@
node_modules
# 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
View 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,jsonc}',
options: {
trailingComma: 'none',
},
},
],
}

20
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
"recommendations": [
"vue.volar",
"stylelint.vscode-stylelint",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"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",
"foxundermoon.shell-format",
"christian-kohler.path-intellisense"
]
}

118
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,118 @@
{
// prettier
"editor.defaultFormatter": "esbenp.prettier-vscode",
// stylelint
"stylelint.validate": ["css", "scss", "vue", "html"], // package.jsonscripts
"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",
"oxlint",
"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": {
"README.md": "index.html,favicon.ico,robots.txt,CHANGELOG.md",
"pages.config.ts": "manifest.config.ts,openapi-ts-request.config.ts",
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,LICENSE,.gitattributes,.gitignore,.gitpod.yml,CNAME,.npmrc,.browserslistrc",
"eslint.config.mjs": "tsconfig.json,.commitlintrc.*,.prettier*,.editorconfig,.commitlint.cjs,.eslint*"
},
//
"prettier.enable": true,
"editor.formatOnSave": true,
//
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
// Disable the default formatter, use eslint instead
// "prettier.enable": false,
// "editor.formatOnSave": false,
// Auto fix
// "editor.codeActionsOnSave": {
// "source.fixAll.eslint": "explicit",
// "source.organizeImports": "never"
// },
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
{ "rule": "format/*", "severity": "off", "fixable": true },
{ "rule": "*-indent", "severity": "off", "fixable": true },
{ "rule": "*-spacing", "severity": "off", "fixable": true },
{ "rule": "*-spaces", "severity": "off", "fixable": true },
{ "rule": "*-order", "severity": "off", "fixable": true },
{ "rule": "*-dangle", "severity": "off", "fixable": true },
{ "rule": "*-newline", "severity": "off", "fixable": true },
{ "rule": "*quotes", "severity": "off", "fixable": true },
{ "rule": "*semi", "severity": "off", "fixable": true }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"json5",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}

56
.vscode/vue3.code-snippets vendored Normal file
View 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
View 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.

View File

@ -0,0 +1,93 @@
<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.
[![GitHub Repo stars](https://img.shields.io/github/stars/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest)
[![GitHub forks](https://img.shields.io/github/forks/codercup/unibest?style=flat&logo=github)](https://github.com/codercup/unibest)
</div>
<div align="center">
[![GitHub Repo stars](https://img.shields.io/github/stars/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest)
[![GitHub forks](https://img.shields.io/github/forks/feige996/unibest?style=flat&logo=github)](https://github.com/feige996/unibest)
[![star](https://gitee.com/feige996/unibest/badge/star.svg?theme=dark)](https://gitee.com/feige996/unibest/stargazers)
[![fork](https://gitee.com/feige996/unibest/badge/fork.svg?theme=dark)](https://gitee.com/feige996/unibest/members)
![node version](https://img.shields.io/badge/node-%3E%3D18-green)
![pnpm version](https://img.shields.io/badge/pnpm-%3E%3D7.30-green)
![GitHub package.json version (subfolder of monorepo)](https://img.shields.io/github/package-json/v/feige996/unibest)
![GitHub License](https://img.shields.io/github/license/feige996/unibest)
</div>
`unibest` —— 最好的 `uniapp` 开发模板,由 `uniapp` + `Vue3` + `Ts` + `Vite5` + `UnoCss` + `wot-ui` + `z-paging` 构成,使用了最新的前端技术栈,无需依靠 `HBuilderX`,通过命令行方式运行 `web``小程序``App`(编辑器推荐 `VSCode`,可选 `webstorm`)。
`unibest` 内置了 `约定式路由``layout布局``请求封装``请求拦截``登录拦截``UnoCSS``i18n多语言` 等基础功能,提供了 `代码提示``自动格式化``统一配置``代码片段` 等辅助功能,让你编写 `uniapp` 拥有 `best` 体验 `unibest 的由来`)。
![](https://raw.githubusercontent.com/andreasbm/readme/master/screenshots/lines/rainbow.png)
<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
## &#x1F4C2; 快速开始
执行 `pnpm create unibest` 创建项目
执行 `pnpm i` 安装依赖
执行 `pnpm dev` 运行 `H5`
执行 `pnpm dev:mp` 运行 `微信小程序`
## 📦 运行(支持热更新)
- web平台 `pnpm dev:h5`, 然后打开 [http://localhost:9000/](http://localhost:9000/)。
- weixin平台`pnpm dev:mp` 然后打开微信开发者工具,导入本地文件夹,选择本项目的`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`, 打包后的文件在 `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="https://oss.laf.run/ukw0y1-site/pay/wepay.png" height="330" style="display:inline-block; height:330px;">
<img alt="special sponsor appwrite" src="https://oss.laf.run/ukw0y1-site/pay/alipay.jpg" height="330" style="display:inline-block; height:330px; margin-left:10px;">
</p>

28
env/.env vendored Normal file
View File

@ -0,0 +1,28 @@
VITE_APP_TITLE = 'unibest'
VITE_APP_PORT = 9000
VITE_UNI_APPID = '__UNI__D1E5001'
VITE_WX_APPID = 'wxa2abb91f64032a2b'
# h5部署网站的base配置到 manifest.config.ts 里的 h5.router.base
VITE_APP_PUBLIC_BASE=/
# 登录页面
VITE_LOGIN_URL = '/pages/login/index'
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
View 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
View 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
View File

@ -0,0 +1,4 @@
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'development'
# 是否去除console 和 debugger
VITE_DELETE_CONSOLE = false

22
eslint.config.mjs Normal file
View File

@ -0,0 +1,22 @@
import uniHelper from '@uni-helper/eslint-config'
export default uniHelper({
unocss: true,
vue: true,
markdown: false,
ignores: [
'src/uni_modules/',
'dist',
],
rules: {
'no-console': 'off',
'no-unused-vars': 'off',
'vue/no-unused-refs': 'off',
'unused-imports/no-unused-vars': 'off',
'eslint-comments/no-unlimited-disable': 'off',
'jsdoc/check-param-names': 'off',
'jsdoc/require-returns-description': 'off',
'ts/no-empty-object-type': 'off',
'no-extend-native': 'off',
},
})

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

26
index.html Normal file
View 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>

138
manifest.config.ts Normal file
View File

@ -0,0 +1,138 @@
import path from 'node:path'
import process from 'node:process'
// manifest.config.ts
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
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,
// 是否启用 ES6 转 ES5
es6: true,
minified: true,
},
usingComponents: true,
// __usePrivacyCheck__: true,
},
'mp-alipay': {
usingComponents: true,
styleIsolation: 'shared',
},
'mp-baidu': {
usingComponents: true,
},
'mp-toutiao': {
usingComponents: true,
},
'uniStatistics': {
enable: false,
},
'vueVersion': '3',
})

View File

@ -0,0 +1,13 @@
import type { GenerateServiceProps } from 'openapi-ts-request'
export default [
{
schemaPath: './src/service/app/caipu.json',
serversPath: './src/service/app/caipu',
requestLibPath: `import request from '@/utils/request';\n import { CustomRequestOptions } from '@/interceptors/request';`,
requestOptionsType: 'CustomRequestOptions',
isGenReactQuery: true,
reactQueryMode: 'vue',
isGenJavaScript: false,
},
] as GenerateServiceProps[]

159
package.json Normal file
View File

@ -0,0 +1,159 @@
{
"name": "digital_village",
"type": "commonjs",
"version": "3.0.0",
"description": "unibest - 最好的 uniapp 开发模板",
"update-time": "2025-06-21",
"author": {
"name": "feige996",
"zhName": "菲鸽",
"email": "1020103647@qq.com",
"github": "https://github.com/feige996",
"gitee": "https://gitee.com/feige996"
},
"license": "MIT",
"homepage": "https://unibest.tech",
"repository": "https://github.com/feige996/unibest",
"repository-gitee": "https://gitee.com/feige996/unibest",
"repository-old": "https://github.com/codercup/unibest",
"bugs": {
"url": "https://github.com/feige996/unibest/issues",
"url-old": "https://github.com/codercup/unibest/issues"
},
"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",
"type-check": "vue-tsc --noEmit",
"openapi-ts-request": "openapi-ts",
"prepare": "git init && husky",
"lint": "eslint",
"lint:fix": "eslint --fix"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4060620250520001",
"@dcloudio/uni-app-harmony": "3.0.0-4060620250520001",
"@dcloudio/uni-app-plus": "3.0.0-4060620250520001",
"@dcloudio/uni-components": "3.0.0-4060620250520001",
"@dcloudio/uni-h5": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-alipay": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-baidu": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-harmony": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-jd": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-lark": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-qq": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-toutiao": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-weixin": "3.0.0-4060620250520001",
"@dcloudio/uni-mp-xhs": "3.0.0-4060620250520001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4060620250520001",
"@tanstack/vue-query": "^5.62.16",
"abortcontroller-polyfill": "^1.7.8",
"dayjs": "1.11.10",
"js-cookie": "^3.0.5",
"pinia": "2.0.36",
"pinia-plugin-persistedstate": "3.2.1",
"qs": "6.5.3",
"vue": "^3.4.21",
"wot-design-uni": "^1.9.1",
"z-paging": "2.8.7"
},
"devDependencies": {
"@antfu/eslint-config": "^4.15.0",
"@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1",
"@dcloudio/types": "^3.4.8",
"@dcloudio/uni-automator": "3.0.0-4060620250520001",
"@dcloudio/uni-cli-shared": "3.0.0-4060620250520001",
"@dcloudio/uni-stacktracey": "3.0.0-4060620250520001",
"@dcloudio/vite-plugin-uni": "3.0.0-4060620250520001",
"@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/eslint-config": "^0.4.0",
"@uni-helper/uni-types": "1.0.0-alpha.3",
"@uni-helper/unocss-preset-uni": "^0.2.11",
"@uni-helper/vite-plugin-uni-components": "0.2.0",
"@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",
"@uni-ku/bundle-optimizer": "^1.3.3",
"@unocss/eslint-plugin": "^66.2.3",
"@unocss/preset-legacy-compat": "^0.59.4",
"@vue/runtime-core": "^3.4.21",
"@vue/tsconfig": "^0.1.3",
"autoprefixer": "^10.4.20",
"eslint": "^9.29.0",
"husky": "^9.1.7",
"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",
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "1.77.8",
"terser": "^5.36.0",
"typescript": "^5.7.2",
"unocss": "65.4.2",
"unplugin-auto-import": "^0.17.8",
"vite": "5.2.8",
"vite-plugin-restart": "^0.4.2",
"vue-tsc": "^2.2.10"
},
"resolutions": {
"bin-wrapper": "npm:bin-wrapper-china"
},
"lint-staged": {
"*": "eslint --fix"
}
}

23
pages.config.ts Normal file
View File

@ -0,0 +1,23 @@
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
import { tabBar } from './src/layouts/fg-tabbar/tabbarList'
export default defineUniPages({
globalStyle: {
navigationStyle: 'default',
navigationBarTitleText: 'unibest',
navigationBarBackgroundColor: '#f8f8f8',
navigationBarTextStyle: 'black',
backgroundColor: '#FFFFFF',
},
easycom: {
autoscan: true,
custom: {
'^fg-(.*)': '@/components/fg-$1/fg-$1.vue',
'^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 的配置统一在 “./src/layouts/fg-tabbar/tabbarList.ts” 文件中
tabBar: tabBar as any,
})

View File

@ -0,0 +1,13 @@
diff --git a/dist/uni-h5.es.js b/dist/uni-h5.es.js
index 7421bad97d94ad34a3d4d94292a9ee9071430662..19c6071ee4036ceb8d1cfa09030e471c002d2cda 100644
--- a/dist/uni-h5.es.js
+++ b/dist/uni-h5.es.js
@@ -23410,7 +23410,7 @@ function useShowTabBar(emit2) {
const tabBar2 = useTabBar();
const showTabBar2 = computed(() => route.meta.isTabBar && tabBar2.shown);
updateCssVar({
- "--tab-bar-height": tabBar2.height
+ "--tab-bar-height": tabBar2?.height || 0
});
return showTabBar2;
}

14262
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,2 @@
patchedDependencies:
'@dcloudio/uni-h5': patches/@dcloudio__uni-h5.patch

35
scripts/postupgrade.js Normal file
View File

@ -0,0 +1,35 @@
// # 执行 `pnpm upgrade` 后会升级 `uniapp` 相关依赖
// # 在升级完后,会自动添加很多无用依赖,这需要删除以减小依赖包体积
// # 只需要执行下面的命令即可
const { exec } = require('node: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}`)
})

61
src/App.vue Normal file
View File

@ -0,0 +1,61 @@
<script setup lang="ts">
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
import { usePageAuth } from '@/hooks/usePageAuth'
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
usePageAuth()
onLaunch(() => {
console.log('App Launch')
})
onShow(() => {
console.log('App Show')
})
onHide(() => {
console.log('App Hide')
})
</script>
<style lang="scss">
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>

83
src/api/login.ts Normal file
View File

@ -0,0 +1,83 @@
import type { ICaptcha, IUpdateInfo, IUpdatePassword, IUserInfoVo, IUserLogin } from './login.typings'
import { http } from '@/utils/http'
/**
*
*/
export interface ILoginForm {
username: string
password: string
code: string
uuid: string
}
/**
*
* @returns ICaptcha
*/
export function getCode() {
return http.get<ICaptcha>('/user/getCode')
}
/**
*
* @param loginForm
*/
export function login(loginForm: ILoginForm) {
return http.post<IUserLogin>('/user/login', loginForm)
}
/**
*
*/
export function getUserInfo() {
return http.get<IUserInfoVo>('/user/info')
}
/**
* 退
*/
export function logout() {
return http.get<void>('/user/logout')
}
/**
*
*/
export function updateInfo(data: IUpdateInfo) {
return http.post('/user/updateInfo', data)
}
/**
*
*/
export function updateUserPassword(data: IUpdatePassword) {
return http.post('/user/updatePassword', data)
}
/**
*
* @returns Promise (code)
*/
export function getWxCode() {
return new Promise<UniApp.LoginRes>((resolve, reject) => {
uni.login({
provider: 'weixin',
success: res => resolve(res),
fail: err => reject(new Error(err)),
})
})
}
/**
*
*/
/**
*
* @param params code
* @returns Promise
*/
export function wxLogin(data: { code: string }) {
return http.post<IUserLogin>('/user/wxLogin', data)
}

57
src/api/login.typings.ts Normal file
View File

@ -0,0 +1,57 @@
/**
*
*/
export interface IUserInfoVo {
id: number
username: string
avatar: string
token: string
}
/**
*
*/
export interface IUserLogin {
id: string
username: string
token: string
}
/**
*
*/
export interface ICaptcha {
captchaEnabled: boolean
uuid: string
image: string
}
/**
*
*/
export interface IUploadSuccessInfo {
fileId: number
originalName: string
fileName: string
storagePath: string
fileHash: string
fileType: string
fileBusinessType: string
fileSize: number
}
/**
*
*/
export interface IUpdateInfo {
id: number
name: string
sex: string
}
/**
*
*/
export interface IUpdatePassword {
id: number
oldPassword: string
newPassword: string
confirmPassword: string
}

0
src/components/.gitkeep Normal file
View File

View File

@ -0,0 +1,58 @@
<script lang="ts" setup>
withDefaults(
defineProps<{
leftText?: string
rightText?: string
leftArrow?: boolean
bordered?: boolean
fixed?: boolean
placeholder?: boolean
zIndex?: number
safeAreaInsetTop?: boolean
leftDisabled?: boolean
rightDisabled?: boolean
}>(),
{
leftText: '返回',
rightText: '',
leftArrow: true,
bordered: true,
fixed: false,
placeholder: true,
zIndex: 1,
safeAreaInsetTop: true,
leftDisabled: false,
rightDisabled: false,
},
)
function handleClickLeft() {
uni.navigateBack({
fail() {
uni.reLaunch({
url: '/pages/index/index',
})
},
})
}
</script>
<template>
<wd-navbar
:left-text="leftText"
:right-text="rightText"
:left-arrow="leftArrow"
:bordered="bordered"
:fixed="fixed"
:placeholder="placeholder"
:z-index="zIndex"
:safe-area-inset-top="safeAreaInsetTop"
:left-disabled="leftDisabled"
:right-disabled="rightDisabled"
@click-left="handleClickLeft"
>
<template #title>
<slot />
</template>
</wd-navbar>
</template>

31
src/env.d.ts vendored Normal file
View File

@ -0,0 +1,31 @@
/// <reference types="vite/client" />
/// <reference types="vite-svg-loader" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
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
View File

50
src/hooks/usePageAuth.ts Normal file
View File

@ -0,0 +1,50 @@
import { onLoad } from '@dcloudio/uni-app'
import { useUserStore } from '@/store'
import { needLoginPages as _needLoginPages, getNeedLoginPages } from '@/utils'
const loginRoute = import.meta.env.VITE_LOGIN_URL
const isDev = import.meta.env.DEV
function isLogined() {
const userStore = useUserStore()
return !!userStore.userInfo.username
}
// 检查当前页面是否需要登录
export function usePageAuth() {
onLoad((options) => {
// 获取当前页面路径
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const currentPath = `/${currentPage.route}`
// 获取需要登录的页面列表
let needLoginPages: string[] = []
if (isDev) {
needLoginPages = getNeedLoginPages()
}
else {
needLoginPages = _needLoginPages
}
// 检查当前页面是否需要登录
const isNeedLogin = needLoginPages.includes(currentPath)
if (!isNeedLogin) {
return
}
const hasLogin = isLogined()
if (hasLogin) {
return true
}
// 构建重定向URL
const queryString = Object.entries(options || {})
.map(([key, value]) => `${key}=${encodeURIComponent(String(value))}`)
.join('&')
const currentFullPath = queryString ? `${currentPath}?${queryString}` : currentPath
const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(currentFullPath)}`
// 重定向到登录页
uni.redirectTo({ url: redirectRoute })
})
}

44
src/hooks/useRequest.ts Normal file
View File

@ -0,0 +1,44 @@
import type { UnwrapRef } from 'vue'
interface 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 }
}

160
src/hooks/useUpload.ts Normal file
View File

@ -0,0 +1,160 @@
import { ref } from 'vue'
import { getEnvBaseUploadUrl } from '@/utils'
const VITE_UPLOAD_BASEURL = `${getEnvBaseUploadUrl()}`
type TfileType = 'image' | 'file'
type TImage = 'png' | 'jpg' | 'jpeg' | 'webp' | '*'
type TFile = 'doc' | 'docx' | 'ppt' | 'zip' | 'xls' | 'xlsx' | 'txt' | TImage
interface TOptions<T extends TfileType> {
formData?: Record<string, any>
maxSize?: number
accept?: T extends 'image' ? TImage[] : TFile[]
fileType?: T
success?: (params: any) => void
error?: (err: any) => void
}
export default function useUpload<T extends TfileType>(options: TOptions<T> = {} as TOptions<T>) {
const {
formData = {},
maxSize = 5 * 1024 * 1024,
accept = ['*'],
fileType = 'image',
success,
error: onError,
} = options
const loading = ref(false)
const error = ref<Error | null>(null)
const data = ref<any>(null)
const handleFileChoose = ({ tempFilePath, size }: { tempFilePath: string, size: number }) => {
if (size > maxSize) {
uni.showToast({
title: `文件大小不能超过 ${maxSize / 1024 / 1024}MB`,
icon: 'none',
})
return
}
// const fileExtension = file?.tempFiles?.name?.split('.').pop()?.toLowerCase()
// const isTypeValid = accept.some((type) => type === '*' || type.toLowerCase() === fileExtension)
// if (!isTypeValid) {
// uni.showToast({
// title: `仅支持 ${accept.join(', ')} 格式的文件`,
// icon: 'none',
// })
// return
// }
loading.value = true
uploadFile({
tempFilePath,
formData,
onSuccess: (res) => {
const { data: _data } = JSON.parse(res)
data.value = _data
// console.log('上传成功', res)
success?.(_data)
},
onError: (err) => {
error.value = err
onError?.(err)
},
onComplete: () => {
loading.value = false
},
})
}
const run = () => {
// 微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
// 微信小程序在2023年10月17日之后使用本API需要配置隐私协议
const chooseFileOptions = {
count: 1,
success: (res: any) => {
console.log('File selected successfully:', res)
// 小程序中res:{errMsg: "chooseImage:ok", tempFiles: [{fileType: "image", size: 48976, tempFilePath: "http://tmp/5iG1WpIxTaJf3ece38692a337dc06df7eb69ecb49c6b.jpeg"}]}
// h5中res:{errMsg: "chooseImage:ok", tempFilePaths: "blob:http://localhost:9000/f74ab6b8-a14d-4cb6-a10d-fcf4511a0de5", tempFiles: [File]}
// h5的File有以下字段{name: "girl.jpeg", size: 48976, type: "image/jpeg"}
// App中res:{errMsg: "chooseImage:ok", tempFilePaths: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", tempFiles: [File]}
// App的File有以下字段{path: "file:///Users/feige/xxx/gallery/1522437259-compressed-IMG_0006.jpg", size: 48976}
let tempFilePath = ''
let size = 0
// #ifdef MP-WEIXIN
tempFilePath = res.tempFiles[0].tempFilePath
size = res.tempFiles[0].size
// #endif
// #ifndef MP-WEIXIN
tempFilePath = res.tempFilePaths[0]
size = res.tempFiles[0].size
// #endif
handleFileChoose({ tempFilePath, size })
},
fail: (err: any) => {
console.error('File selection failed:', err)
error.value = err
onError?.(err)
},
}
if (fileType === 'image') {
// #ifdef MP-WEIXIN
uni.chooseMedia({
...chooseFileOptions,
mediaType: ['image'],
})
// #endif
// #ifndef MP-WEIXIN
uni.chooseImage(chooseFileOptions)
// #endif
}
else {
uni.chooseFile({
...chooseFileOptions,
type: 'all',
})
}
}
return { loading, error, data, run }
}
async function uploadFile({
tempFilePath,
formData,
onSuccess,
onError,
onComplete,
}: {
tempFilePath: string
formData: Record<string, any>
onSuccess: (data: any) => void
onError: (err: any) => void
onComplete: () => void
}) {
uni.uploadFile({
url: VITE_UPLOAD_BASEURL,
filePath: tempFilePath,
name: 'file',
formData,
success: (uploadFileRes) => {
try {
const data = uploadFileRes.data
onSuccess(data)
}
catch (err) {
onError(err)
}
},
fail: (err) => {
console.error('Upload failed:', err)
onError(err)
},
complete: onComplete,
})
}

View File

@ -0,0 +1,3 @@
export { prototypeInterceptor } from './prototype'
export { requestInterceptor } from './request'
export { routeInterceptor } from './route'

View File

@ -0,0 +1,14 @@
export const prototypeInterceptor = {
install() {
// 解决低版本手机不识别 array.at() 导致运行报错的问题
if (typeof Array.prototype.at !== 'function') {
Array.prototype.at = function (index: number) {
if (index < 0)
return this[this.length + index]
if (index >= this.length)
return undefined
return this[index]
}
}
},
}

View File

@ -0,0 +1,70 @@
import qs from 'qs'
import { useUserStore } from '@/store'
import { getEnvBaseUrl } from '@/utils'
import { platform } from '@/utils/platform'
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)
},
}

65
src/interceptors/route.ts Normal file
View File

@ -0,0 +1,65 @@
/**
* by on 2024-03-06
*
*
* 便使
*/
import { useUserStore } from '@/store'
import { needLoginPages as _needLoginPages, getLastPage, getNeedLoginPages } from '@/utils'
// TODO Check
const loginRoute = import.meta.env.VITE_LOGIN_URL
function isLogined() {
const userStore = useUserStore()
return !!userStore.userInfo.username
}
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
View File

@ -0,0 +1,17 @@
<script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni'
const themeVars: ConfigProviderThemeVars = {
// colorTheme: 'red',
// buttonPrimaryBgColor: '#07c160',
// buttonPrimaryColor: '#07c160',
}
</script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

17
src/layouts/demo.vue Normal file
View File

@ -0,0 +1,17 @@
<script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni'
const themeVars: ConfigProviderThemeVars = {
// colorTheme: 'red',
// buttonPrimaryBgColor: '#07c160',
// buttonPrimaryColor: '#07c160',
}
</script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

View File

@ -0,0 +1,67 @@
<script setup lang="ts">
import { tabbarStore } from './tabbar'
// 'i-carbon-code',
import { tabbarList as _tabBarList, cacheTabbarEnable, selectedTabbarStrategy } from './tabbarList'
// @ts-expect-error
const customTabbarEnable = selectedTabbarStrategy === 1 || selectedTabbarStrategy === 2
/** tabbarList 里面的 path 从 pages.config.ts 得到 */
const tabbarList = _tabBarList.map(item => ({ ...item, path: `/${item.pagePath}` }))
function selectTabBar({ value: index }: { value: number }) {
const url = tabbarList[index].path
tabbarStore.setCurIdx(index)
if (cacheTabbarEnable) {
uni.switchTab({ url })
}
else {
uni.navigateTo({ url })
}
}
onLoad(() => {
// tabBar 2 tabBar
// @ts-expect-error
const hideRedundantTabbarEnable = selectedTabbarStrategy === 1
hideRedundantTabbarEnable
&& uni.hideTabBar({
fail(err) {
console.log('hideTabBar fail: ', err)
},
success(res) {
console.log('hideTabBar success: ', res)
},
})
})
</script>
<template>
<wd-tabbar
v-if="customTabbarEnable"
v-model="tabbarStore.curIdx"
bordered
safeareainsetbottom
placeholder
fixed
@change="selectTabBar"
>
<block v-for="(item, idx) in tabbarList" :key="item.path">
<wd-tabbar-item v-if="item.iconType === 'uiLib'" :title="item.text" :icon="item.icon" />
<wd-tabbar-item
v-else-if="item.iconType === 'unocss' || item.iconType === 'iconfont'"
:title="item.text"
>
<template #icon>
<view
h-40rpx
w-40rpx
:class="[item.icon, idx === tabbarStore.curIdx ? 'is-active' : 'is-inactive']"
/>
</template>
</wd-tabbar-item>
<wd-tabbar-item v-else-if="item.iconType === 'local'" :title="item.text">
<template #icon>
<image :src="item.icon" h-40rpx w-40rpx />
</template>
</wd-tabbar-item>
</block>
</wd-tabbar>
</template>

View File

@ -0,0 +1,16 @@
# tabbar 说明
tabbar 分为4种情况
- 完全原生tabbar使用 switchTab 切换 tabbartabbar页面有缓存。
- 优势原生自带的tabbar最先渲染有缓存。
- 劣势只能使用2组图片来切换选中和非选中状态修改颜色只能重新换图片或者用iconfont
- 半自定义tabbar使用 switchTab 切换 tabbartabbar页面有缓存。使用了第三方UI库的 tabbar 组件,并隐藏了原生 tabbar 的显示。
- 优势:可以随意配置自己想要的 svg icon切换字体颜色方便。有缓存。可以实现各种花里胡哨的动效等。
- 劣势首次点击tababr会闪烁。
- 全自定义tabbar使用 navigateTo 切换tabbartabbar页面无缓存。使用了第三方UI库的 tabbar 组件。
- 优势:可以随意配置自己想要的 svg icon切换字体颜色方便。可以实现各种花里胡哨的动效等。
- 劣势首次点击tababr会闪烁无缓存。
- 无tabbar只有一个页面入口底部无tabbar显示常用语临时活动页。
> 注意:花里胡哨的效果需要自己实现,本模版不提供。

View File

@ -0,0 +1,11 @@
/**
* tabbar storageSync tabbar
* 使reactive简单状态 pinia
*/
export const tabbarStore = reactive({
curIdx: uni.getStorageSync('app-tabbar-index') || 0,
setCurIdx(idx: number) {
this.curIdx = idx
uni.setStorageSync('app-tabbar-index', idx)
},
})

View File

@ -0,0 +1,65 @@
/**
* tabbar tabbar.md
* 0: 'NATIVE_TABBAR'
* 2: 'FULL_CUSTOM_TABBAR'
* 1: 'HALF_CUSTOM_TABBAR'
* 3: 'NO_TABBAR'
*
* pages.json
*/
// TODO通过这里切换使用tabbar的策略
export const selectedTabbarStrategy = 0
// 0 和 1 时需要tabbar缓存
export const cacheTabbarEnable = selectedTabbarStrategy < 2
// selectedTabbarStrategy==0 时,需要填 iconPath 和 selectedIconPath
// selectedTabbarStrategy==1 or 2 时,需要填 icon 和 iconType
// selectedTabbarStrategy==3 时tabbarList 不生效
export const tabbarList = [
{
iconPath: 'static/tabbar/home.png',
selectedIconPath: 'static/tabbar/homeHL.png',
pagePath: 'pages/index/index',
text: '首页',
icon: 'home',
iconType: 'uiLib',
},
{
iconPath: 'static/tabbar/example.png',
selectedIconPath: 'static/tabbar/exampleHL.png',
pagePath: 'pages/about/about',
text: '关于',
icon: 'i-carbon-code',
// 注意 unocss 的图标需要在 页面上引入一下,或者配置到 unocss.config.ts 的 safelist 中
iconType: 'unocss',
},
// {
// pagePath: 'pages/my/index',
// text: '我的',
// icon: '/static/logo.svg',
// iconType: 'local',
// },
// {
// pagePath: 'pages/mine/index',
// text: '我的',
// icon: 'iconfont icon-my',
// iconType: 'iconfont',
// },
]
const _tabbar = {
color: '#999999',
selectedColor: '#018d71',
backgroundColor: '#F8F8F8',
borderStyle: 'black',
height: '50px',
fontSize: '10px',
iconWidth: '24px',
spacing: '3px',
list: tabbarList,
}
// 0和1 需要显示底部的tabbar的各种配置以利用缓存
export const tabBar = cacheTabbarEnable ? _tabbar : undefined

19
src/layouts/tabbar.vue Normal file
View File

@ -0,0 +1,19 @@
<script lang="ts" setup>
import type { ConfigProviderThemeVars } from 'wot-design-uni'
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
const themeVars: ConfigProviderThemeVars = {
// colorTheme: 'red',
// buttonPrimaryBgColor: '#07c160',
// buttonPrimaryColor: '#07c160',
}
</script>
<template>
<wd-config-provider :theme-vars="themeVars">
<slot />
<FgTabbar />
<wd-toast />
<wd-message-box />
</wd-config-provider>
</template>

21
src/main.ts Normal file
View File

@ -0,0 +1,21 @@
import { VueQueryPlugin } from '@tanstack/vue-query'
import { createSSRApp } from 'vue'
import App from './App.vue'
import { prototypeInterceptor, requestInterceptor, routeInterceptor } from './interceptors'
import store from './store'
import '@/style/index.scss'
import 'virtual:uno.css'
export function createApp() {
const app = createSSRApp(App)
app.use(store)
app.use(routeInterceptor)
app.use(requestInterceptor)
app.use(prototypeInterceptor)
app.use(VueQueryPlugin)
return {
app,
}
}

113
src/manifest.json Normal file
View File

@ -0,0 +1,113 @@
{
"name": "unibest",
"appid": "__UNI__D1E5001",
"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,
"es6": true,
"minified": true
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true,
"styleIsolation": "shared"
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "3",
"h5": {
"router": {
"base": "/"
}
}
}

View File

@ -0,0 +1,27 @@
<route lang="json5" type="page">
{
style: {
navigationStyle: 'default',
navigationBarTitleText: '分包页面 标题',
},
}
</route>
<script lang="ts" setup>
// code here
</script>
<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>
<style lang="scss" scoped>
//
</style>

65
src/pages.json Normal file
View File

@ -0,0 +1,65 @@
{
"globalStyle": {
"navigationStyle": "default",
"navigationBarTitleText": "unibest",
"navigationBarBackgroundColor": "#f8f8f8",
"navigationBarTextStyle": "black",
"backgroundColor": "#FFFFFF"
},
"easycom": {
"autoscan": true,
"custom": {
"^fg-(.*)": "@/components/fg-$1/fg-$1.vue",
"^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": "首页",
"icon": "home",
"iconType": "uiLib"
},
{
"iconPath": "static/tabbar/example.png",
"selectedIconPath": "static/tabbar/exampleHL.png",
"pagePath": "pages/about/about",
"text": "关于",
"icon": "i-carbon-code",
"iconType": "unocss"
}
]
},
"pages": [
{
"path": "pages/index/index",
"type": "home",
"layout": "tabbar",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/about/about",
"type": "page",
"layout": "tabbar",
"style": {
"navigationBarTitleText": "关于"
}
}
],
"subPackages": []
}

46
src/pages/about/about.vue Normal file
View File

@ -0,0 +1,46 @@
<route lang="json5">
{
layout: 'tabbar',
style: {
navigationBarTitleText: '关于',
},
}
</route>
<script lang="ts" setup>
import RequestComp from './components/request.vue'
import UploadComp from './components/upload.vue'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
// vue .ts
// const testOxlint = (name: string) => {
// console.log('oxlint')
// }
// testOxlint('oxlint')
console.log('about')
</script>
<template>
<view>
<view class="mt-8 text-center text-3xl">
鸽友们好我是
<text class="text-red-500">
菲鸽
</text>
</view>
<RequestComp />
<UploadComp />
</view>
</template>
<style lang="scss" scoped>
.test-css {
// 16rpx=>0.5rem
padding-bottom: 16rpx;
// mt-4=>1rem=>16px;
margin-top: 16px;
text-align: center;
}
</style>

View File

@ -0,0 +1,84 @@
<route lang="json5">
{
layout: 'demo',
style: {
navigationBarTitleText: '请求',
},
}
</route>
<script lang="ts" setup>
import type { IFooItem } from '@/service/index/foo'
import { getFooAPI } 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'] } }))
function reset() {
data.value = initialData
}
</script>
<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 class="my-6" @click="run">
发送请求
</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" class="my-6" :disabled="!data" @click="reset">
重置数据
</wd-button>
</view>
</template>

View File

@ -0,0 +1,38 @@
<route lang="json5" type="page">
{
layout: 'default',
style: {
navigationBarTitleText: '上传-状态一体化',
},
}
</route>
<script lang="ts" setup>
const { loading, data, run } = useUpload()
</script>
<template>
<view class="p-4 text-center">
<wd-button @click="run">
选择图片并上传
</wd-button>
<view v-if="loading" class="h-10 text-blue">
上传...
</view>
<template v-else>
<view class="m-2">
上传后返回的接口数据
</view>
<view class="m-2">
{{ data }}
</view>
<view v-if="data" class="h-80 w-full">
<image :src="data.url" mode="scaleToFill" />
</view>
</template>
</view>
</template>
<style lang="scss" scoped>
//
</style>

82
src/pages/index/index.vue Normal file
View File

@ -0,0 +1,82 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page推荐使用json5更强大且允许注释 -->
<route lang="json5" type="home">
{
layout: 'tabbar',
style: {
// 'custom' 'default'
navigationStyle: 'custom',
navigationBarTitleText: '首页',
},
}
</route>
<script lang="ts" setup>
import PLATFORM from '@/utils/platform'
defineOptions({
name: 'Home',
})
//
let safeAreaInsets
let systemInfo
// #ifdef MP-WEIXIN
// 使API
systemInfo = uni.getWindowInfo()
safeAreaInsets = systemInfo.safeArea
? {
top: systemInfo.safeArea.top,
right: systemInfo.windowWidth - systemInfo.safeArea.right,
bottom: systemInfo.windowHeight - systemInfo.safeArea.bottom,
left: systemInfo.safeArea.left,
}
: null
// #endif
// #ifndef MP-WEIXIN
// 使uni API
systemInfo = uni.getSystemInfoSync()
safeAreaInsets = systemInfo.safeAreaInsets
// #endif
const author = ref('菲鸽')
const description = ref(
'unibest 是一个集成了多种工具和技术的 uniapp 开发模板,由 uniapp + Vue3 + Ts + Vite5 + UnoCss + VSCode 构建,模板具有代码提示、自动格式化、统一配置、代码片段等功能,并内置了许多常用的基本组件和基本功能,让你编写 uniapp 拥有 best 体验。',
)
// uni API
onLoad(() => {
console.log('项目作者:', author.value)
})
console.log('index')
</script>
<template>
<view class="bg-white px-4 pt-2" :style="{ marginTop: `${safeAreaInsets?.top}px` }">
<view class="mt-12">
<image src="/static/logo.svg" alt="" class="mx-auto block h-28 w-28" />
</view>
<view class="mt-4 text-center text-4xl text-[#d14328]">
unibest
</view>
<view class="mb-8 mt-2 text-center text-2xl">
最好用的 uniapp 开发模板
</view>
<view class="m-auto mb-2 max-w-100 text-justify indent text-4">
{{ description }}
</view>
<view class="mt-8 text-center">
当前平台是
<text class="text-green-500">
{{ PLATFORM.platform }}
</text>
</view>
<view class="mt-4 text-center">
模板分支是
<text class="text-green-500">
base
</text>
</view>
</view>
</template>

1158
src/service/app/caipu.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
/* eslint-disable */
// @ts-ignore
export * from './types';
export * from './yanxi';
export * from './yanxi.vuequery';

View File

@ -0,0 +1,64 @@
/* eslint-disable */
// @ts-ignore
export type getChefDetailParams = {
id?: string;
/** 年月 */
month?: string;
};
export type getChefListParams = {
page?: number;
limit?: number;
keyword?: string;
};
export type getDishesCategoryParams = {
/** 厨师/酒店id */
server_user_id?: number;
/** 第几餐 */
index?: number;
};
export type getDishesDetailParams = {
id?: number;
};
export type getDishesListParams = {
page?: number;
limit?: number;
/** 分类id */
category_id?: number;
/** 搜索词 */
keyword?: string;
/** 第几餐 */
index?: number;
/** 厨师/酒店id */
server_user_id?: number;
/** 菜品类型1单品2套餐 */
type?: number;
};
export type getHotelDetailParams = {
id?: number;
};
export type getHotelListParams = {
page?: number;
limit?: number;
keyword?: string;
};
export type getHotelScheduleParams = {
id?: number;
month?: string;
};
export type getOrderDetailParams = {
order_id?: number;
};
export type getOrderListParams = {
page?: number;
limit?: number;
};

View File

@ -0,0 +1,376 @@
/* eslint-disable */
// @ts-ignore
import request from '@/utils/request';
import { CustomRequestOptions } from '@/interceptors/request';
import * as API from './types';
/** 添加到购物车 POST /api/banquet/cart/add https://app.apifox.com/web/project/6830277/apis/api-334023073-run */
export async function postCartAdd({
body,
options,
}: {
body: {
index: number;
dishes_id: number;
/** 数量 */
number: number;
/** 厨师/酒店id */
server_user_id: number;
/** 是否立即购买1是0否 */
buy_now: number;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 删除购物车记录 POST /api/banquet/cart/delete https://app.apifox.com/web/project/6830277/apis/api-334077833-run */
export async function postCartOpenApiDelete({
body,
options,
}: {
body: {
id: string;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/cart/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 编辑购物车信息 POST /api/banquet/cart/edit https://app.apifox.com/web/project/6830277/apis/api-334124014-run */
export async function postCartEdit({
body,
options,
}: {
body: {
/** 厨师/酒店id */
server_user_id: number;
/** 第几餐 */
index: number;
/** 宴席日期 */
date: string;
/** 宴席时段 */
time: string;
/** 桌数 */
number: number;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/cart/edit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 厨师详情 GET /api/banquet/chef/detail https://app.apifox.com/web/project/6830277/apis/api-333728717-run */
export async function getChefDetail({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getChefDetailParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/chef/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 厨师列表 GET /api/banquet/chef/list https://app.apifox.com/web/project/6830277/apis/api-333667936-run */
export async function getChefList({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getChefListParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/chef/list', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 宴席类型列表 GET /api/banquet/dishes/banquetType https://app.apifox.com/web/project/6830277/apis/api-334185705-run */
export async function getDishesBanquetType({
options,
}: {
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/dishes/banquetType', {
method: 'GET',
...(options || {}),
});
}
/** 菜品分类 GET /api/banquet/dishes/category https://app.apifox.com/web/project/6830277/apis/api-333741485-run */
export async function getDishesCategory({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesCategoryParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/dishes/category', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 菜品详情 GET /api/banquet/dishes/detail https://app.apifox.com/web/project/6830277/apis/api-335503840-run */
export async function getDishesDetail({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesDetailParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/dishes/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 菜品列表 GET /api/banquet/dishes/list https://app.apifox.com/web/project/6830277/apis/api-333742056-run */
export async function getDishesList({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesListParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/dishes/list', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 酒店详情 GET /api/banquet/hotel/detail https://app.apifox.com/web/project/6830277/apis/api-335865859-run */
export async function getHotelDetail({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelDetailParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/hotel/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 酒店列表 GET /api/banquet/hotel/list https://app.apifox.com/web/project/6830277/apis/api-335865679-run */
export async function getHotelList({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelListParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/hotel/list', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 酒店日程 GET /api/banquet/hotel/schedule https://app.apifox.com/web/project/6830277/apis/api-335866010-run */
export async function getHotelSchedule({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelScheduleParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/hotel/schedule', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 取消订单 POST /api/banquet/order/cancel https://app.apifox.com/web/project/6830277/apis/api-334369097-run */
export async function postOrderCancel({
body,
options,
}: {
body: {
/** 订单id */
order_id: number;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/cancel', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 校验订单信息 POST /api/banquet/order/check https://app.apifox.com/web/project/6830277/apis/api-334089060-run */
export async function postOrderCheck({
body,
options,
}: {
body: {
/** 购物车id */
cart_ids: number[];
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 提交订单信息 POST /api/banquet/order/createOrder https://app.apifox.com/web/project/6830277/apis/api-334145352-run */
export async function postOrderCreateOrder({
body,
options,
}: {
body: {
/** 购物车id酒店必填 */
cart_ids: number[];
/** 客户姓名 */
customer_name: string;
/** 手机号 */
phone: string;
/** 地址 */
address: string;
/** 备注 */
remark: string;
/** 宴席类型 */
banquet_type: number;
/** 预约类型1后付费2订金 */
reservation_type: number;
/** 厨师/酒店id */
server_user_id: number;
/** 桌数(酒店必填) */
table_number: number;
/** 日期(酒店必填) */
banquet_date: string;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/createOrder', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 订单详情 GET /api/banquet/order/detail https://app.apifox.com/web/project/6830277/apis/api-334335775-run */
export async function getOrderDetail({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getOrderDetailParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/detail', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 订单列表 GET /api/banquet/order/list https://app.apifox.com/web/project/6830277/apis/api-336320486-run */
export async function getOrderList({
params,
options,
}: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getOrderListParams;
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/list', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 订单发起支付 POST /api/banquet/order/pay https://app.apifox.com/web/project/6830277/apis/api-334619375-run */
export async function postOrderPay({
body,
options,
}: {
body: {
/** 订单id */
order_id: number;
};
options?: CustomRequestOptions;
}) {
return request<Record<string, unknown>>('/api/banquet/order/pay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}

View File

@ -0,0 +1,301 @@
/* 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 './yanxi';
import * as API from './types';
/** 添加到购物车 POST /api/banquet/cart/add https://app.apifox.com/web/project/6830277/apis/api-334023073-run */
export function usePostCartAddMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postCartAdd,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 删除购物车记录 POST /api/banquet/cart/delete https://app.apifox.com/web/project/6830277/apis/api-334077833-run */
export function usePostCartOpenApiDeleteMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postCartOpenApiDelete,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 编辑购物车信息 POST /api/banquet/cart/edit https://app.apifox.com/web/project/6830277/apis/api-334124014-run */
export function usePostCartEditMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postCartEdit,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 厨师详情 GET /api/banquet/chef/detail https://app.apifox.com/web/project/6830277/apis/api-333728717-run */
export function getChefDetailQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getChefDetailParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getChefDetail(queryKey[1] as typeof options);
},
queryKey: ['getChefDetail', options],
});
}
/** 厨师列表 GET /api/banquet/chef/list https://app.apifox.com/web/project/6830277/apis/api-333667936-run */
export function getChefListQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getChefListParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getChefList(queryKey[1] as typeof options);
},
queryKey: ['getChefList', options],
});
}
/** 宴席类型列表 GET /api/banquet/dishes/banquetType https://app.apifox.com/web/project/6830277/apis/api-334185705-run */
export function getDishesBanquetTypeQueryOptions(options: {
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getDishesBanquetType(queryKey[1] as typeof options);
},
queryKey: ['getDishesBanquetType', options],
});
}
/** 菜品分类 GET /api/banquet/dishes/category https://app.apifox.com/web/project/6830277/apis/api-333741485-run */
export function getDishesCategoryQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesCategoryParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getDishesCategory(queryKey[1] as typeof options);
},
queryKey: ['getDishesCategory', options],
});
}
/** 菜品详情 GET /api/banquet/dishes/detail https://app.apifox.com/web/project/6830277/apis/api-335503840-run */
export function getDishesDetailQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesDetailParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getDishesDetail(queryKey[1] as typeof options);
},
queryKey: ['getDishesDetail', options],
});
}
/** 菜品列表 GET /api/banquet/dishes/list https://app.apifox.com/web/project/6830277/apis/api-333742056-run */
export function getDishesListQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getDishesListParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getDishesList(queryKey[1] as typeof options);
},
queryKey: ['getDishesList', options],
});
}
/** 酒店详情 GET /api/banquet/hotel/detail https://app.apifox.com/web/project/6830277/apis/api-335865859-run */
export function getHotelDetailQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelDetailParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getHotelDetail(queryKey[1] as typeof options);
},
queryKey: ['getHotelDetail', options],
});
}
/** 酒店列表 GET /api/banquet/hotel/list https://app.apifox.com/web/project/6830277/apis/api-335865679-run */
export function getHotelListQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelListParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getHotelList(queryKey[1] as typeof options);
},
queryKey: ['getHotelList', options],
});
}
/** 酒店日程 GET /api/banquet/hotel/schedule https://app.apifox.com/web/project/6830277/apis/api-335866010-run */
export function getHotelScheduleQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getHotelScheduleParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getHotelSchedule(queryKey[1] as typeof options);
},
queryKey: ['getHotelSchedule', options],
});
}
/** 取消订单 POST /api/banquet/order/cancel https://app.apifox.com/web/project/6830277/apis/api-334369097-run */
export function usePostOrderCancelMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postOrderCancel,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 校验订单信息 POST /api/banquet/order/check https://app.apifox.com/web/project/6830277/apis/api-334089060-run */
export function usePostOrderCheckMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postOrderCheck,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 提交订单信息 POST /api/banquet/order/createOrder https://app.apifox.com/web/project/6830277/apis/api-334145352-run */
export function usePostOrderCreateOrderMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postOrderCreateOrder,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}
/** 订单详情 GET /api/banquet/order/detail https://app.apifox.com/web/project/6830277/apis/api-334335775-run */
export function getOrderDetailQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getOrderDetailParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getOrderDetail(queryKey[1] as typeof options);
},
queryKey: ['getOrderDetail', options],
});
}
/** 订单列表 GET /api/banquet/order/list https://app.apifox.com/web/project/6830277/apis/api-336320486-run */
export function getOrderListQueryOptions(options: {
// 叠加生成的Param类型 (非body参数openapi默认没有生成对象)
params: API.getOrderListParams;
options?: CustomRequestOptions;
}) {
return queryOptions({
queryFn: async ({ queryKey }) => {
return apis.getOrderList(queryKey[1] as typeof options);
},
queryKey: ['getOrderList', options],
});
}
/** 订单发起支付 POST /api/banquet/order/pay https://app.apifox.com/web/project/6830277/apis/api-334619375-run */
export function usePostOrderPayMutation(options?: {
onSuccess?: (value?: Record<string, unknown>) => void;
onError?: (error?: DefaultError) => void;
}) {
const { onSuccess, onError } = options || {};
const response = useMutation({
mutationFn: apis.postOrderPay,
onSuccess(data: Record<string, unknown>) {
onSuccess?.(data);
},
onError(error) {
onError?.(error);
},
});
return response;
}

View 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
View 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
View 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 || {}),
});
}

View 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
View 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 || {}),
});
}

View 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
View 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
View 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 || {}),
});
}

View 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],
});
}

28
src/service/index/foo.ts Normal file
View File

@ -0,0 +1,28 @@
import { http } from '@/utils/http'
export interface IFooItem {
id: string
name: string
}
/** GET 请求 */
export function getFooAPI(name: string) {
return http.get<IFooItem>('/foo', { name })
}
/** GET 请求;支持 传递 header 的范例 */
export function getFooAPI2(name: string) {
return http.get<IFooItem>('/foo', { name }, { 'Content-Type-100': '100' })
}
/** POST 请求 */
export function postFooAPI(name: string) {
return http.post<IFooItem>('/foo', { name })
}
/** POST 请求;需要传递 query 参数的范例微信小程序经常有同时需要query参数和body参数的场景 */
export function postFooAPI2(name: string) {
return http.post<IFooItem>('/foo', { name })
}
/** POST 请求;支持 传递 header 的范例 */
export function postFooAPI3(name: string) {
return http.post<IFooItem>('/foo', { name }, { name }, { 'Content-Type-100': '100' })
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

33
src/static/logo.svg Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/static/tabbar/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Some files were not shown because too many files have changed in this diff Show More