Browse Source

add project

master
juncheng.li 1 year ago
commit
df73fba48d
  1. 71
      .commitlintrc.js
  2. 6
      .env.development
  3. 2
      .env.production
  4. 2
      .eslintignore
  5. 49
      .eslintrc.json
  6. 31
      .gitignore
  7. 9
      .prettierrc.js
  8. 21
      LICENSE
  9. 260
      README.md
  10. 25
      index.html
  11. 99
      package.json
  12. 5971
      pnpm-lock.yaml
  13. 16
      src/App.vue
  14. 94
      src/api/http.ts
  15. 1
      src/api/index.ts
  16. 24
      src/api/modules/user.ts
  17. 58
      src/components/hello/index.vue
  18. 17
      src/components/unocss/index.vue
  19. 13
      src/env.d.ts
  20. 38
      src/main.ts
  21. 82
      src/manifest.json
  22. 22
      src/pages.json
  23. 40
      src/pages/axios/index.vue
  24. 51
      src/pages/index/index.vue
  25. 60
      src/pages/pinia/index.vue
  26. 95
      src/pages/unocss/index.vue
  27. 42
      src/pages/uview/index.vue
  28. BIN
      src/static/logo.png
  29. 1
      src/store/index.ts
  30. 23
      src/store/modules/countStore.ts
  31. 2
      src/styles/vars/_base.less
  32. 2
      src/styles/vars/_base.scss
  33. 77
      src/uni.scss
  34. 140
      src/utils/common.ts
  35. 52
      src/utils/dateTime.ts
  36. 19
      src/utils/http.ts
  37. 31
      src/utils/utils.ts
  38. 762
      src/utils/validator.ts
  39. 26
      tsconfig.json
  40. 30
      unocss.config.ts
  41. 47
      vite.config.ts
  42. 7
      vitest.config.ts
  43. 24
      y/.gitignore
  44. 13
      y/index.html
  45. 15
      y/package.json
  46. 1
      y/public/vite.svg
  47. 9
      y/src/counter.ts
  48. 24
      y/src/main.ts
  49. 97
      y/src/style.css
  50. 1
      y/src/typescript.svg
  51. 1
      y/src/vite-env.d.ts
  52. 23
      y/tsconfig.json

71
.commitlintrc.js

@ -0,0 +1,71 @@
// @ts-check
/** @type {import('cz-git').UserConfig} */
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
[
'feat',
'fix',
'perf',
'style',
'docs',
'test',
'refactor',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release'
]
]
},
prompt: {
// 中英文对照版
// messages: {
// type: '选择你要提交的类型 :',
// scope: '选择一个提交范围 (可选):',
// customScope: '请输入自定义的提交范围 :',
// subject: '填写简短精炼的变更描述 :\n',
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
// customFooterPrefixs: '输入自定义issue前缀 :',
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
// confirmCommit: '是否提交或修改commit ?'
// },
// types: [
// { value: 'feat', name: 'feat: 新增功能' },
// { value: 'fix', name: 'fix: 修复缺陷' },
// { value: 'docs', name: 'docs: 文档变更' },
// { value: 'style', name: 'style: 代码格式' },
// { value: 'refactor', name: 'refactor: 代码重构' },
// { value: 'perf', name: 'perf: 性能优化' },
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
// {
// value: 'build',
// name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)'
// },
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
// { value: 'revert', name: 'revert: 回滚 commit' },
// {
// value: 'chore',
// name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)'
// },
// { value: 'wip', name: 'wip: 正在开发中' },
// { value: 'workflow', name: 'workflow: 工作流程改进' },
// { value: 'types', name: 'types: 类型定义文件修改' }
// ]
}
}

6
.env.development

@ -0,0 +1,6 @@
VITE_BASE_URL=http://192.168.0.168:8090
VITE_BASE_URL_IMAGE=http://192.168.0.168:8080
# VITE_BASE_URL=http://192.168.0.142:8090
# VITE_BASE_URL_IMAGE=http://192.168.0.142:8090
# VITE_BASE_URL=http://dev.ccwin-in.com:23111/app
# VITE_BASE_URL_IMAGE=http://dev.ccwin-in.com:23111

2
.env.production

@ -0,0 +1,2 @@
VITE_BASE_URL=http://dev.ccwin-in.com:23111/app
VITE_BASE_URL_IMAGE=http://dev.ccwin-in.com:23111

2
.eslintignore

@ -0,0 +1,2 @@
dist
*.nvue

49
.eslintrc.json

