This commit is contained in:
XiaoDaiGua-Ray 2023-08-31 15:29:46 +08:00
parent 4dd2024bec
commit d6be8fe9fe
17 changed files with 708 additions and 101 deletions

View File

@ -1,5 +1,18 @@
# CHANGE LOG
## 4.1.9
### Feats
- 新增 RayQRCode 组件(二维码)
- 基于 awesome-qr 封装,继承其所有特性。并且拓展了 状态、下载、自动更新等属性
- 自动卸载于释放内存,仅需要关注 text 内容填充
- 移除 qrcode.vue 依赖
### Fixes
- 修复了一些小细节问题
## 4.1.8
### Feats

147
README.md
View File

@ -1,44 +1,16 @@
<div align="center"> <a href="https://github.com/XiaoDaiGua-Ray/ray-template"> <img alt="Ray Template" width="200" height="200" src="https://usc1.contabostorage.com/c2e495d7890844d392e8ec0c6e5d77eb:alist/ray/ray.svg?sign=ZklU9Bh5b6oKp1X0LOhGwkx4g5mW4wk_w9Jt5zlZ5EQ=:0"> </a> <br> <br>
<h1>Ray Template</h1>
</div>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<div align="center">
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)
# Ray Template
<!-- ALL-CONTRIBUTORS-BADGE:END -->
一个基于 vite4.x & ts(x) & pinia & vue3.x 的中后台模板
## 前言
</div>
> 该项目模板采用 `vue3.x` `vite4.x` `pinia` `tsx` 进行开发。
> 使用 `naive ui` 作为组件库。
> 预设了最佳构建体验的配置与常用搬砖工具。意在提供一个简洁、快速上手的模板。
> 该模板不支持移动端设备。
## 感谢
> 感谢 [`yun`](https://me.yka.moe/) 对于本人的支持。
## 预览地址
- [点击预览](https://xiaodaigua-ray.github.io/ray-template/#/)
- [点击预览(加速地址)](https://ray-template.yunkuangao.com/#/)
## 文档地址
- [文档](https://xiaodaigua-ray.github.io/ray-template-doc/)
- [文档(加速地址)](https://ray-template.yunkuangao.com/ray-template-doc/)
## 更新日志
- [日志](https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io/blob/main/CHANGELOG.md)
## 常见问题
- [常见问题](https://github.com/XiaoDaiGua-Ray/ray-template/blob/main/COMMONPROBLEM.md)
## 特性
## ✨ 特性
- **最新技术栈**:使用 Vue3.x/vite4.x 等前端前沿技术开发
- **TypeScript**:应用程序级 JavaScript 的语言
@ -49,7 +21,21 @@
- **组件**:二次封装了多个常用的组件
- **Axios 请求**:二次封装 axios 库
## 准备
## 🪄 预览地址
- [点击预览](https://xiaodaigua-ray.github.io/ray-template/#/)
- [点击预览(加速地址)](https://ray-template.yunkuangao.com/#/)
## 🦾 文档地址
- [文档](https://xiaodaigua-ray.github.io/ray-template-doc/)
- [文档(加速地址)](https://ray-template.yunkuangao.com/ray-template-doc/)
## 🔋 更新日志
- [更新日志](https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io/blob/main/CHANGELOG.md)
## 🪴 准备
- [node](http://nodejs.org/) 和 [git](https://git-scm.com/) -项目开发环境
- [Vite](https://vitejs.dev/) - 熟悉 vite 特性
@ -62,16 +48,9 @@
- [Pinia](https://pinia.vuejs.org/zh/introduction.html) - 状态管理器 pinia 使用
- [TSX](https://github.com/vuejs/babel-plugin-jsx/blob/main/packages/babel-plugin-jsx/README-zh_CN.md) - tsx 基本语法
## 未来
## 📦 起步
> 根据个人时间空余情况,会不定时对该模板进行更新和迭代。希望将该工具的功能不断补全(虽然现在已经是足够日常开发和使用),将该模板打造为一个更加健全的中后台模板。如果你有好的想法和建议,可以直接联系我或者直接提 `issues` 即可。
## 提示
> 项目默认启用严格模式 `eslint`,但是由于 `vite-plugin-eslint` 插件优先级最高,所以如果出现自动导入类型错误提示,请优先解决其他问题。
> 建议开启 `vscode` 保存自动修复功能。
## 项目安装
### 获取项目
```sh
# github
@ -81,12 +60,12 @@ git clone https://github.com/XiaoDaiGua-Ray/ray-template.git
git clone https://gh.yka.moe/https://github.com/XiaoDaiGua-Ray/ray-template.git
```
## 拉取依赖
### 拉取依赖
```sh
# yarn
# pnpm
yarn
pnpm
```
```sh
@ -95,12 +74,12 @@ yarn
npm install
```
## 启动项目
### 启动项目
```sh
# yarn
# pnpm
yarn dev
pnpm dev
```
```sh
@ -109,12 +88,12 @@ yarn dev
npm run dev
```
## 项目打包
### 项目打包
```sh
# yarn
# pnpm
yarn build
pnpm build
```
```sh
@ -123,12 +102,12 @@ yarn build
npm run build
```
## 预览项目
### 预览项目
```sh
# yarn
# pnpm
yarn preview
pnpm preview
```
```sh
@ -137,12 +116,12 @@ yarn preview
npm run preview
```
## 体积分析
### 体积分析
```sh
# yarn
# pnpm
yarn report
pnpm report
```
```sh
@ -151,48 +130,24 @@ yarn report
npm run report
```
## 浏览器支持
## 🪴 项目活动
> 仅支持现代浏览器,不支持 `IE`
![Alt](https://repobeats.axiom.co/api/embed/fab6071297ab281913a42f07a2779b488cfd62b8.svg 'Repobeats analytics image')
### 贡献者
感谢他们的所做的一切贡献 🐝
<a href="https://github.com/XiaoDaiGua-Ray/ray-template/graphs/contributors">
<img src="https://contrib.rocks/image?repo=XiaoDaiGua-Ray/ray-template" />
</a>
## 浏览器支持
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 最后,希望大家搬砖愉快
## 📄 证书
## 贡献者
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://heartofyun.com"><img src="https://avatars.githubusercontent.com/u/40163747?v=4?s=100" width="100px;" alt="Cloud"/><br /><sub><b>Cloud</b></sub></a><br /><a href="#tool-yunkuangao" title="Tools">🔧</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## License
[MIT © Ray-2020](./LICENSE)
[MIT License](https://github.com/XiaoDaiGua-Ray/ray-template/blob/main/LICENSE) © 2022-PRESENT [Ray](https://github.com/XiaoDaiGua-Ray/ray-template)

View File

@ -25,6 +25,7 @@
},
"dependencies": {
"@vueuse/core": "^9.1.0",
"awesome-qr": "2.1.5-rc.0",
"axios": "^1.2.0",
"clipboard": "^2.0.11",
"crypto-js": "^4.1.1",
@ -37,7 +38,6 @@
"pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.1.0",
"print-js": "^1.6.0",
"qrcode.vue": "^3.3.4",
"sass": "^1.54.3",
"screenfull": "^6.0.2",
"vue": "^3.3.4",

View File

@ -22,6 +22,8 @@ module.exports = {
unitPrecision: 3,
/** 指定需要转换成的视窗单位 */
viewportUnit: 'rem',
/** 制定字体转换单位 */
fontViewportUnit: 'rem',
/** 指定不转换为视窗单位的类 */
selectorBlackList: ['.ignore'],
/** 小于或等于 1px 不转换为视窗单位 */

View File

@ -0,0 +1,9 @@
import RayQRcode from './src/index'
export default RayQRcode
export type {
QRCodeStatus,
QRCodeLevel,
QRCodeRenderResponse,
QRCodeInst,
} from './src/type'

View File

@ -0,0 +1,26 @@
.ray-qrcode {
position: relative;
display: inline-flex;
& .ray-qrcode__error {
position: absolute;
width: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
background-color: rgba(0, 0, 0, 0.7);
width: 100%;
height: 100%;
@include flexCenter;
flex-direction: column;
gap: 18px 0;
& .ray-qrcode__error-content {
text-align: center;
font-size: 18px;
font-weight: 500;
color: #ffffff;
}
}
}

View File

@ -0,0 +1,140 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-29
*
* @workspace ray-template
*
* @remark
*/
import './index.scss'
import { NButton, NSpin } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import props from './props'
import { AwesomeQR } from 'awesome-qr'
import { isValueType, downloadBase64File } from '@use-utils/hook'
import { call } from '@/utils/vue/index'
import type { QRCodeRenderResponse } from './type'
const RayQRcode = defineComponent({
name: 'RayQRcode',
props,
setup(props, ctx) {
const { expose } = ctx
const qrcodeURL = ref<QRCodeRenderResponse>()
const spinOverrides = {
opacitySpinning: '0.1',
}
const renderQRCode = () => {
new AwesomeQR({
...props,
})
.draw()
.then((res) => {
const { onSuccess } = props
if (onSuccess) {
call(onSuccess, res)
}
qrcodeURL.value = res
})
.catch((err) => {
const { onError } = props
if (onError) {
call(onError, err)
}
})
}
const errorActionClick = () => {
if (ctx.slots.errorAction) {
return
}
const { onReload } = props
if (onReload) {
call(onReload)
}
}
const downloadQRCode = (fileName?: string) => {
if (qrcodeURL.value && isValueType<string>(qrcodeURL.value, 'String')) {
downloadBase64File(qrcodeURL.value, fileName)
}
}
watchEffect(() => {
if (props.watchText) {
nextTick().then(() => {
renderQRCode()
})
}
})
expose({
downloadQRCode,
})
onMounted(() => {
renderQRCode()
})
return {
qrcodeURL,
spinOverrides,
errorActionClick,
}
},
render() {
return (
<div class="ray-qrcode">
<NSpin
show={this.status === 'loading'}
themeOverrides={this.spinOverrides}
>
<img src={this.qrcodeURL as string | undefined} />
</NSpin>
{this.status === 'error' ? (
<div class="ray-qrcode__error">
<div class="ray-qrcode__error-content">
{isValueType<string>(this.errorDescription, 'String')
? this.errorDescription
: () => this.errorDescription}
</div>
<div
class="ray-qrcode__error-btn"
onClick={this.errorActionClick.bind(this)}
>
{this.$slots.errorAction ? (
this.$slots.errorAction()
) : (
<>
<NButton text color="#ffffff">
{{
default: () => this.errorActionDescription,
icon: () => (
<RayIcon name="reload" size="16" color="#ffffff" />
),
}}
</NButton>
</>
)}
</div>
</div>
) : null}
</div>
)
},
})
export default RayQRcode

View File

@ -0,0 +1,281 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-29
*
* @workspace ray-template
*
* @remark
*/
import type { QRCodeStatus, QRCodeLevel } from './type'
import type { PropType, VNode } from 'vue'
import type { MaybeArray } from '@/types/modules/utils'
import type { Options } from 'awesome-qr'
const props = {
watchText: {
/**
*
* Atuo watch QR code text
* If update text, then re-render QR code
*
* @default true
*/
type: Boolean,
default: true,
},
status: {
/**
*
* QR code status
*
* @default undefined
*/
type: String as PropType<QRCodeStatus>,
},
errorDescription: {
/**
*
* QR code error description label
*
* @default
*/
type: [String, Object] as PropType<string | VNode>,
default: '二维码已过期',
},
errorActionDescription: {
/**
*
* QR code error action description label
*
* @default
*/
type: String,
default: '重新加载',
},
text: {
/**
*
* Text to be encoded in the QR code
*/
type: String,
required: true,
},
size: {
/**
*
* Size of the QR code in pixel.
*
* @default 160
*/
type: Number,
default: 160,
},
margin: {
/**
*
* Size of margins around the QR code body in pixel.
*
* @default 12
*/
type: Number,
default: 12,
},
correctLevel: {
/**
*
* Error correction level of the QR code
* Accepts a value provided by _QRErrorCorrectLevel_
*
* @default 1
*/
type: Number as PropType<QRCodeLevel>,
default: 1,
validator: (value: unknown) => [0, 1, 2, 3].includes(value as number),
},
maskPattern: {
/**
*
* Specify the mask pattern to be used in QR code encoding
* Accepts a value provided by _QRMaskPattern_
*/
type: Number,
},
version: {
/**
*
* Specify the version to be used in QR code encoding
* Accepts an integer in range [1, 40]
*/
type: Number,
},
components: {
/**
*
* Options to control components in the QR code.
*
* @default {data:{scale...},...}
*/
type: Object as PropType<Options['components']>,
default: () => ({
data: {
scale: 1,
},
timing: {
scale: 1,
protectors: false,
},
alignment: {
scale: 1,
protectors: false,
},
cornerAlignment: {
scale: 1,
protectors: true,
},
}),
},
colorDark: {
/**
*
* Color of the blocks on the QR code
* Accepts a CSS &lt;color&gt;
*
* @default #000000
*/
type: String,
default: '#000000',
},
colorLight: {
/**
*
* Color of the blocks on the QR code
* Accepts a CSS &lt;color&gt;
*
* @default #ffffff
*/
type: String,
default: '#ffffff',
},
autoColor: {
/**
*
* Automatically calculate the _colorLight_ value from the QR code's background
*
* @default true
*/
type: Boolean,
default: true,
},
backgroundImage: {
/**
*
* Background image to be used in the QR code
* Accepts a `data:` string in web browsers or a Buffer in Node.js
*
* @default undefined
*/
type: String,
},
backgroundDimming: {
/**
*
* Color of the dimming mask above the background image
* Accepts a CSS &lt;color&gt;
*
* @default rgba(0, 0, 0, 0)
*/
type: String,
default: 'rgba(0, 0, 0, 0)',
},
gifBackground: {
/**
*
* GIF background image to be used in the QR code
*
* @default undefined
*/
type: ArrayBuffer,
},
whiteMargin: {
/**
*
* Use a white margin instead of a transparent one which reveals the background of the QR code on margins
*
* @default true
*/
type: Boolean,
default: true,
},
logoImage: {
/**
*
* Logo image to be displayed at the center of the QR code
* Accepts a `data:` string in web browsers or a Buffer in Node.js
* When set to `undefined` or `null`, the logo is disabled
*
* @default undefined
*/
type: String,
},
logoScale: {
/**
*
* Ratio of the logo size to the QR code size
*
* @default 0.4
*/
type: Number,
default: 0.4,
},
logoMargin: {
/**
*
* Size of margins around the logo image in pixels
*
* @default 6
*/
type: Number,
default: 6,
},
logoCornerRadius: {
/**
* Corner radius of the logo image in pixels.
*
* @default 8
*/
type: Number,
default: 8,
},
onSuccess: {
/**
*
* When the QR code is successfully generated, this callback is called
*/
type: [Function, Array] as PropType<
MaybeArray<(dataURL: ArrayBuffer | string | undefined) => void>
>,
default: null,
},
onError: {
/**
*
* When the QR code generation fails, this callback is called
*/
type: [Function, Array] as PropType<MaybeArray<(e: unknown) => void>>,
default: null,
},
onReload: {
/**
*
* When reload button is clicked, this callback is called
* This method will not execute if the errorAction slot is used
*/
type: [Function, Array] as PropType<MaybeArray<() => void>>,
default: null,
},
}
export default props

View File

@ -0,0 +1,26 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-29
*
* @workspace ray-template
*
* @remark
*/
export type QRCodeStatus = 'error' | 'success' | 'loading'
export type QRCodeLevel = 0 | 1 | 2 | 3
export type QRCodeRenderResponse = string | ArrayBuffer | Buffer | undefined
export type QRCodeInst = {
/**
*
* @param fileName file name
*
* .png
*/
downloadQRCode: (fileName?: string) => void
}

View File

@ -0,0 +1,17 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'
const qrcode: AppRouteRecordRaw = {
path: '/qrcode',
name: 'RQRCode',
component: () => import('@/views/demo/qrcode/index'),
meta: {
noLocalTitle: '二维码',
icon: 'other',
order: 3,
},
}
export default qrcode

View File

@ -33,6 +33,22 @@ export const arrayBufferToBase64Image = (data: ArrayBuffer): string | null => {
return base64
}
/**
*
* @param base64 base64
* @param fileName file name
*
* @remark base64
*/
export const downloadBase64File = (base64: string, fileName?: string) => {
const link = document.createElement('a')
link.href = base64
link.download = fileName || new Date().getTime() + '.png'
link.click()
}
/**
*
* @param value

View File

@ -0,0 +1,104 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-08-30
*
* @workspace ray-template
*
* @remark
*/
import { NSpace, NCard, NButton } from 'naive-ui'
import RayQRcode from '@/components/RayQRCode/index'
import LOGO from '@/assets/images/ray.svg'
import type { QRCodeStatus, QRCodeInst } from '@/components/RayQRCode/index'
const RQRCode = defineComponent({
name: 'RQRCode',
setup() {
const qrcodeText = ref('ray template yes')
const qrcodeStatus = ref<QRCodeStatus | undefined>()
const rayQRCodeRef = ref<QRCodeInst>()
return {
qrcodeText,
qrcodeStatus,
rayQRCodeRef,
}
},
render() {
return (
<NSpace wrapItem={false}>
<NCard>
<h2>
awesome-qr LOGOgifbackgroundImage
</h2>
<h2>watchText</h2>
<h2>使 props </h2>
</NCard>
<NCard title="基础二维码">
<NSpace>
<RayQRcode text="ray template yes" />
<RayQRcode text="ray template yes" logoImage={LOGO} />
</NSpace>
</NCard>
<NCard title="状态二维码">
<NSpace>
<RayQRcode
text="ray template yes"
logoImage={LOGO}
status="error"
onReload={() => {
window.$message.error('relod props')
}}
/>
<RayQRcode
text="ray template yes"
logoImage={LOGO}
status="loading"
/>
</NSpace>
</NCard>
<NCard title="监听内容变化">
<NSpace vertical>
<NSpace>
<NButton
onClick={() => {
this.qrcodeStatus = 'loading'
setTimeout(() => {
this.qrcodeText = 'text updated: ' + new Date().getTime()
this.qrcodeStatus = void 0
}, 1000)
}}
>
</NButton>
<NButton
onClick={() => {
this.rayQRCodeRef?.downloadQRCode()
}}
>
</NButton>
</NSpace>
<NSpace>
<RayQRcode
text={this.qrcodeText}
status={this.qrcodeStatus}
logoImage={LOGO}
ref="rayQRCodeRef"
/>
{this.qrcodeText}
</NSpace>
</NSpace>
</NCard>
</NSpace>
)
},
})
export default RQRCode

View File

@ -11,7 +11,9 @@
import './index.scss'
import QRCode from 'qrcode.vue'
import RayQRcode from '@/components/RayQRCode/index'
import LOGO from '@/assets/images/ray.svg'
/**
*
@ -34,7 +36,7 @@ const QRCodeSignin = defineComponent({
render() {
return (
<div class="qrcode-signin">
<QRCode value={this.qrcodeValue} size={200} />
<RayQRcode text="ray template yes" size={200} logoImage={LOGO} />
</div>
)
},

1
src/vite-env.d.ts vendored
View File

@ -2,6 +2,7 @@
/// <reference types="vite/client" />
/// <reference types="vue/macros-global" />
/// <reference types="vite-svg-loader" />
/// <reference types="./types/app.d.ts" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'

View File

@ -8,6 +8,7 @@
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"acceptHMRUpdate": true,
"asyncComputed": true,
"autoResetRef": true,
@ -121,10 +122,12 @@
"useArrayFilter": true,
"useArrayFind": true,
"useArrayFindIndex": true,
"useArrayFindLast": true,
"useArrayJoin": true,
"useArrayMap": true,
"useArrayReduce": true,
"useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
@ -136,6 +139,7 @@
"useBrowserLocation": true,
"useCached": true,
"useClipboard": true,
"useCloned": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
@ -212,11 +216,14 @@
"useParallax": true,
"usePermission": true,
"usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredContrast": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
@ -230,6 +237,7 @@
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSorted": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,

View File

@ -118,10 +118,12 @@ declare global {
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
const useArraySome: typeof import('@vueuse/core')['useArraySome']
const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
@ -133,6 +135,7 @@ declare global {
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCached: typeof import('@vueuse/core')['useCached']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCounter: typeof import('@vueuse/core')['useCounter']
@ -209,11 +212,14 @@ declare global {
const useParallax: typeof import('@vueuse/core')['useParallax']
const usePermission: typeof import('@vueuse/core')['usePermission']
const usePointer: typeof import('@vueuse/core')['usePointer']
const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
@ -227,6 +233,7 @@ declare global {
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
const useShare: typeof import('@vueuse/core')['useShare']
const useSlots: typeof import('vue')['useSlots']
const useSorted: typeof import('@vueuse/core')['useSorted']
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
const useStepper: typeof import('@vueuse/core')['useStepper']
@ -284,5 +291,5 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue'
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
}

View File

@ -105,7 +105,7 @@ export default defineConfig(async ({ mode }) => {
viteCompression(),
viteVueI18nPlugin(),
viteSvgLoader({
defaultImport: 'component', // 默认以 `componetn` 形式导入 `svg`
defaultImport: 'url', // 默认以 `componetn` 形式导入 `svg`
}),
viteSVGIcon(),
viteEslint({