@ -0,0 +1,49 @@
{
"parser": "vue-eslint-parser",
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"parserOptions": {
"ecmaVersion": 2021,
"parser": "@typescript-eslint/parser",
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"extends": [
"airbnb-base",
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:vue/vue3-essential",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["vue", "@typescript-eslint", "todo-ddl"],
"rules": {
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"import/extensions": "off",
"quotes": ["warn", "single"],
"semi": ["warn", "never"],
"import/no-unresolved": "off",
"todo-ddl/diy": "warn",
"import/prefer-default-export": "off",
"no-param-reassign": "warn",
"import/no-extraneous-dependencies": "off",
"max-len": "warn",
"no-restricted-syntax": "off",
"no-bitwise": "off",
"camelcase": "off",
"no-case-declarations": "off",
"@typescript-eslint/no-namespace": "off",
"no-undef": "off",
"no-promise-executor-return": "off",
"vue/multi-word-component-names": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/ban-ts-comment": "off",
"linebreak-style": "off"
}
}

31
.gitignore

@ -0,0 +1,31 @@
.DS_Store
node_modules/
unpackage/
dist/
wxcomponents
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.project
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
.hbuilderx
.gitee
.github
package-lock.json
yarn.lock

9
.prettierrc.js

@ -0,0 +1,9 @@
module.exports = {
printWidth: 700, // 一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
useTabs: false, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
singleQuote: true, // 字符串是否使用单引号,默认为 false,使用双引号
semi: false, // 行尾是否使用分号,默认为true
trailingComma: 'none', // 是否使用尾逗号
bracketSpacing: true // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
}

21
LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 sugar
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.

260
README.md

@ -0,0 +1,260 @@
# uni-vue3-ts-template
uni-app Vue3 + TypeScript + Vite + Pinia + Unocss 模板项目
支持小程序,H5,App
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxODc4OTk1OQ==653218789959)
![Unocss](https://fastly.jsdelivr.net/gh/MellowCo/image-host/2022/202211121156442.png)
| H5 | 微信小程序 | App(iOS) | App(Android) |
| :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------: |
| ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzE5Mzc4MzUyMQ==653193783521) | ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzE5Mzc1Mzk1MQ==653193753951) | ![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMDc2NTcwNg==653210765706) | <img src="https://img.cdn.sugarat.top/mdImg/MTY1MzIxMzkyOTQxNg==653213929416" width="360"/> |
其它模板
* Vue3的uni-app 纯js模板:[uni-app-template](https://github.com/ATQQ/uni-app-template)
* Vue3的Web应用模板:[vite-vue3-template](https://github.com/ATQQ/vite-vue3-template)
## Env Suggest
**Node >= 14.19**
**pnpm 7**
**Registry taobao - https://registry.npmmirror.com/**
## Use This Template
```sh
npx degit atqq/uni-vue3-ts-template#main my-uni-vue3-ts-vite-project
```
## Feature
### Prod
* [x] [Vue3](https://vuejs.org/)
* [x] [Pinia](https://pinia.vuejs.org/) - replace vuex
* [x] [Axios](https://github.com/axios/axios)
* UI/组件库
* [x] [uView](https://vkuviewdoc.fsq.pub/) - vk-uview-ui
* [ ] [uni-ui](https://github.com/dcloudio/uni-ui) - 待接入
### Dev
* [x] [Vite](https://github.com/vitejs/vite)
* [x] [TypeScript](https://github.com/microsoft/TypeScript/#readme)
* [x] [Sass](https://github.com/sass/sass)
* [x] [Less](https://github.com/less/less.js)
* [x] [Eslint](https://eslint.org/)
* [x] [Prettier](https://prettier.io/)
* [x] [Vitest](https://vitest.dev/) - replace jest
* [x] [unocss](https://github.com/unocss/unocss) - 即时按需原子 css 引擎
* [x] GitHooks [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks#readme)
* ~~LintStaged~~
* ~~StyleLint~~
## 使用
### 安装依赖
**建议使用pnpm,依赖安装速度更快**
```sh
npm i -g pnpm
```
```sh
pnpm install
```
**MAC M1(ARM芯片),其它操作系统无需关注**,正常运行需要手动安装 `esbuild-darwin-64`即可
```sh
pnpm add esbuild-darwin-64@0.15.13 -D
```
## 本地启动
### 微信小程序
```sh
# 构建出产物
pnpm dev:mp-weixin
```
> **Q1:** 如果dev的时候发现报错,可以尝试删除`node_modules`之后再在命令行中运行`pnpm install --shamefully-hoist`重新安装依赖再`pnpm dev:mp-weixin`
>
> [详细参考文档](https://pnpm.io/zh/faq#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%883)
> **Q2:** 如果运行白屏,有报错信息 “app.js错误ReferenceError: regeneratorRuntime is not defined”
>
> 参考[解决方案](https://blog.csdn.net/FUFCY/article/details/125160828) 给微信小程序IDE开启**增强编译选项**
然后将编译结果`dist/dev/mp-weixin`导入微信开发者工具即可运行
<details>
<summary>点击查看 导入详细步骤</summary>
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjc3MjA4Mw==637416772083)
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjg4MTUwNA==637416881504)
![图片](https://img.cdn.sugarat.top/mdImg/MTYzNzQxNjY3OTY0NQ==637416679645)
</details>
### H5
```sh
# CSR
pnpm dev:h5
# SSR
pnpm dev:h5:ssr
```
根据提示,打开对应地址即可访问
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMTE0MDEzMg==653211140132)
### App
>**Q1:** 如启动到App侧有报错?
>请更新至最新的HBuilderX-Alpha客户端
#### 安装一些必要工具
需要使用 `uni-app` 官方提供的 [HBuilderX](https://www.dcloud.io/hbuilderx.html) 启动项目
**Android模拟器在MacOSX、Windows上都可以安装;iOS模拟器只能在MacOSX上安装。**
先安装相关模拟器,[详细参考文档](https://hx.dcloud.net.cn/Tutorial/App/installSimulator)
* 安卓:[夜神模拟器](https://www.yeshen.com/blog/)
* iOS:Mac上安装Xcode
准备就绪后,使用 HBuilderX 打开项目
#### iOS模拟器运行
通过顶部菜单栏,找到运行入口
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMjk1MTgzNw==653212951837)
选择一个目标设备,点击启动即可
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMjk3NDM0NQ==653212974345)
#### Android模拟器运行
这里以[夜神模拟器](https://www.yeshen.com/blog/)为例
<details>
<summary>点击查看 详细步骤</summary>
先通过 HBuilderX 修改模拟器端口为 `62001`
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDAzMjIwNg==653214032206)
打开夜神模拟器
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDA5OTYxNg==653214099616)
选择运行到 Android 基座
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDEzMzI0OA==653214133248)
选择已经打开的模拟器,点击运行即可
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxNDIxNjczNw==653214216737)
![图片](https://img.cdn.sugarat.top/mdImg/MTY1MzIxMzkyOTQxNg==653213929416)
</details>
## 打包构建
### 微信小程序
```
pnpm build:mp-weixin
```
### H5
```sh
# CSR
pnpm build:h5
# SSR
pnpm build:h5:ssr
```
### App
基于 `HBuilderX` 参考[官方文档](https://hx.dcloud.net.cn/Tutorial/App/SafePack)进行进一步的操作
其它更多运行脚本 查看 [package.json](./package.json)中的scripts
## css预处理
### 已配置`scss`和`less`全局变量
```typescript
// vite.config.ts
export default defineConfig({
// ......
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "@/static/styles/variables.scss";'
},
less: {
additionalData: '@import "@/static/styles/variables.less";'
}
}
}
})
```
`additionalData`的值是文件的路径,可以按照自己业务需求去修改,**如果项目样式变量分的比较细,可以使用一个样式文件引入多个变量样式文件,然后在这里引入入口文件**
## 别名配置
如果我们想要在`import`的时候 src 的路径简写成`@`,下面的就是配置 vite 的别名,[属性类型请查看vite文档](https://vitejs.cn/config/#resolve-alias)
- `@` 代替 `./src`
- `@components`代替`./src/components`
```typescript
// vite.config.ts
export default defineConfig({
// ......
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components')
}
}
})
```
例子:
```diff
// pages/index/index.vue
- import Hello from '../../components/hello/index.vue'
+ import Hello from '@/components/hello/index.vue'
// 或者
+ import Hello from '@components/hello/index.vue'
```
### ts
如果是使用ts开发,这样还不够,ts不会识别路径的别名,显示找不到模块的报错,这个时候需要修改 `tsconfig.json` 文件,纠正下路径才可以。
```diff
// tsconfig.json
{
// ......
"compilerOptions": {
// ......
+ "baseUrl": "./",
+ "paths": {
+ "@/*": ["src/*"],
+ "@components/*": ["src/components/*"]
}
},
}
```
添加 `baseUrl``paths` 参数,就可以完美解决编辑器的报错提示了!
## 原子化css
* [unocss](https://github.com/unocss/unocss) - 即时按需原子 css 引擎
* [unocss-preset-weapp](https://github.com/MellowCo/unocss-preset-weapp) - 兼容小程序 unocss 预设
> 支持小程序,h5,app
![](https://fastly.jsdelivr.net/gh/MellowCo/image-host/2022/202211121156442.png)

25
index.html

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<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></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app">
<!--app-html-->
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

99
package.json

@ -0,0 +1,99 @@
{
"name": "闻荫APP",
"version": "1.0.0",
"private": true,
"scripts": {
"dev:app": "uni -p app",
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"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: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:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"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: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",
"lint": "eslint --ext .ts,.js,.vue --fix ./",
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"cz": "git add . && czg",
"postinstall": "simple-git-hooks",
"updatehooks": "git config core.hooksPath .git/hooks/ && rm -rf .git/hooks && npx simple-git-hooks"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-app-plus": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-components": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-h5": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3060920221114001",
"axios": "^0.27.2",
"cz-git": "^1.4.1",
"pinia": "^2.0.14",
"vk-uview-ui": "^1.3.7",
"vue": "^3.2.41",
"vue-i18n": "^9.1.9",
"vuex": "^4.0.2"
},
"devDependencies": {
"@commitlint/cli": "^17.4.2",
"@commitlint/config-conventional": "^17.4.2",
"@dcloudio/types": "^3.0.16",
"@dcloudio/uni-automator": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3060920221114001",
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3060920221114001",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3060920221114001",
"@types/node": "^17.0.45",
"@typescript-eslint/eslint-plugin": "^5.30.3",
"@typescript-eslint/parser": "^5.30.3",
"@vitejs/plugin-vue": "^2.3.3",
"@vitest/ui": "^0.10.5",
"c8": "^7.11.3",
"czg": "^1.4.1",
"eslint": "^8.19.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-todo-ddl": "^1.1.1",
"eslint-plugin-vue": "^9.1.1",
"less": "^4.1.3",
"prettier": "^2.7.1",
"sass": "^1.53.0",
"simple-git-hooks": "^2.8.1",
"typescript": "^4.7.4",
"unocss": "^0.46.4",
"unocss-preset-weapp": "^0.2.1",
"vite": "^3.1.8",
"vite-plugin-eslint": "^1.6.1",
"vitest": "^0.16.0"
},
"simple-git-hooks": {
"commit-msg": "npx --no-install commitlint --edit \"$1\""
}
}

5971
pnpm-lock.yaml

File diff suppressed because it is too large

16
src/App.vue

@ -0,0 +1,16 @@
<script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
onLaunch(() => {
console.log('App Launch')
})
onShow(() => {
console.log('App Show')
})
onHide(() => {
console.log('App Hide')
})
</script>
<style lang="scss">
@import 'vk-uview-ui/index.scss';
</style>

94
src/api/http.ts

@ -0,0 +1,94 @@
import axios from 'axios'
import { getFullURL } from '@/utils/http'
const instance = axios.create({
baseURL: import.meta.env.VITE_BASE_URL,
adapter(config) {
const { url, method, data, params, headers, baseURL, paramsSerializer } =
config
return new Promise((resolve, reject) => {
uni.request({
method: method!.toUpperCase() as any,
url: getFullURL(baseURL || '', url!, params, paramsSerializer),
header: headers,
data,
dataType: 'json',
responseType: config.responseType,
success: (res: any) => {
resolve(res)
},
fail: (err: any) => {
reject(err)
}
})
})
}
})
/**
*
*/
instance.interceptors.request.use((config) => {
const { method, params, url } = config
// 附带鉴权的token
const headers: any = {
token: uni.getStorageSync('token')
}
console.log(uni.getStorageSync('token'))
if (uni.getStorageSync('token')) {
headers['Authorization'] = 'Bearer ' + uni.getStorageSync('token')
}
// 不缓存get请求
if (method === 'get') {
headers['Cache-Control'] = 'no-cache'
}
// delete请求参数放入body中
if (method === 'delete') {
headers['Content-type'] = 'application/json;'
Object.assign(config, {
data: params,
params: {}
})
}
return {
...config,
headers
}
})
/**
*
*/
instance.interceptors.response.use((v) => {
if (v.data?.code === 401) {
uni.removeStorageSync('token')
uni.showToast({
title: '登录失效,请重新登录',
icon: 'none',
duration: 1500
});
setTimeout(()=>{
uni.reLaunch({
url: '/pages/login/index'
})
}, 1500)
return v.data
}
// @ts-ignore
if ((v.status || v.statusCode) === 200) {
return v.data
}
uni.showToast({
title: '网络错误',
icon: 'none',
duration: 1500
});
// alert(v.statusText, '网络错误')
return Promise.reject(v)
})
export default instance

1
src/api/index.ts

@ -0,0 +1 @@
export { default as userApi } from './modules/user'

24
src/api/modules/user.ts

@ -0,0 +1,24 @@
import http from '../http'
function login(account: string, pwd: string) {
return http.post('user/login', {
account,
pwd
})
}
/**
*
* @param phone
*/
function getCode(phone: string): Promise<{ num: number }> {
return http.get('random/code', {
params: {
phone
}
})
}
export default {
login,
getCode
}

58
src/components/hello/index.vue

@ -0,0 +1,58 @@
<template>
<view class="hello">
<image class="logo" src="/static/logo.png" />
<view class="text-area">
<text class="title">{{ title }}</text>
</view>
<view class="scss-title">这是scss 全局变量的样式</view>
<view class="less-title">这是less 全局变量的样式</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const title = ref('Hello')
</script>
<style scoped>
.hello {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
<style lang="scss" scoped>
.scss-title {
font-size: $title-size;
color: $title-color;
}
</style>
<style lang="less" scoped>
.less-title {
font-size: @title-size;
color: @title-color;
}
</style>

17
src/components/unocss/index.vue

@ -0,0 +1,17 @@
<template>
<view flex justify-center flex-col items-center my-2>
<view
w-100
h-100
m-3
animate-iteration-infinite
animate-swing
bg-cover
class="bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
></view>
<view class="bg-#3498db/20 text-#3498db rounded" p="x2 y1"
>unocss demo</view
>
</view>
</template>

13
src/env.d.ts

@ -0,0 +1,13 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
interface ImportMetaEnv {
VITE_TITLE: string
VITE_BASE_URL: string
}

38
src/main.ts

@ -0,0 +1,38 @@
import { createSSRApp } from 'vue'
import * as Pinia from 'pinia'
// @ts-ignore
import uView from 'vk-uview-ui'
import App from './App.vue'
// unocss
import 'uno.css'
import {_dTo,_gTo, _toast,_backT, _call,_confirm, _alert, _getSync, _setSync, _removeSync, _showLoading,_closeLoading,_screenshot,_copy,_upLoad} from "./utils/common";
import {accessTimeInAnHour,getNowFormatDate} from "./utils/dateTime";
export function createApp() {
const app = createSSRApp(App)
app.config.globalProperties.$dTo = _dTo
app.config.globalProperties.$gTo = _gTo
app.config.globalProperties.$toast = _toast
app.config.globalProperties.$backT = _backT;
app.config.globalProperties.$call = _call;
app.config.globalProperties.$confirm = _confirm;
app.config.globalProperties.$alert = _alert;
app.config.globalProperties.$getSync = _getSync;
app.config.globalProperties.$setSync = _setSync;
app.config.globalProperties.$removeSync = _removeSync;
app.config.globalProperties.$showLoading = _showLoading;
app.config.globalProperties.$closeLoading = _closeLoading;
app.config.globalProperties.$screenshot = _screenshot;
app.config.globalProperties.$copy = _copy;
app.config.globalProperties.$upLoad = _upLoad;
app.config.globalProperties.$accessTimeInAnHour = accessTimeInAnHour;
app.config.globalProperties.$getNowFormatDate = getNowFormatDate;
app.use(Pinia.createPinia())
app.use(uView)
return {
app,
// uni-app 官方文档示例 https://zh.uniapp.dcloud.io/tutorial/vue3-pinia.html#%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86-pinia
Pinia // 此处必须将 Pinia 返回
}
}

82
src/manifest.json

@ -0,0 +1,82 @@
{
"name" : "闻荫App",
"appid" : "__UNI__DA16D5F",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"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\"/>"
]
},
/* ios */
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wxf326f1995627c671",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"h5" : {
"template" : "index.html",
"devServer" : {
"port" : 9020
}
}
}

22
src/pages.json

@ -0,0 +1,22 @@
{
"pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"easycom": {
"custom": {
"^u-(.*)": "vk-uview-ui/components/u-$1/u-$1.vue"
}
}
}

40
src/pages/axios/index.vue

@ -0,0 +1,40 @@
<template>
<view class="axios-demo">
<view class="title-h1">Axios Page</view>
<input type="number" v-model="phone" />
<button @click="getCode">获取验证码(GET)</button>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { userApi } from '@/api'
const phone = ref('12345678901')
const getCode = () => {
userApi
.getCode(phone.value)
.then((v) => {
uni.showToast({
title: `${v.num}`,
icon: 'success'
})
})
.catch((err) => {
console.log(err)
uni.showToast({
title: '获取验证码失败',
icon: 'error'
})
})
}
</script>
<style lang="less" scoped>
.axios-demo {
text-align: center;
}
.title-h1 {
font-size: 50rpx;
}
</style>

51
src/pages/index/index.vue

@ -0,0 +1,51 @@
<template>
<view class="index-page">
<Hello />
<UnoCss />
<text class="h2"> 查看其它页面示例 </text>
<view>
<navigator v-for="(v, idx) in pages" :key="idx" :url="v.url">{{
v.title
}}</navigator>
</view>
</view>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import Hello from '@/components/hello/index.vue'
import UnoCss from '@/components/unocss/index.vue'
const pages = reactive([
{
title: 'Pinia Demo',
url: '/pages/pinia/index'
},
{
title: 'Axios Demo',
url: '/pages/axios/index'
},
{
title: 'uView Demo',
url: '/pages/uview/index'
},
{
title: 'UnoCSS Demo',
url: '/pages/unocss/index'
}
])
</script>
<style scoped>
.index-page {
font-style: normal;
text-align: center;
}
.h2 {
color: green;
font-size: 50rpx;
}
navigator {
color: #1e80ff;
}
</style>

60
src/pages/pinia/index.vue

@ -0,0 +1,60 @@
<template>
<view class="pinia-demo">
<view class="title-h2">Pinia(Replace Vuex)</view>
<text class="title-h3">{{ isEven ? 'Even' : 'Odd' }}</text>
<text>{{ count }}</text>
<view>
<button @click="add">Sync Add</button>
<button @click="asyncAdd">Async Add</button>
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useCountStore } from '@/store'
// store
const store = useCountStore()
// state
const { count } = storeToRefs(store)
// isEven
const isEven = computed(() => store.count % 2 === 0)
// or getters
// const { isEven } = storeToRefs(store)
// or getters
// const isEven = computed(() => store.isEven)
// add
const add = () =>
store.$patch((v) => {
v.count += 1
})
// or actions
// const add = () => store.synIncrease()
// asyncAdd
// const asyncAdd = () => store.$patch((v) => {
// setTimeout(() => {
// v.count++
// }, 1000)
// })
// or actions
const asyncAdd = () => store.asyncIncrease()
</script>
<style lang="scss" scoped>
.pinia-demo {
text-align: center;
.title-h2 {
color: red;
font-size: 40rpx;
}
.title-h3 {
font-weight: bold;
}
}
</style>

95
src/pages/unocss/index.vue

@ -0,0 +1,95 @@
<template>
<view class="bg-#e2f3fe p-4">
<view class="text-lg mb-2 text-c2">使用 class</view>
<view class="p-5 bg-white rounded-xl shadow-md flex items-center mx-auto">
<view>
<view
class="h-100 w-100 bg-cover bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
/>
</view>
<view class="ml-5">
<view class="text-xl text-c1">UnoCSS</view>
<view class="text-c3">The instant on-demand Atomic CSS engine.</view>
</view>
</view>
<view class="flex mb-2 mt-4">
<view class="text-lg text-c2 mr-4">切换 class</view>
<view
class="bg-#3498db/20 text-#3498db rounded px-2 py-1"
@click="switchFlag"
>点我切换</view
>
</view>
<view
class="p-5 rounded-xl shadow-md flex items-center mx-auto"
:class="[flag ? 'bg-white' : 'bg-green']"
>
<view>
<view
class="h-100 w-100 bg-cover bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
/>
</view>
<view class="ml-5">
<view class="text-xl">UnoCSS</view>
<view class="text-c3">The instant on-demand Atomic CSS engine.</view>
</view>
</view>
<view text="lg c2" m="b2 t4">使用 Attributify mode </view>
<view rounded-xl shadow-md flex items-center mx-auto p-5 bg-white>
<view>
<view
h-100
w-100
bg="cover [url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
/>
</view>
<view ml-5>
<view text="xl c1">UnoCSS</view>
<view text-c3>The instant on-demand Atomic CSS engine.</view>
</view>
</view>
<view text="lg c2" m="b2 t4">基础动画</view>
<view flex justify-center items-center my-2>
<view
w-100
h-100
m-3
animate="iteration-infinite swing"
bg-cover
class="bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
></view>
<view
w-100
h-100
m-3
bg-cover
animate="pulse-bck"
class="bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
></view>
<view
w-100
h-100
m-3
bg-cover
animate="rubber-band iteration-infinite"
class="bg-[url(https://img.cdn.sugarat.top/mdImg/MTY2ODA4OTc3MjcyMg==unocss-icon-gray.svg)]"
></view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const flag = ref(true)
function switchFlag() {
flag.value = !flag.value
}
</script>

42
src/pages/uview/index.vue

@ -0,0 +1,42 @@
<template>
<view>
<u-button>默认按钮</u-button>
<u-button type="primary">主要按钮</u-button>
<u-button type="success">成功按钮</u-button>
<u-button type="info">信息按钮</u-button>
<u-button type="warning">警告按钮</u-button>
<u-button type="error">危险按钮</u-button>
<u-button size="default">江湖</u-button>
<u-button size="medium">夜雨</u-button>
<u-button size="mini">十年灯</u-button>
<!-- <u-calendar :show="show"></u-calendar> -->
<u-button @click="showIs">打开</u-button>
<u-popup v-model="show">
<view>出淤泥而不染濯清涟而不妖</view>
</u-popup>
<!-- <u-picker :show="show" :columns="columns"></u-picker>
<u-rate :count="count" v-model="value"></u-rate>
<u-search placeholder="日照香炉生紫烟" v-model="keyword"></u-search> -->
</view>
</template>
<script lang="ts" setup>
import {
ref,
reactive
} from 'vue'
let show = ref(false);
let keyword = ref('');
let columns = reactive([
['中国', '美国', '日本']
]);
let count = ref(4);
let value = ref(2);
function showIs(){
console.log(1);
show.value = true;
count.value = 2
console.log(show);
}
</script>

BIN
src/static/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

1
src/store/index.ts

@ -0,0 +1 @@
export { default as useCountStore } from './modules/countStore'

23
src/store/modules/countStore.ts

@ -0,0 +1,23 @@
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
// arrow function recommended for full type inference
state: () => ({
// all these properties will have their type inferred automatically
count: 0
}),
getters: {
isEven: (state) => state.count % 2 === 0
},
actions: {
synIncrease() {
this.count += 1
},
async asyncIncrease() {
await new Promise((resolve) => setTimeout(resolve, 1000))
this.count += 1
}
}
})
export default useStore

2
src/styles/vars/_base.less

@ -0,0 +1,2 @@
@title-size: 40rpx;
@title-color: #47caff;

2
src/styles/vars/_base.scss

@ -0,0 +1,2 @@
$title-size: 40rpx;
$title-color: #bd34fe;

77
src/uni.scss

@ -0,0 +1,77 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
@import 'vk-uview-ui/theme.scss';
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; //基本色
$uni-text-color-inverse: #fff; //反色
$uni-text-color-grey: #999; //辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #ffffff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; //点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); //遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 24rpx;
$uni-font-size-base: 28rpx;
$uni-font-size-lg: 32rpx;
/* 图片尺寸 */
$uni-img-size-sm: 40rpx;
$uni-img-size-base: 52rpx;
$uni-img-size-lg: 80rpx;
/* Border Radius */
$uni-border-radius-sm: 4rpx;
$uni-border-radius-base: 6rpx;
$uni-border-radius-lg: 12rpx;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 10px;
$uni-spacing-row-base: 20rpx;
$uni-spacing-row-lg: 30rpx;
/* 垂直间距 */
$uni-spacing-col-sm: 8rpx;
$uni-spacing-col-base: 16rpx;
$uni-spacing-col-lg: 24rpx;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 40rpx;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle: 36rpx;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 30rpx;

140
src/utils/common.ts

@ -0,0 +1,140 @@
const _dTo = function(url) {
if (!_getSync('isLogin')) {
_gTo('/pages/login/index')
return;
}
uni.navigateTo({
url: url
});
}
const _gTo = function(url) {
uni.navigateTo({
url: url
});
}
const _getSync = (i) => {
return uni.getStorageSync(i);
}
const _removeSync = (i) => {
return uni.removeStorageSync(i);
}
const _setSync = (i, data) => {
return uni.setStorageSync(i, data);
}
const _alert = (txt, cb) => {
uni.showModal({
title: '温馨提示',
content: txt,
showCancel: false,
confirmColor: '#2979ff',
success: function() {
cb && cb();
}
});
}
const _confirm = function(txt, cb) {
uni.showModal({
title: '温馨提示',
content: txt,
showCancel: true,
confirmColor: '#2979ff',
success: function(res) {
if (res.confirm) {
cb && cb();
}
}
});
}
const _toast = function(txt) {
uni.showToast({
title: txt,
icon: 'none',
duration: 1500
});
}
const _backT = function() {
uni.navigateBack();
}
const _call = function(tel) {
uni.makePhoneCall({
phoneNumber: tel
});
}
const _showLoading = (msg = '') => uni.showLoading({
mask: true,
title: msg
});
/**
* loading
*/
const _closeLoading = () => uni.hideLoading();
// 获取截图宽高
const _screenshot = function(fromWhere, widthProp, proportion) {
var width = 0,
height = 0;
uni.getSystemInfo({
//整个手机屏幕的高
success: function(res) {
console.log(res)
width = parseInt(res.screenWidth * widthProp) //宽等于屏幕款*百分比
height = width * proportion
}
});
_gTo('../u-avatar-cropper/u-avatar-cropper?destWidth=' + (width * 2) + '&destHeight=' + (height * 2) +
'&rectWidth=' + width + '&rectHeight=' + height + '&fileType=jpg' + '&fromWhere=' +
fromWhere)
}
// 复制
const _copy = (data) => {
uni.setClipboardData({
data: data,
success: function() {
console.log('success');
}
});
}
const _upLoad = function(tempFilePaths) {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: import.meta.env.VITE_BASE_URL + '/common/upload', //仅为示例,非真实的接口地址
filePath: tempFilePaths,
name: 'file',
formData: {
'user': 'test'
},
header: { "Content-Type": "multipart/form-data", 'openId': uni.getStorageSync('openId') },
success: (uploadFileRes) => {
let item = JSON.parse(uploadFileRes.data.replace(/\ufeff/g, ""));
resolve(item)
},
fail(err) {
}
});
})
}
export {
_dTo,
_gTo,
_toast,
_backT,
_call,
_confirm,
_alert,
_getSync,
_setSync,
_removeSync,
_showLoading,
_closeLoading,
_screenshot,
_copy,
_upLoad
};

52
src/utils/dateTime.ts

@ -0,0 +1,52 @@
const zeroPadd = function(date) {
var hours = date.getHours(); // 获取时
var minutes = date.getMinutes(); // 获取分
var second = date.getSeconds(); // 获取秒
var seperator1 = "-"; // 自定义日期分隔符
var year = date.getFullYear(); // 获取年
var month = date.getMonth() + 1; // 获取月
var strDate = date.getDate(); // 获取日
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
if (hours >= 0 && hours <= 9) {
hours = "0" + hours;
}
if (minutes >= 0 && minutes <= 9) {
minutes = "0" + minutes;
}
if (second >= 0 && second <= 9) {
second = "0" + second;
}
var time = hours + ":" + minutes + ":" + second; // 时分秒
var currentdate = year + seperator1 + month + seperator1 + strDate; // 年月日
var date = {
time, currentdate
}
return date;
}
// 获取当前日期 时间
const getNowFormatDate = function(date) {
return zeroPadd(date);
}
//获取一小时后的日期 时间
const accessTimeInAnHour = function(date, h) {
var date1 = date.getTime(); // 获取当前时间戳
// 当前时间戳+3600s(一小时,其他时间通过计算时间戳进行相应加减),重新设置 Date 对象
// console.log(date)
date.setTime(date1 + h * 3600000);
// console.log(zeroPadd(date))
return zeroPadd(date);
}
export {
getNowFormatDate,
accessTimeInAnHour,
};

19
src/utils/http.ts

@ -0,0 +1,19 @@
// @ts-ignore
import buildURL from 'axios/lib/helpers/buildURL'
import type { AxiosRequestConfig } from 'axios'
type ParamsSerializer = AxiosRequestConfig['paramsSerializer']
export function getFullURL(
baseURL: string,
url: string,
params: Record<string, any>,
paramsSerializer?: ParamsSerializer
) {
if (url.startsWith('http')) {
return buildURL(url, params, paramsSerializer)
}
baseURL = baseURL.endsWith('/') ? baseURL : `${baseURL}/`
url = url.startsWith('/') ? url.slice(1) : url
return buildURL(`${baseURL}${url}`, params, paramsSerializer)
}

31
src/utils/utils.ts

@ -0,0 +1,31 @@
function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
export default {
compareVersion
}

762
src/utils/validator.ts

@ -0,0 +1,762 @@
//校验学校编码 只能为数字
export function validateCode(rule, value, callback) {
if (!value) {
return callback(new Error('学校编码不能为空'))
} else {
const codeReg = /^[0-9]+$/
const codeMax = /^\d{0,5}$/
if (codeReg.test(value)) {
if (codeMax.test(value)) {
callback()
} else {
callback(new Error('学校编码不能大于5位'))
}
} else {
callback(new Error('请输入正确的学校编码,只能是数字'))
}
}
}
//校验邮箱
export function validateEmail(rule, value, callback) {
if (value) {
const mailReg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/
if (mailReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的邮箱格式'))
}
} else {
callback()
}
}
//校验英文
export function validateEng(rule, value, callback) {
if (value) {
const mailReg = /^[A-Za-z\-\&\(\)\Ⅰ\Ⅱ\Ⅲ\Ⅳ\Ⅴ\Ⅵ\Ⅶ\Ⅷ\Ⅸ\Ⅹ\s]+$/;
if (mailReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的英文名字'))
}
} else {
callback()
}
}
//校验姓名拼音
export function validateEngName(rule, value, callback) {
if (value) {
const EngNameReg = /^[A-Za-z \(\)\s]+$/
if (EngNameReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的姓名拼音'))
}
} else {
callback()
}
}
//校验手机号码
export function validateHanset(rule, value, callback) {
if (value) {
// const regs =/^[1][3,4,5,6,7,8,9][0-9]{9}$/;
// const regs = /^1[3|4|5|7|8][0-9]\d{8}$/
const regs = /^1[3-9]\d{9}$/
if (regs.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的手机号'))
}
} else {
callback()
}
}
//校验座机电话
export function validatePhone(rule, value, callback) {
if (value) {
//const reg = /^1[3|4|5|7|8][0-9]\d{8}$/
// const regs = /^([0-9]{3,4}-)?[0-9]{7,8}$/;
const regs = /^((0\d{2,3}-\d{7,8}))$/;
// console.log(regss.test(value));
if (regs.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的座机号'))
}
} else {
callback()
}
}
//校验家庭电话 手机或者座机
export function validateFamilyPhone(rule, value, callback) {
if (value) {
const isPhone = /^([0-9]{3,4}-)?[0-9]{7,8}$/;
const isMob = /^((\+?86)|(\+86))?(13[0123456789][0-9]{8}|15[0123456789][0-9]{8}|17[0123456789][0-9]{8}|18[0123456789][0-9]{8}|147[0-9]{8}|1349[0-9]{7})$/;
// console.log(regss.test(value));
if (isPhone.test(value) || isMob.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的手机或者座机电话'))
}
} else {
callback()
}
}
// 校验只能为中文
export function validateChinese(rule, value, callback) {
if (value) {
const chineseReg = /^[\u4E00-\u9FA5]+$/
if (chineseReg.test(value)) {
callback()
} else {
callback(new Error('请输入简介,只能为中文'))
}
} else {
callback()
}
}
// 校验名称既能为中文也可以为英文
export function validateName(rule, value, callback) {
if (value) {
const chineseReg = /^[\u4E00-\u9FA5]+$/
const engLish = /^[A-Za-z]+$/
if (chineseReg.test(value) || engLish.test(value)) {
callback()
} else {
callback(new Error('请输入正确的中文或者英文名称'))
}
} else {
callback()
}
}
// 校验负责人既能为中文也可以为英文
export function validateChargeperson(rule, value, callback) {
if (value) {
const chineseReg = /^[\u4E00-\u9FA5]+$/
const engLish = /^[A-Za-z]+$/
if (chineseReg.test(value) || engLish.test(value)) {
callback()
} else {
callback(new Error('请输入正确的负责人(中英文都可以)'))
}
} else {
callback()
}
}
//校验学校名称不能为空
export function validateXXMC(rule, value, callback) {
if (!value) {
return callback(new Error('案例名称不能为空'))
} else {
const chineseReg = /^[\u4E00-\u9FA5]+$/
if (chineseReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的案例名称,只能是汉字'))
}
}
}
//校验中英文数字和下划线都可以
export function validateZYS(rule, value, callback) {
if (value) {
//const postReg =/^[\u4e00-\u9fa5_a-zA-Z0-9_]{4,10}+$/
const Reg = /^[\u4e00-\u9fa5a-zA-Z0-9]+$/
if (Reg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的名称'))
}
} else {
callback()
}
}
// 校验邮政编码
export function validatePostCode(rule, value, callback) {
if (value) {
const postReg = /^[1-9]\d{5}$/
if (postReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的邮政编码'))
}
} else {
callback()
}
}
// 数字
export function validateNum(rule, value, callback) {
if (value) {
const numReg = /^[\d]+$/
if (numReg.test(value)) {
callback()
} else {
callback(new Error('请输入数字'))
}
} else {
callback()
}
}
//数字和小数点
export function validateNumDot(rule, value, callback) {
if (value) {
const numReg = /^\d+$|^\d+\.\d+$/g
if (numReg.test(value)) {
callback()
} else {
callback(new Error('请输入数字或小数点'))
}
} else {
callback()
}
}
// 组织机构代码
export function validateOrganization(rule, value, callback) {
if (value) {
const orgReg = /^[A-Za-z0-9]\w{14}$/g
if (orgReg.test(value)) {
callback()
} else {
callback(new Error('请输入组织机构代码'))
}
} else {
callback()
}
}
// 传真
export function validateFax(rule, value, callback) {
if (value) {
const faxReg = /^(\d{3,4}-)?\d{7,8}$/
if (faxReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的传真'))
}
} else {
callback()
}
}
// 主页地址
export function validateHome(rule, value, callback) {
if (value) {
const homeReg = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/
if (homeReg.test(value)) {
callback()
} else {
return callback(new Error('请输入正确的主页地址'))
}
} else {
callback()
}
}
// 学分 小数,且保留最多三位小数
export function validateXf(rule, value, callback) {
if (!value) {
return callback(new Error('学分不能为空'))
} else {
const numReg = /^[0-9]+\.[0-9]{0,3}$/
if (numReg.test(value)) {
callback()
} else {
callback(new Error('请输入小数,且小数点后最多三位'))
}
}
}
// 数字格式 小数点后一位
export function validateOneNum(rule, value, callback) {
if (value) {
const numReg = /^\d+(\.\d+)?$/
const numOneReg = /^\d*\.{0,1}\d{0,1}$/
if (numReg.test(value)) {
if (numOneReg.test(value)) {
callback()
} else {
callback(new Error('小数点后最多1位'))
}
} else {
callback(new Error('请输入数字'))
}
}
callback()
}
// 数字格式 小数点后两位
export function validateTwoNum(rule, value, callback) {
if (value) {
const numReg = /^\d+(\.\d+)?$/
const numTwoReg = /^\d*\.{0,2}\d{0,2}$/
if (numReg.test(value)) {
if (numTwoReg.test(value)) {
callback()
} else {
callback(new Error('小数点后最多2位'))
}
} else {
callback(new Error('请输入数字'))
}
}
callback()
}
// 数字格式 小数点后两位 小数点前保留五位
export function validateTwoNumThree(rule, value, callback) {
if (value) {
if (Number(value) > 10000) {// 校验value值不能大于10000
console.log(Number(value))
callback(new Error('数值过大,请重新输入'))
}
const numReg = /^\d+(\.\d+)?$/
const numTwoReg = /^\d*\.{0,2}\d{0,2}$/
if (numReg.test(value)) {
if (numTwoReg.test(value)) {
callback()
} else {
callback(new Error('小数点后最多2位'))
}
} else {
callback(new Error('请输入数字'))
}
}
callback()
}
// 数字格式 小数点后三位
export function validateThreeNum(rule, value, callback) {
if (value) {
const numReg = /^\d+(\.\d+)?$/
const numTwoReg = /^\d*\.{0,3}\d{0,3}$/
if (numReg.test(value)) {
if (numTwoReg.test(value)) {
callback()
} else {
callback(new Error('小数点后最多3位'))
}
} else {
callback(new Error('请输入数字'))
}
}
callback()
// if (!value) {
// return callback(new Error('字段不能为空'))
// } else {
// const numReg = /^\d+(\.\d+)?$/
// const numTwoReg = /^\d*\.{0,3}\d{0,3}$/
// if (numReg.test(value)) {
// if (numTwoReg.test(value)) {
// callback()
// } else {
// callback(new Error('小数点后最多3位'))
// }
// } else {
// callback(new Error('请输入数字'))
// }
// }
}
//校验年份必须为4位数字
export function validateNF(rule, value, callback) {
if (value) {
const NFReg = /^\d{4}$/
if (NFReg.test(value)) {
callback()
} else {
callback(new Error('请输入4位数字'))
}
} else {
callback()
}
}
//校验年份必须为4位数字
export function validateXQ(rule, value, callback) {
if (value) {
const NFReg = /^\d{5}$/
if (NFReg.test(value)) {
callback()
} else {
callback(new Error('请输入5位数字'))
}
} else {
callback()
}
}
//校验分数最大值
export function validateMaxNumber(rule, value, callback) {
if (parseInt(value) <= 200) {
callback()
} else {
callback(new Error('分数不能大于200'))
}
}
//校验正整数
export function validateInteger(rule, value, callback) {
if (value) {
const integerReg = /^[+]{0,1}(\d+)$/
if (integerReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的整数'))
}
} else {
callback()
}
}
//校验整数
export function validateroundNumber(rule, value, callback) {
if (value) {
const numReg = /^[1-9]\d*$/
if (numReg.test(value)) {
callback()
} else {
callback(new Error('请输入正确的整数'))
}
} else {
callback()
}
}
//校验身份证号
export function validateCard(rule, value, callback) {
if (value) {
let cardBoolean = IdCardValidate(value);
// const cardReg =/(^\d{18}$)|(^\d{17}(\d|X|x)$)/
// if (cardReg.test(value)) {
if (cardBoolean) {
callback()
} else {
callback(new Error('请输入正确的身份证号'))
}
} else {
callback()
}
}
//身份证:身份证校验
function IdCardValidate(code) {
var tip = "";
if (code != "") {
var city = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江 ",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北 ",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏 ",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "新疆",
71: "台湾",
81: "香港",
82: "澳门",
91: "国外 "
};
var pass = true;
//是否为空
if (code === '') {
tip = "请输入身份证号,身份证号不能为空";
pass = false;
}
//校验长度,类型
else if (isCardNo(code) === false) {
tip = "您输入的身份证号码不正确,请重新输入";
pass = false;
}
//检查省份
else if (checkProvince(code, city) === false) {
tip = "您输入的身份证号码不正确,请重新输入";
pass = false;
}
//校验生日
else if (checkBirthday(code) === false) {
tip = "您输入的身份证号码生日不正确,请重新输入";
pass = false;
} else {
//18位身份证需要验证最后一位校验位
if (code.length == 18) {
code = code.split('');
//∑(ai×Wi)(mod 11)
//加权因子
var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
//校验位
var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
var sum = 0;
var ai = 0;
var wi = 0;
for (var i = 0; i < 17; i++) {
ai = code[i];
wi = factor[i];
sum += ai * wi;
}
var last = parity[sum % 11];
if (parity[sum % 11] != code[17]) {
tip = "身份证格式错误";
pass = false;
}
}
}
return pass;
}
}
//身份证:检查身份证号码是否符合规范,包括长度,类型
function isCardNo(card) {
//身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
var reg = /(^\d{15}$)|(^\d{17}(\d|X)$)/;
if (reg.test(card) === false) {
return false;
}
return true;
};
//身份证:取身份证前两位,校验省份
function checkProvince(card, city) {
var province = card.substr(0, 2);
if (city[province] == undefined) {
return false;
}
return true;
};
//身份证:检查生日是否正确
function checkBirthday(card) {
var len = card.length;
//身份证15位时,次序为省(3位)市(3位)年(2位)月(2位)日(2位)校验位(3位),皆为数字
if (len == '15') {
var re_fifteen = /^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/;
var arr_data = card.match(re_fifteen);
var year = arr_data[2];
var month = arr_data[3];
var day = arr_data[4];
var birthday = new Date('19' + year + '/' + month + '/' + day);
return verifyBirthday('19' + year, month, day, birthday);
}
//身份证18位时,次序为省(3位)市(3位)年(4位)月(2位)日(2位)校验位(4位),校验位末尾可能为X
if (len == '18') {
var re_eighteen = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/;
var arr_data = card.match(re_eighteen);
var year = arr_data[2];
var month = arr_data[3];
var day = arr_data[4];
var birthday = new Date(year + '/' + month + '/' + day);
return verifyBirthday(year, month, day, birthday);
}
return false;
};
//身份证:校验日期
function verifyBirthday(year, month, day, birthday) {
var now = new Date();
var now_year = now.getFullYear();
//年月日是否合理
if (birthday.getFullYear() == year && (birthday.getMonth() + 1) == month && birthday.getDate() == day) {
//判断年份的范围(3岁到100岁之间)
var time = now_year - year;
if (time >= 3 && time <= 100) {
return true;
}
return false;
}
return false;
};
/**
* 18
* @param a_idCard
* @return
*/
function isTrueValidateCodeBy18IdCard(a_idCard) {
let By18Val = a_idCard[17].toLowerCase(); // 获取第十八位值
const numReg = /^[1-9]\d*$/
let numVal = false; // 校验第十八位是否为整数
if (numReg.test(Number(By18Val))) {
numVal = true
} else {
numVal = false
}
if (By18Val == 'x' || By18Val == 'X' || numVal) {
return true
} else {
return false
}
}
/**
*
* @param AddressNum
* @constructor
*/
function IdCardValidateAddress(AddressNum) {
var city = {
11: "北京",
12: "天津",
13: "河北",
14: "山西",
15: "内蒙古",
21: "辽宁",
22: "吉林",
23: "黑龙江 ",
31: "上海",
32: "江苏",
33: "浙江",
34: "安徽",
35: "福建",
36: "江西",
37: "山东",
41: "河南",
42: "湖北 ",
43: "湖南",
44: "广东",
45: "广西",
46: "海南",
50: "重庆",
51: "四川",
52: "贵州",
53: "云南",
54: "西藏 ",
61: "陕西",
62: "甘肃",
63: "青海",
64: "宁夏",
65: "新疆",
71: "台湾",
81: "香港",
82: "澳门",
91: "国外 "
};
if (city[AddressNum.substr(0, 2)]) {
return true
} else {
return false
}
}
/**
* 18
* @param idCard 18
* @return
*/
function isValidityBrithBy18IdCard(idCard18) {
var year = idCard18.substring(6, 10);
var month = idCard18.substring(10, 12);
var day = idCard18.substring(12, 14);
var temp_date = new Date(year, parseFloat(month) - 1, parseFloat(day));
// 这里用getFullYear()获取年份,避免千年虫问题
if (temp_date.getFullYear() != parseFloat(year)
|| temp_date.getMonth() != parseFloat(month) - 1
|| temp_date.getDate() != parseFloat(day)) {
return false;
} else {
return true;
}
}
/**
* 15
* @param idCard15 15
* @return
*/
function isValidityBrithBy15IdCard(idCard15) {
var year = idCard15.substring(6, 8);
var month = idCard15.substring(8, 10);
var day = idCard15.substring(10, 12);
var temp_date = new Date(year, parseFloat(month) - 1, parseFloat(day));
// 对于老身份证中的你年龄则不需考虑千年虫问题而使用getYear()方法
if (temp_date.getYear() != parseFloat(year)
|| temp_date.getMonth() != parseFloat(month) - 1
|| temp_date.getDate() != parseFloat(day)) {
return false;
} else {
return true;
}
}
/**
*
* @param str
* @returns {*}
*/
function trim(str) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
export default {
validateCode,
validateEmail,
validateEng,
validatePhone,
validateChinese,
validatePostCode,
validateNum,
validateNumDot,
validateZYS,
validateOrganization,
validateFax,
validateHome,
validateXXMC,
validateXf,
validateOneNum,
validateMaxNumber,
validateTwoNum,
validateTwoNumThree,
validateThreeNum,
validateInteger,
validateNF,
validateXQ,
validateroundNumber,
validateEngName,
validateCard,
validateHanset,
validateFamilyPhone,
validateName,
validateChargeperson
}

26
tsconfig.json

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": [
"@dcloudio/types",
"vite/client",
"@types/node",
"vitest/globals"
],
"baseUrl": "./",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

30
unocss.config.ts

@ -0,0 +1,30 @@
import presetWeapp from 'unocss-preset-weapp'
import { defineConfig } from 'unocss'
import {
transformerAttributify,
transformerClass
} from 'unocss-preset-weapp/transformer'
export default defineConfig({
presets: [
// https://github.com/MellowCo/unocss-preset-weapp
presetWeapp()
],
shortcuts: [
{
'border-base': 'border border-gray-500_10',
'flex-center': 'flex justify-center items-center',
'bg-base': 'bg-#f6f7fb',
'text-c1': 'color-#000/85',
'text-c2': 'color-#000/65',
'text-c3': 'color-#000/45',
'text-c4': 'color-#000/25'
}
],
transformers: [
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify
transformerAttributify(),
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass
transformerClass()
]
})

47
vite.config.ts

@ -0,0 +1,47 @@
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import path from 'path'
import Unocss from 'unocss/vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
uni(),
// https://github.com/antfu/unocss
Unocss()
],
server: {
port: 81,
host: '0.0.0.0',
proxy: {
'/api/': {
target:
'https://service-rbji0bev-1256505457.cd.apigw.tencentcs.com/release',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/api/, '')
},
'/api-prod/': {
target: 'http://localhost:3001',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/api-prod/, '')
}
}
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components')
}
},
css: {
// 配置`scss`和`less`全局变量
preprocessorOptions: {
scss: {
additionalData: '@import "@/styles/vars/_base.scss";'
},
less: {
additionalData: '@import "@/styles/vars/_base.less";'
}
}
}
})

7
vitest.config.ts

@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true
}
})

24
y/.gitignore

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

13
y/index.html

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

15
y/package.json

@ -0,0 +1,15 @@
{
"name": "y",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"typescript": "^5.0.2",
"vite": "^4.4.0"
}
}

1
y/public/vite.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

9
y/src/counter.ts

@ -0,0 +1,9 @@
export function setupCounter(element: HTMLButtonElement) {
let counter = 0
const setCounter = (count: number) => {
counter = count
element.innerHTML = `count is ${counter}`
}
element.addEventListener('click', () => setCounter(counter + 1))
setCounter(0)
}

24
y/src/main.ts

@ -0,0 +1,24 @@
import './style.css'
import typescriptLogo from './typescript.svg'
import viteLogo from '/vite.svg'
import { setupCounter } from './counter.ts'
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="${viteLogo}" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
<img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
</a>
<h1>Vite + TypeScript</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the Vite and TypeScript logos to learn more
</p>
</div>
`
setupCounter(document.querySelector<HTMLButtonElement>('#counter')!)

97
y/src/style.css

@ -0,0 +1,97 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vanilla:hover {
filter: drop-shadow(0 0 2em #3178c6aa);
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

1
y/src/typescript.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path fill="#007ACC" d="M0 128v128h256V0H0z"></path><path fill="#FFF" d="m56.612 128.85l-.081 10.483h33.32v94.68h23.568v-94.68h33.321v-10.28c0-5.69-.122-10.444-.284-10.566c-.122-.162-20.4-.244-44.983-.203l-44.74.122l-.121 10.443Zm149.955-10.742c6.501 1.625 11.459 4.51 16.01 9.224c2.357 2.52 5.851 7.111 6.136 8.208c.08.325-11.053 7.802-17.798 11.988c-.244.162-1.22-.894-2.317-2.52c-3.291-4.795-6.745-6.867-12.028-7.233c-7.76-.528-12.759 3.535-12.718 10.321c0 1.992.284 3.17 1.097 4.795c1.707 3.536 4.876 5.649 14.832 9.956c18.326 7.883 26.168 13.084 31.045 20.48c5.445 8.249 6.664 21.415 2.966 31.208c-4.063 10.646-14.14 17.879-28.323 20.276c-4.388.772-14.79.65-19.504-.203c-10.28-1.828-20.033-6.908-26.047-13.572c-2.357-2.6-6.949-9.387-6.664-9.874c.122-.163 1.178-.813 2.356-1.504c1.138-.65 5.446-3.129 9.509-5.485l7.355-4.267l1.544 2.276c2.154 3.29 6.867 7.801 9.712 9.305c8.167 4.307 19.383 3.698 24.909-1.26c2.357-2.153 3.332-4.388 3.332-7.68c0-2.966-.366-4.266-1.91-6.501c-1.99-2.845-6.054-5.242-17.595-10.24c-13.206-5.69-18.895-9.224-24.096-14.832c-3.007-3.25-5.852-8.452-7.03-12.8c-.975-3.617-1.22-12.678-.447-16.335c2.723-12.76 12.353-21.659 26.25-24.3c4.51-.853 14.994-.528 19.424.569Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

1
y/src/vite-env.d.ts

@ -0,0 +1 @@
/// <reference types="vite/client" />

23
y/tsconfig.json

@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
Loading…
Cancel
Save