mirror of
https://github.com/fantastic-admin/basic.git
synced 2026-10-07 01:13:28 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b504024ddc | ||
|
|
a2ee25e900 | ||
|
|
bf27f7f980 | ||
|
|
699b6d5e4e | ||
|
|
c61a9caa44 | ||
|
|
24348a70b2 | ||
|
|
c7dc819d06 | ||
|
|
c0cd2ffc9f | ||
|
|
6ebdea493c | ||
|
|
05e3e6141b | ||
|
|
57f98e7bb1 | ||
|
|
29618d2816 | ||
|
|
7277861ade | ||
|
|
f1c0258676 | ||
|
|
410ce626a8 | ||
|
|
574d0fcccd | ||
|
|
f6516782c0 | ||
|
|
445e6c9e33 | ||
|
|
2646930feb | ||
|
|
eb4538c753 | ||
|
|
4e5bfb923d | ||
|
|
67656e5943 | ||
|
|
bd4bec9a9e | ||
|
|
26b5c165e3 | ||
|
|
58452d656c | ||
|
|
749c55edbc | ||
|
|
40cab5efa3 | ||
|
|
5f9a01fd29 | ||
|
|
a77416fbbe | ||
|
|
2302186258 | ||
|
|
f7789a4791 | ||
|
|
474c11d9ea | ||
|
|
5356dbeee4 | ||
|
|
e057f01edb | ||
|
|
b4b68d78ea | ||
|
|
1b0dc3b947 | ||
|
|
244e6cb4fa | ||
|
|
ded93e90b7 | ||
|
|
70b29edb6e | ||
|
|
fc2c89fa2d | ||
|
|
5ba6d08df3 | ||
|
|
c0bc31f7f4 | ||
|
|
871dd5c56f | ||
|
|
caedad8e72 | ||
|
|
bb3bd479b8 | ||
|
|
931b10c1f3 | ||
|
|
5e2558ac05 | ||
|
|
81beda6e56 | ||
|
|
1d86ef87d3 | ||
|
|
d0dc9275b3 | ||
|
|
1ccbd6402b | ||
|
|
84eb9b7a39 | ||
|
|
5e023d9055 | ||
|
|
cf4a7eae7d | ||
|
|
42b7ab33c6 | ||
|
|
85eefe75bb | ||
|
|
0bcea9d3c8 | ||
|
|
38e6abab21 | ||
|
|
1c81115605 | ||
|
|
e55e94743f | ||
|
|
efb0886e10 |
+4
-55
@@ -1,5 +1,5 @@
|
||||
[中文](./readme.md) | **English**
|
||||
<img src="https://fantastic-admin.hurui.me/logo.svg" align="right" width="80" height="80" alt="logo" />
|
||||
<a href="https://fantastic-admin.hurui.me" target="_blank"><img src="https://fantastic-admin.hurui.me/logo.svg" align="right" height="80" alt="logo" /></a>
|
||||
|
||||
# Fantastic-admin
|
||||
|
||||
@@ -56,57 +56,6 @@ If you find Fantastic-admin useful, or you are already using it, please consider
|
||||
|
||||
## Ecosystem
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="3" align="center">
|
||||
<a href="https://hooray.github.io/fantastic-startkit/" target="_blank">Fantastic-startkit</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3" align="center">
|
||||
A simple and easy-to-use Vue 3 project starter kit
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="3" align="center">
|
||||
<a href="https://one-step-admin.hurui.me" target="_blank">One-step-admin</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3" align="center">
|
||||
A Vue admin framework built to help you move faster than the rest
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview1.png" alt="" /></td>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview2.png" alt="" /></td>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview3.png" alt="" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview4.png" alt="" /></td>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview5.png" alt="" /></td>
|
||||
<td><img src="https://one-step-admin.hurui.me/preview6.png" alt="" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="4" align="center">
|
||||
<a href="https://fantastic-mobile.hurui.me" target="_blank">Fantastic-mobile</a>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="4" align="center">
|
||||
A distinctive mobile H5 framework
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://fantastic-mobile.hurui.me/preview1.png" alt="" /></td>
|
||||
<td><img src="https://fantastic-mobile.hurui.me/preview2.png" alt="" /></td>
|
||||
<td><img src="https://fantastic-mobile.hurui.me/preview3.png" alt="" /></td>
|
||||
<td><img src="https://fantastic-mobile.hurui.me/preview4.png" alt="" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
- [`Fantastic-startkit`](https://hooray.github.io/fantastic-startkit/) - A simple and easy-to-use Vue 3 project starter kit
|
||||
- [`Fantastic-mobile`](https://fantastic-mobile.hurui.me/) - Let your H5 project have a solid engineering base
|
||||
- [`One-step-admin`](https://one-step-admin.hurui.me) - A Vue admin framework built to help you move faster than the rest
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
**中文** | [English](./README.EN.md)
|
||||
<img src="https://fantastic-admin.hurui.me/logo.svg" align="right" width="80" height="80" alt="logo" />
|
||||
<a href="https://fantastic-admin.hurui.me" target="_blank"><img src="https://fantastic-admin.hurui.me/logo.svg" align="right" height="80" alt="logo" /></a>
|
||||
|
||||
# Fantastic-admin
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
- AI 友好的工程底座,内置多个 Skills
|
||||
- 一流的技术栈:Vue 3.6 / Vite 8 / Pinia / UnoCSS / VueUse / TypeScript / ESLint / Stylelint / ...
|
||||
- 自由选择喜爱的 UI 库,默认 Element Plus
|
||||
- 8 套默认主题方案且可扩展,给不同行业提供专属品牌气质
|
||||
- 18 套默认主题方案且可扩展,给不同行业提供专属品牌气质
|
||||
- 7 款导航菜单模式,匹配产品发展的各个阶段
|
||||
- 精细可控的页面保活策略
|
||||
- 全方位权限验证
|
||||
@@ -58,4 +58,4 @@
|
||||
|
||||
- [`Fantastic-startkit`](https://hooray.github.io/fantastic-startkit/) - 简单好用的 Vue3 项目启动套件
|
||||
- [`Fantastic-mobile`](https://fantastic-mobile.hurui.me/) - 让你的 H5 项目拥有稳固的工程底座
|
||||
- [`One-step-admin`](https://one-step-admin.hurui.me) - 干啥都快人一步的 Vue 中后台管理系统框架
|
||||
- [`One-step Console`](https://one-step-admin.hurui.me) - 像导播一样编排你的工作现场
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
"serve": "http-server ./dist -o",
|
||||
"serve:test": "http-server ./dist-test -o",
|
||||
"svgo": "svgo -f src/assets/icons",
|
||||
"generate:icons": "tsx ./scripts/generate.icons.ts",
|
||||
"generate:icons": "fa-iconify-tools",
|
||||
"lint": "vue-tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fantastic-admin/components": "workspace:*",
|
||||
"@fantastic-admin/composables": "workspace:*",
|
||||
"@fantastic-admin/settings": "workspace:*",
|
||||
"@fantastic-admin/types": "workspace:*",
|
||||
"@vee-validate/zod": "catalog:",
|
||||
@@ -28,7 +29,6 @@
|
||||
"eruda": "catalog:",
|
||||
"es-toolkit": "catalog:",
|
||||
"hotkeys-js": "catalog:",
|
||||
"lucide-vue-next": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"path-browserify": "catalog:",
|
||||
@@ -49,9 +49,9 @@
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "catalog:",
|
||||
"@faker-js/faker": "catalog:",
|
||||
"@fantastic-admin/copyright": "workspace:*",
|
||||
"@fantastic-admin/iconify-tools": "workspace:*",
|
||||
"@iconify/vue": "catalog:",
|
||||
"@spiriit/vite-plugin-svg-spritemap": "catalog:",
|
||||
"@types/nprogress": "catalog:",
|
||||
@@ -66,7 +66,6 @@
|
||||
"postcss-nested": "catalog:",
|
||||
"sass-embedded": "catalog:",
|
||||
"svgo": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"unplugin-auto-import": "catalog:",
|
||||
"unplugin-turbo-console": "catalog:",
|
||||
"unplugin-vue-components": "catalog:",
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import * as p from '@clack/prompts'
|
||||
import { lookupCollection, lookupCollections } from '@iconify/json'
|
||||
|
||||
// 拿到全部图标集的原始数据
|
||||
const raw = await lookupCollections()
|
||||
|
||||
let lastChoose = fs.readFileSync(path.resolve(process.cwd(), 'src/iconify/index.json'), 'utf-8')
|
||||
lastChoose = JSON.parse(lastChoose)
|
||||
|
||||
// 取出可使用的图标集数据用于选择,并按名称排序
|
||||
const collections = Object.entries(raw).map(([id, item]) => ({
|
||||
...item,
|
||||
id,
|
||||
})).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
p.intro('图标集生成工具')
|
||||
|
||||
/**
|
||||
* 分别会在对应目录下生成以下文件,其中(1)(3)用于离线下载并安装图标,(2)用于图标选择器使用
|
||||
* (1) src/iconify/index.json 记录用户交互信息
|
||||
* (2) src/iconify/data.json 包含多个图标集数据,仅记录图标名
|
||||
* (3) public/icons/*-raw.json 多个图标集的原始数据,独立存放,用于离线使用
|
||||
*/
|
||||
const answers = await p.group(
|
||||
{
|
||||
collections: () =>
|
||||
p.multiselect({
|
||||
message: '请选择需要生成的图标集',
|
||||
options: collections.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
hint: `${item.total} 个图标`,
|
||||
})),
|
||||
initialValues: lastChoose.collections,
|
||||
}),
|
||||
isOfflineUse: () =>
|
||||
p.confirm({
|
||||
message: '是否需要离线使用',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('操作已取消')
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const spinner = p.spinner()
|
||||
spinner.start('正在生成图标集...')
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/index.json'),
|
||||
{
|
||||
collections: answers.collections,
|
||||
isOfflineUse: answers.isOfflineUse,
|
||||
},
|
||||
)
|
||||
|
||||
const outputDir = path.resolve(process.cwd(), 'public/icons')
|
||||
await fs.ensureDir(outputDir)
|
||||
await fs.emptyDir(outputDir)
|
||||
|
||||
const collectionsMeta: object[] = []
|
||||
for (const info of answers.collections) {
|
||||
const setData = await lookupCollection(info)
|
||||
|
||||
collectionsMeta.push({
|
||||
prefix: setData.prefix,
|
||||
info: setData.info,
|
||||
icons: Object.keys(setData.icons),
|
||||
})
|
||||
|
||||
const offlineFilePath = path.join(outputDir, `${info}-raw.json`)
|
||||
|
||||
if (answers.isOfflineUse) {
|
||||
await fs.writeJSON(offlineFilePath, setData)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/data.json'),
|
||||
collectionsMeta,
|
||||
)
|
||||
|
||||
// 使用 spawn 运行 eslint
|
||||
const eslint = spawn('eslint', ['src/iconify/data.json', 'src/iconify/index.json', '--cache', '--fix'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
})
|
||||
|
||||
eslint.on('error', (err) => {
|
||||
p.log.error(`ESLint 执行失败: ${err.message}`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
eslint.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
p.log.error(`ESLint 执行失败,退出码: ${code}`)
|
||||
process.exit(code)
|
||||
}
|
||||
spinner.stop('图标集生成完成!')
|
||||
})
|
||||
@@ -51,7 +51,7 @@ function handleError(error: any) {
|
||||
useAppAccountStore().requestLogout()
|
||||
}
|
||||
else {
|
||||
faToast.error('Error', {
|
||||
useFaToast().error('Error', {
|
||||
description: error.message,
|
||||
})
|
||||
}
|
||||
@@ -70,7 +70,7 @@ api.interceptors.response.use(
|
||||
if (typeof response.data === 'object') {
|
||||
if (response.data.status === 1) {
|
||||
if (response.data.error) {
|
||||
faToast.warning('Warning', {
|
||||
useFaToast().warning('Warning', {
|
||||
description: response.data.error,
|
||||
})
|
||||
return Promise.reject(response.data)
|
||||
|
||||
@@ -32,7 +32,7 @@ const form = useForm({
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
loading.value = true
|
||||
appAccountStore.editPassword(values).then(async () => {
|
||||
faToast.success('模拟修改成功,请重新登录')
|
||||
useFaToast().success('模拟修改成功,请重新登录')
|
||||
appAccountStore.logout()
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
@@ -61,7 +61,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -75,7 +75,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -89,7 +89,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -90,7 +90,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -104,7 +104,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -113,7 +113,7 @@ function testAccount(account: string) {
|
||||
<FormField v-slot="{ componentField }" type="checkbox" name="remember">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<FaCheckbox v-bind="componentField">
|
||||
<FaCheckbox :model-value="componentField.modelValue" @update:model-value="componentField['onUpdate:modelValue']?.($event)">
|
||||
记住我
|
||||
</FaCheckbox>
|
||||
</FormControl>
|
||||
|
||||
@@ -63,7 +63,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,11 +76,11 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</template>
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<FormDescription class="m-0">
|
||||
<FaPasswordStrength :password="value" />
|
||||
</FormDescription>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -94,7 +94,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -70,7 +70,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -81,7 +81,7 @@ function handleSendCaptcha() {
|
||||
<FaInputOTP :model-value="value" :name="componentField.name" :length="6" class="border-destructive" @update:model-value="val => setValue(val)" />
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -99,7 +99,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -80,13 +80,13 @@ export function useAppTabbar() {
|
||||
const index = appTabbarStore.list.findIndex(item => item.tabId === tabId)
|
||||
if (index < 0) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('关闭的标签页不存在', {
|
||||
!checkOnly && useFaToast().warning('关闭的标签页不存在', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
else if (appTabbarStore.list.length <= 1) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('当前只有一个标签页,不可关闭', {
|
||||
!checkOnly && useFaToast().warning('当前只有一个标签页,不可关闭', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
export function usePagination() {
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
sort: null as string | null,
|
||||
order: null as string | null,
|
||||
})
|
||||
|
||||
function getParams() {
|
||||
return {
|
||||
// page,size 和 from,limit 是分页的两种方式,方便兼容两种接口
|
||||
page: pagination.value.page,
|
||||
size: pagination.value.size,
|
||||
from: (pagination.value.page - 1) * pagination.value.size,
|
||||
limit: pagination.value.size,
|
||||
...(
|
||||
pagination.value.sort && pagination.value.order && {
|
||||
sort: pagination.value.sort,
|
||||
order: pagination.value.order,
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async function onSizeChange(size: number) {
|
||||
pagination.value.size = size
|
||||
}
|
||||
|
||||
async function onCurrentChange(page: number) {
|
||||
pagination.value.page = page
|
||||
}
|
||||
|
||||
async function onSortChange(prop: string, order: string) {
|
||||
pagination.value.sort = prop
|
||||
pagination.value.order = order === 'ascending' ? 'asc' : 'desc'
|
||||
}
|
||||
|
||||
return {
|
||||
pagination,
|
||||
getParams,
|
||||
onSizeChange,
|
||||
onCurrentChange,
|
||||
onSortChange,
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -53,7 +53,7 @@ function handleCopy() {
|
||||
'columns-2': appSettingsStore.mode === 'pc',
|
||||
}"
|
||||
>
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
颜色方案
|
||||
@@ -83,7 +83,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.theme.colorAmblyopia" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="menu-mode">
|
||||
<FaTooltip text="侧边栏模式 (有主导航菜单)" :delay="500">
|
||||
<FaButton variant="outline" class="mode mode-side" :class="{ active: appSettingsStore.settings.menu.mode === 'side' }" @click="appSettingsStore.settings.menu.mode = 'side'">
|
||||
@@ -145,7 +145,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.menu.hotkeys" :disabled="appSettingsStore.settings.menu.mode === 'single'" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
标签栏
|
||||
@@ -175,7 +175,7 @@ function handleCopy() {
|
||||
</FaButtonGroup>
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
显示图标
|
||||
@@ -189,7 +189,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.tabbar.hotkeys" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div v-if="appSettingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
<FaIcon name="i-ic:twotone-double-arrow" />
|
||||
@@ -237,7 +237,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.toolbar.colorScheme" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
载入进度条
|
||||
@@ -248,7 +248,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.page.progress" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="p-4 pb-4 pt-14 border rounded-lg relative space-y-4">
|
||||
<div class="font-bold px-4 py-2 border-b border-e rounded-rb-lg inset-s-0 inset-t-0 absolute">
|
||||
账号
|
||||
|
||||
@@ -72,13 +72,13 @@ watch(() => route, (val) => {
|
||||
function tabbarScrollTip() {
|
||||
if (tabContainerRef.value?.$el.clientWidth > (tabsRef.value?.ref?.$el.clientWidth ?? 0) && !localStorage.has('tabbarScrollTip')) {
|
||||
localStorage.setItem('tabbarScrollTip', '')
|
||||
const tips = faToast.info('温馨提示', {
|
||||
const tips = useFaToast().info('温馨提示', {
|
||||
description: '标签栏数量超过展示区域范围,可以将鼠标移到标签栏上,通过鼠标滚轮滑动浏览',
|
||||
position: 'top-center',
|
||||
duration: Infinity,
|
||||
action: {
|
||||
label: '知道了',
|
||||
onClick: () => faToast.dismiss(tips),
|
||||
onClick: () => useFaToast().dismiss(tips),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+10
-8
@@ -8,13 +8,15 @@ const mainPage = useAppPage()
|
||||
|
||||
const isAnimating = ref(false)
|
||||
|
||||
function handleClick() {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
|
||||
function handleCtrlClick() {
|
||||
location.reload()
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
location.reload()
|
||||
return
|
||||
}
|
||||
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,7 +30,7 @@ function handleCtrlClick() {
|
||||
<p>可切换为浏览器原生刷新</p>
|
||||
</div>
|
||||
</template>
|
||||
<FaButton variant="ghost" size="icon-sm" @click.exact="handleClick" @click.ctrl.exact="handleCtrlClick" @animationend="isAnimating = false">
|
||||
<FaButton variant="ghost" size="icon-sm" @click="handleClick" @animationend="isAnimating = false">
|
||||
<FaIcon name="i-iconoir:refresh-double" class="size-4" :class="{ animation: isAnimating }" />
|
||||
</FaButton>
|
||||
</FaTooltip>
|
||||
|
||||
@@ -8,7 +8,7 @@ defineOptions({
|
||||
const route = useRoute()
|
||||
const { copy, copied } = useClipboard()
|
||||
watch(copied, (val) => {
|
||||
val && faToast.success('复制成功')
|
||||
val && useFaToast().success('复制成功')
|
||||
})
|
||||
|
||||
function open() {
|
||||
|
||||
@@ -110,7 +110,7 @@ function extendClose(router: Router) {
|
||||
}
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface Router {
|
||||
interface _RouterClassic {
|
||||
/**
|
||||
* 本方法为框架扩展语法,会同时关闭当前标签页
|
||||
*
|
||||
|
||||
@@ -94,16 +94,6 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
await apiApp.passwordEdit(data)
|
||||
}
|
||||
|
||||
// 锁屏
|
||||
function lock() {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
// 解锁
|
||||
function unlock() {
|
||||
localStorage.setItem('token', token.value)
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
account,
|
||||
@@ -115,7 +105,5 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
requestLogout,
|
||||
getPermissions,
|
||||
editPassword,
|
||||
lock,
|
||||
unlock,
|
||||
}
|
||||
})
|
||||
|
||||
+2
-2
@@ -16,7 +16,6 @@ declare global {
|
||||
const defineComponent: typeof import('vue').defineComponent
|
||||
const defineStore: typeof import('pinia').defineStore
|
||||
const effectScope: typeof import('vue').effectScope
|
||||
const faToast: typeof import('@fantastic-admin/components').faToast
|
||||
const getActivePinia: typeof import('pinia').getActivePinia
|
||||
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||
@@ -84,10 +83,11 @@ declare global {
|
||||
const useFaDrawer: typeof import('@fantastic-admin/components').useFaDrawer
|
||||
const useFaImagePreview: typeof import('@fantastic-admin/components').useFaImagePreview
|
||||
const useFaModal: typeof import('@fantastic-admin/components').useFaModal
|
||||
const useFaToast: typeof import('@fantastic-admin/components').useFaToast
|
||||
const useId: typeof import('vue').useId
|
||||
const useLink: typeof import('vue-router').useLink
|
||||
const useModel: typeof import('vue').useModel
|
||||
const usePagination: typeof import('../composables/pagination').usePagination
|
||||
const usePagination: typeof import('@fantastic-admin/composables').usePagination
|
||||
const useRoute: typeof import('vue-router').useRoute
|
||||
const useRouter: typeof import('vue-router').useRouter
|
||||
const useSlots: typeof import('vue').useSlots
|
||||
|
||||
@@ -19,13 +19,17 @@ declare module 'vue' {
|
||||
AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -48,12 +52,15 @@ declare module 'vue' {
|
||||
FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
@@ -70,13 +77,17 @@ declare global {
|
||||
const AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
const AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
const AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
const FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
const FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
const FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
const FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
const FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
const FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
const FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
const FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
const FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
const FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
const FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
const FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
const FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
const FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -99,12 +110,15 @@ declare global {
|
||||
const FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
const FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
const FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
const FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
const FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
const FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
const FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
const FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
const FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
const FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
const FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
const FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
const FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
const FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
const FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
|
||||
@@ -33,12 +33,12 @@ const products = ref([
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'One-step-admin',
|
||||
tagline: '干啥都快人一步的 Vue 中后台系统框架',
|
||||
name: 'One-step Console',
|
||||
tagline: '像导播一样编排你的工作现场',
|
||||
logo: 'https://one-step-admin.hurui.me/logo.png',
|
||||
url: 'https://one-step-admin.hurui.me',
|
||||
images: [
|
||||
'https://one-step-admin.hurui.me/preview1.png',
|
||||
'https://one-step-admin.hurui.me/hero_preview.png',
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
@@ -47,7 +47,10 @@ export default defineConfig(({ mode, command }) => {
|
||||
},
|
||||
plugins: createVitePlugins(mode, command === 'build'),
|
||||
optimizeDeps: {
|
||||
exclude: ['@fantastic-admin/components'],
|
||||
exclude: [
|
||||
'@fantastic-admin/components',
|
||||
'@fantastic-admin/composables',
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PluginOption } from 'vite'
|
||||
import process from 'node:process'
|
||||
import { FantasticAutoImports, FantasticComponentsResolver, FantasticComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import { ComponentsAutoImports as FantasticAdminComponentsAutoImports, ComponentsResolver as FantasticAdminComponentsResolver, ComponentsType as FantasticAdminComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { ComposablesAutoImports as FantasticAdminComposablesAutoImports } from '@fantastic-admin/composables/resolver'
|
||||
import { createCopyrightPlugins as createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import VitePluginSvgSpritemap from '@spiriit/vite-plugin-svg-spritemap'
|
||||
import vueLegacy from '@vitejs/plugin-legacy'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -37,6 +38,7 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
launchEditor: viteEnv.VITE_LAUNCH_EDITOR,
|
||||
}),
|
||||
|
||||
// https://github.com/yue1123/vite-plugin-env-parse
|
||||
envParse({
|
||||
dtsPath: 'src/types/env.d.ts',
|
||||
}),
|
||||
@@ -47,7 +49,8 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
'vue',
|
||||
'vue-router',
|
||||
'pinia',
|
||||
FantasticAutoImports,
|
||||
FantasticAdminComponentsAutoImports,
|
||||
FantasticAdminComposablesAutoImports,
|
||||
],
|
||||
dts: './src/types/auto-imports.d.ts',
|
||||
dirs: [
|
||||
@@ -63,10 +66,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
],
|
||||
dts: './src/types/components.d.ts',
|
||||
resolvers: [
|
||||
FantasticComponentsResolver(),
|
||||
FantasticAdminComponentsResolver(),
|
||||
],
|
||||
types: [
|
||||
FantasticComponentsType,
|
||||
FantasticAdminComponentsType,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -78,9 +81,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
// https://github.com/condorheroblog/vite-plugin-fake-server
|
||||
vitePluginFakeServer({
|
||||
logger: !isBuild,
|
||||
include: 'src/api/modules',
|
||||
include: 'src/api/fake_modules',
|
||||
enableProd: isBuild && viteEnv.VITE_BUILD_FAKE,
|
||||
}),
|
||||
|
||||
// https://github.com/nonzzz/vite-plugin-compression
|
||||
viteEnv.VITE_BUILD_COMPRESS && compression({
|
||||
exclude: [/\.(br)$/, /\.(gz)$/],
|
||||
@@ -105,7 +109,6 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
(() => {
|
||||
const moduleId = 'virtual:fantastic-admin/turbo-console'
|
||||
const resolvedModuleId = `\0${moduleId}`
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-turbo-console-bridge',
|
||||
resolveId(id) {
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
"serve": "http-server ./dist -o",
|
||||
"serve:test": "http-server ./dist-test -o",
|
||||
"svgo": "svgo -f src/assets/icons",
|
||||
"generate:icons": "tsx ./scripts/generate.icons.ts",
|
||||
"generate:icons": "fa-iconify-tools",
|
||||
"lint": "vue-tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fantastic-admin/components": "workspace:*",
|
||||
"@fantastic-admin/composables": "workspace:*",
|
||||
"@fantastic-admin/settings": "workspace:*",
|
||||
"@fantastic-admin/types": "workspace:*",
|
||||
"@vee-validate/zod": "catalog:",
|
||||
@@ -28,7 +29,6 @@
|
||||
"eruda": "catalog:",
|
||||
"es-toolkit": "catalog:",
|
||||
"hotkeys-js": "catalog:",
|
||||
"lucide-vue-next": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"path-browserify": "catalog:",
|
||||
@@ -49,9 +49,9 @@
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "catalog:",
|
||||
"@faker-js/faker": "catalog:",
|
||||
"@fantastic-admin/copyright": "workspace:*",
|
||||
"@fantastic-admin/iconify-tools": "workspace:*",
|
||||
"@iconify/vue": "catalog:",
|
||||
"@spiriit/vite-plugin-svg-spritemap": "catalog:",
|
||||
"@types/nprogress": "catalog:",
|
||||
@@ -66,7 +66,6 @@
|
||||
"postcss-nested": "catalog:",
|
||||
"sass-embedded": "catalog:",
|
||||
"svgo": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"unplugin-auto-import": "catalog:",
|
||||
"unplugin-turbo-console": "catalog:",
|
||||
"unplugin-vue-components": "catalog:",
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import * as p from '@clack/prompts'
|
||||
import { lookupCollection, lookupCollections } from '@iconify/json'
|
||||
|
||||
// 拿到全部图标集的原始数据
|
||||
const raw = await lookupCollections()
|
||||
|
||||
let lastChoose = fs.readFileSync(path.resolve(process.cwd(), 'src/iconify/index.json'), 'utf-8')
|
||||
lastChoose = JSON.parse(lastChoose)
|
||||
|
||||
// 取出可使用的图标集数据用于选择,并按名称排序
|
||||
const collections = Object.entries(raw).map(([id, item]) => ({
|
||||
...item,
|
||||
id,
|
||||
})).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
p.intro('图标集生成工具')
|
||||
|
||||
/**
|
||||
* 分别会在对应目录下生成以下文件,其中(1)(3)用于离线下载并安装图标,(2)用于图标选择器使用
|
||||
* (1) src/iconify/index.json 记录用户交互信息
|
||||
* (2) src/iconify/data.json 包含多个图标集数据,仅记录图标名
|
||||
* (3) public/icons/*-raw.json 多个图标集的原始数据,独立存放,用于离线使用
|
||||
*/
|
||||
const answers = await p.group(
|
||||
{
|
||||
collections: () =>
|
||||
p.multiselect({
|
||||
message: '请选择需要生成的图标集',
|
||||
options: collections.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
hint: `${item.total} 个图标`,
|
||||
})),
|
||||
initialValues: lastChoose.collections,
|
||||
}),
|
||||
isOfflineUse: () =>
|
||||
p.confirm({
|
||||
message: '是否需要离线使用',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('操作已取消')
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const spinner = p.spinner()
|
||||
spinner.start('正在生成图标集...')
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/index.json'),
|
||||
{
|
||||
collections: answers.collections,
|
||||
isOfflineUse: answers.isOfflineUse,
|
||||
},
|
||||
)
|
||||
|
||||
const outputDir = path.resolve(process.cwd(), 'public/icons')
|
||||
await fs.ensureDir(outputDir)
|
||||
await fs.emptyDir(outputDir)
|
||||
|
||||
const collectionsMeta: object[] = []
|
||||
for (const info of answers.collections) {
|
||||
const setData = await lookupCollection(info)
|
||||
|
||||
collectionsMeta.push({
|
||||
prefix: setData.prefix,
|
||||
info: setData.info,
|
||||
icons: Object.keys(setData.icons),
|
||||
})
|
||||
|
||||
const offlineFilePath = path.join(outputDir, `${info}-raw.json`)
|
||||
|
||||
if (answers.isOfflineUse) {
|
||||
await fs.writeJSON(offlineFilePath, setData)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/data.json'),
|
||||
collectionsMeta,
|
||||
)
|
||||
|
||||
// 使用 spawn 运行 eslint
|
||||
const eslint = spawn('eslint', ['src/iconify/data.json', 'src/iconify/index.json', '--cache', '--fix'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
})
|
||||
|
||||
eslint.on('error', (err) => {
|
||||
p.log.error(`ESLint 执行失败: ${err.message}`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
eslint.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
p.log.error(`ESLint 执行失败,退出码: ${code}`)
|
||||
process.exit(code)
|
||||
}
|
||||
spinner.stop('图标集生成完成!')
|
||||
})
|
||||
@@ -51,7 +51,7 @@ function handleError(error: any) {
|
||||
useAppAccountStore().requestLogout()
|
||||
}
|
||||
else {
|
||||
faToast.error('Error', {
|
||||
useFaToast().error('Error', {
|
||||
description: error.message,
|
||||
})
|
||||
}
|
||||
@@ -70,7 +70,7 @@ api.interceptors.response.use(
|
||||
if (typeof response.data === 'object') {
|
||||
if (response.data.status === 1) {
|
||||
if (response.data.error) {
|
||||
faToast.warning('Warning', {
|
||||
useFaToast().warning('Warning', {
|
||||
description: response.data.error,
|
||||
})
|
||||
return Promise.reject(response.data)
|
||||
|
||||
@@ -32,7 +32,7 @@ const form = useForm({
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
loading.value = true
|
||||
appAccountStore.editPassword(values).then(async () => {
|
||||
faToast.success('模拟修改成功,请重新登录')
|
||||
useFaToast().success('模拟修改成功,请重新登录')
|
||||
appAccountStore.logout()
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
@@ -61,7 +61,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -75,7 +75,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -89,7 +89,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -90,7 +90,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -104,7 +104,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -113,7 +113,7 @@ function testAccount(account: string) {
|
||||
<FormField v-slot="{ componentField }" type="checkbox" name="remember">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<FaCheckbox v-bind="componentField">
|
||||
<FaCheckbox :model-value="componentField.modelValue" @update:model-value="componentField['onUpdate:modelValue']?.($event)">
|
||||
记住我
|
||||
</FaCheckbox>
|
||||
</FormControl>
|
||||
|
||||
@@ -63,7 +63,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,11 +76,11 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</template>
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<FormDescription class="m-0">
|
||||
<FaPasswordStrength :password="value" />
|
||||
</FormDescription>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -94,7 +94,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -70,7 +70,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -81,7 +81,7 @@ function handleSendCaptcha() {
|
||||
<FaInputOTP :model-value="value" :name="componentField.name" :length="6" class="border-destructive" @update:model-value="val => setValue(val)" />
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -99,7 +99,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -80,13 +80,13 @@ export function useAppTabbar() {
|
||||
const index = appTabbarStore.list.findIndex(item => item.tabId === tabId)
|
||||
if (index < 0) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('关闭的标签页不存在', {
|
||||
!checkOnly && useFaToast().warning('关闭的标签页不存在', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
else if (appTabbarStore.list.length <= 1) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('当前只有一个标签页,不可关闭', {
|
||||
!checkOnly && useFaToast().warning('当前只有一个标签页,不可关闭', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
export function usePagination() {
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
sort: null as string | null,
|
||||
order: null as string | null,
|
||||
})
|
||||
|
||||
function getParams() {
|
||||
return {
|
||||
// page,size 和 from,limit 是分页的两种方式,方便兼容两种接口
|
||||
page: pagination.value.page,
|
||||
size: pagination.value.size,
|
||||
from: (pagination.value.page - 1) * pagination.value.size,
|
||||
limit: pagination.value.size,
|
||||
...(
|
||||
pagination.value.sort && pagination.value.order && {
|
||||
sort: pagination.value.sort,
|
||||
order: pagination.value.order,
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async function onSizeChange(size: number) {
|
||||
pagination.value.size = size
|
||||
}
|
||||
|
||||
async function onCurrentChange(page: number) {
|
||||
pagination.value.page = page
|
||||
}
|
||||
|
||||
async function onSortChange(prop: string, order: string) {
|
||||
pagination.value.sort = prop
|
||||
pagination.value.order = order === 'ascending' ? 'asc' : 'desc'
|
||||
}
|
||||
|
||||
return {
|
||||
pagination,
|
||||
getParams,
|
||||
onSizeChange,
|
||||
onCurrentChange,
|
||||
onSortChange,
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -53,7 +53,7 @@ function handleCopy() {
|
||||
'columns-2': appSettingsStore.mode === 'pc',
|
||||
}"
|
||||
>
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
颜色方案
|
||||
@@ -83,7 +83,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.theme.colorAmblyopia" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="menu-mode">
|
||||
<FaTooltip text="侧边栏模式 (有主导航菜单)" :delay="500">
|
||||
<FaButton variant="outline" class="mode mode-side" :class="{ active: appSettingsStore.settings.menu.mode === 'side' }" @click="appSettingsStore.settings.menu.mode = 'side'">
|
||||
@@ -145,7 +145,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.menu.hotkeys" :disabled="appSettingsStore.settings.menu.mode === 'single'" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
标签栏
|
||||
@@ -175,7 +175,7 @@ function handleCopy() {
|
||||
</FaButtonGroup>
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
显示图标
|
||||
@@ -189,7 +189,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.tabbar.hotkeys" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div v-if="appSettingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
<FaIcon name="i-ic:twotone-double-arrow" />
|
||||
@@ -237,7 +237,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.toolbar.colorScheme" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
载入进度条
|
||||
@@ -248,7 +248,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.page.progress" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="p-4 pb-4 pt-14 border rounded-lg relative space-y-4">
|
||||
<div class="font-bold px-4 py-2 border-b border-e rounded-rb-lg inset-s-0 inset-t-0 absolute">
|
||||
账号
|
||||
|
||||
@@ -72,13 +72,13 @@ watch(() => route, (val) => {
|
||||
function tabbarScrollTip() {
|
||||
if (tabContainerRef.value?.$el.clientWidth > (tabsRef.value?.ref?.$el.clientWidth ?? 0) && !localStorage.has('tabbarScrollTip')) {
|
||||
localStorage.setItem('tabbarScrollTip', '')
|
||||
const tips = faToast.info('温馨提示', {
|
||||
const tips = useFaToast().info('温馨提示', {
|
||||
description: '标签栏数量超过展示区域范围,可以将鼠标移到标签栏上,通过鼠标滚轮滑动浏览',
|
||||
position: 'top-center',
|
||||
duration: Infinity,
|
||||
action: {
|
||||
label: '知道了',
|
||||
onClick: () => faToast.dismiss(tips),
|
||||
onClick: () => useFaToast().dismiss(tips),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@ const mainPage = useAppPage()
|
||||
|
||||
const isAnimating = ref(false)
|
||||
|
||||
function handleClick() {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
|
||||
function handleCtrlClick() {
|
||||
location.reload()
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
location.reload()
|
||||
return
|
||||
}
|
||||
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,7 +30,7 @@ function handleCtrlClick() {
|
||||
<p>可切换为浏览器原生刷新</p>
|
||||
</div>
|
||||
</template>
|
||||
<FaButton variant="ghost" size="icon-sm" @click.exact="handleClick" @click.ctrl.exact="handleCtrlClick" @animationend="isAnimating = false">
|
||||
<FaButton variant="ghost" size="icon-sm" @click="handleClick" @animationend="isAnimating = false">
|
||||
<FaIcon name="i-iconoir:refresh-double" class="size-4" :class="{ animation: isAnimating }" />
|
||||
</FaButton>
|
||||
</FaTooltip>
|
||||
|
||||
@@ -8,7 +8,7 @@ defineOptions({
|
||||
const route = useRoute()
|
||||
const { copy, copied } = useClipboard()
|
||||
watch(copied, (val) => {
|
||||
val && faToast.success('复制成功')
|
||||
val && useFaToast().success('复制成功')
|
||||
})
|
||||
|
||||
function open() {
|
||||
|
||||
@@ -110,7 +110,7 @@ function extendClose(router: Router) {
|
||||
}
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface Router {
|
||||
interface _RouterClassic {
|
||||
/**
|
||||
* 本方法为框架扩展语法,会同时关闭当前标签页
|
||||
*
|
||||
|
||||
@@ -94,16 +94,6 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
await apiApp.passwordEdit(data)
|
||||
}
|
||||
|
||||
// 锁屏
|
||||
function lock() {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
// 解锁
|
||||
function unlock() {
|
||||
localStorage.setItem('token', token.value)
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
account,
|
||||
@@ -115,7 +105,5 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
requestLogout,
|
||||
getPermissions,
|
||||
editPassword,
|
||||
lock,
|
||||
unlock,
|
||||
}
|
||||
})
|
||||
|
||||
+2
-2
@@ -16,7 +16,6 @@ declare global {
|
||||
const defineComponent: typeof import('vue').defineComponent
|
||||
const defineStore: typeof import('pinia').defineStore
|
||||
const effectScope: typeof import('vue').effectScope
|
||||
const faToast: typeof import('@fantastic-admin/components').faToast
|
||||
const getActivePinia: typeof import('pinia').getActivePinia
|
||||
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||
@@ -84,10 +83,11 @@ declare global {
|
||||
const useFaDrawer: typeof import('@fantastic-admin/components').useFaDrawer
|
||||
const useFaImagePreview: typeof import('@fantastic-admin/components').useFaImagePreview
|
||||
const useFaModal: typeof import('@fantastic-admin/components').useFaModal
|
||||
const useFaToast: typeof import('@fantastic-admin/components').useFaToast
|
||||
const useId: typeof import('vue').useId
|
||||
const useLink: typeof import('vue-router').useLink
|
||||
const useModel: typeof import('vue').useModel
|
||||
const usePagination: typeof import('../composables/pagination').usePagination
|
||||
const usePagination: typeof import('@fantastic-admin/composables').usePagination
|
||||
const useRoute: typeof import('vue-router').useRoute
|
||||
const useRouter: typeof import('vue-router').useRouter
|
||||
const useSlots: typeof import('vue').useSlots
|
||||
|
||||
+14
@@ -19,13 +19,17 @@ declare module 'vue' {
|
||||
AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -48,12 +52,15 @@ declare module 'vue' {
|
||||
FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
@@ -70,13 +77,17 @@ declare global {
|
||||
const AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
const AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
const AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
const FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
const FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
const FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
const FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
const FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
const FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
const FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
const FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
const FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
const FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
const FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
const FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
const FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
const FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -99,12 +110,15 @@ declare global {
|
||||
const FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
const FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
const FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
const FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
const FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
const FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
const FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
const FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
const FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
const FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
const FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
const FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
const FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
const FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
const FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
|
||||
@@ -11,6 +11,8 @@ const themeConfig = computed(() => ({
|
||||
|
||||
<template>
|
||||
<AConfigProvider :locale="antdvNextLocaleZhCN" :theme="themeConfig">
|
||||
<slot />
|
||||
<AApp class="size-full">
|
||||
<slot />
|
||||
</AApp>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
|
||||
@@ -33,12 +33,12 @@ const products = ref([
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'One-step-admin',
|
||||
tagline: '干啥都快人一步的 Vue 中后台系统框架',
|
||||
name: 'One-step Console',
|
||||
tagline: '像导播一样编排你的工作现场',
|
||||
logo: 'https://one-step-admin.hurui.me/logo.png',
|
||||
url: 'https://one-step-admin.hurui.me',
|
||||
images: [
|
||||
'https://one-step-admin.hurui.me/preview1.png',
|
||||
'https://one-step-admin.hurui.me/hero_preview.png',
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
@@ -47,7 +47,10 @@ export default defineConfig(({ mode, command }) => {
|
||||
},
|
||||
plugins: createVitePlugins(mode, command === 'build'),
|
||||
optimizeDeps: {
|
||||
exclude: ['@fantastic-admin/components'],
|
||||
exclude: [
|
||||
'@fantastic-admin/components',
|
||||
'@fantastic-admin/composables',
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PluginOption } from 'vite'
|
||||
import process from 'node:process'
|
||||
import { FantasticAutoImports, FantasticComponentsResolver, FantasticComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import { ComponentsAutoImports as FantasticAdminComponentsAutoImports, ComponentsResolver as FantasticAdminComponentsResolver, ComponentsType as FantasticAdminComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { ComposablesAutoImports as FantasticAdminComposablesAutoImports } from '@fantastic-admin/composables/resolver'
|
||||
import { createCopyrightPlugins as createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import VitePluginSvgSpritemap from '@spiriit/vite-plugin-svg-spritemap'
|
||||
import vueLegacy from '@vitejs/plugin-legacy'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -37,6 +38,7 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
launchEditor: viteEnv.VITE_LAUNCH_EDITOR,
|
||||
}),
|
||||
|
||||
// https://github.com/yue1123/vite-plugin-env-parse
|
||||
envParse({
|
||||
dtsPath: 'src/types/env.d.ts',
|
||||
}),
|
||||
@@ -47,7 +49,8 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
'vue',
|
||||
'vue-router',
|
||||
'pinia',
|
||||
FantasticAutoImports,
|
||||
FantasticAdminComponentsAutoImports,
|
||||
FantasticAdminComposablesAutoImports,
|
||||
],
|
||||
dts: './src/types/auto-imports.d.ts',
|
||||
dirs: [
|
||||
@@ -63,10 +66,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
],
|
||||
dts: './src/types/components.d.ts',
|
||||
resolvers: [
|
||||
FantasticComponentsResolver(),
|
||||
FantasticAdminComponentsResolver(),
|
||||
],
|
||||
types: [
|
||||
FantasticComponentsType,
|
||||
FantasticAdminComponentsType,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -78,9 +81,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
// https://github.com/condorheroblog/vite-plugin-fake-server
|
||||
vitePluginFakeServer({
|
||||
logger: !isBuild,
|
||||
include: 'src/api/modules',
|
||||
include: 'src/api/fake_modules',
|
||||
enableProd: isBuild && viteEnv.VITE_BUILD_FAKE,
|
||||
}),
|
||||
|
||||
// https://github.com/nonzzz/vite-plugin-compression
|
||||
viteEnv.VITE_BUILD_COMPRESS && compression({
|
||||
exclude: [/\.(br)$/, /\.(gz)$/],
|
||||
@@ -105,7 +109,6 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
(() => {
|
||||
const moduleId = 'virtual:fantastic-admin/turbo-console'
|
||||
const resolvedModuleId = `\0${moduleId}`
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-turbo-console-bridge',
|
||||
resolveId(id) {
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
"serve": "http-server ./dist -o",
|
||||
"serve:test": "http-server ./dist-test -o",
|
||||
"svgo": "svgo -f src/assets/icons",
|
||||
"generate:icons": "tsx ./scripts/generate.icons.ts",
|
||||
"generate:icons": "fa-iconify-tools",
|
||||
"lint": "vue-tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fantastic-admin/components": "workspace:*",
|
||||
"@fantastic-admin/composables": "workspace:*",
|
||||
"@fantastic-admin/settings": "workspace:*",
|
||||
"@fantastic-admin/types": "workspace:*",
|
||||
"@vee-validate/zod": "catalog:",
|
||||
@@ -27,7 +28,6 @@
|
||||
"eruda": "catalog:",
|
||||
"es-toolkit": "catalog:",
|
||||
"hotkeys-js": "catalog:",
|
||||
"lucide-vue-next": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"path-browserify": "catalog:",
|
||||
@@ -49,9 +49,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arco-design/web-vue": "catalog:arco-design-vue",
|
||||
"@clack/prompts": "catalog:",
|
||||
"@faker-js/faker": "catalog:",
|
||||
"@fantastic-admin/copyright": "workspace:*",
|
||||
"@fantastic-admin/iconify-tools": "workspace:*",
|
||||
"@iconify/vue": "catalog:",
|
||||
"@spiriit/vite-plugin-svg-spritemap": "catalog:",
|
||||
"@types/nprogress": "catalog:",
|
||||
@@ -66,7 +66,6 @@
|
||||
"postcss-nested": "catalog:",
|
||||
"sass-embedded": "catalog:",
|
||||
"svgo": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"unplugin-auto-import": "catalog:",
|
||||
"unplugin-turbo-console": "catalog:",
|
||||
"unplugin-vue-components": "catalog:",
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import * as p from '@clack/prompts'
|
||||
import { lookupCollection, lookupCollections } from '@iconify/json'
|
||||
|
||||
// 拿到全部图标集的原始数据
|
||||
const raw = await lookupCollections()
|
||||
|
||||
let lastChoose = fs.readFileSync(path.resolve(process.cwd(), 'src/iconify/index.json'), 'utf-8')
|
||||
lastChoose = JSON.parse(lastChoose)
|
||||
|
||||
// 取出可使用的图标集数据用于选择,并按名称排序
|
||||
const collections = Object.entries(raw).map(([id, item]) => ({
|
||||
...item,
|
||||
id,
|
||||
})).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
p.intro('图标集生成工具')
|
||||
|
||||
/**
|
||||
* 分别会在对应目录下生成以下文件,其中(1)(3)用于离线下载并安装图标,(2)用于图标选择器使用
|
||||
* (1) src/iconify/index.json 记录用户交互信息
|
||||
* (2) src/iconify/data.json 包含多个图标集数据,仅记录图标名
|
||||
* (3) public/icons/*-raw.json 多个图标集的原始数据,独立存放,用于离线使用
|
||||
*/
|
||||
const answers = await p.group(
|
||||
{
|
||||
collections: () =>
|
||||
p.multiselect({
|
||||
message: '请选择需要生成的图标集',
|
||||
options: collections.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
hint: `${item.total} 个图标`,
|
||||
})),
|
||||
initialValues: lastChoose.collections,
|
||||
}),
|
||||
isOfflineUse: () =>
|
||||
p.confirm({
|
||||
message: '是否需要离线使用',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('操作已取消')
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const spinner = p.spinner()
|
||||
spinner.start('正在生成图标集...')
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/index.json'),
|
||||
{
|
||||
collections: answers.collections,
|
||||
isOfflineUse: answers.isOfflineUse,
|
||||
},
|
||||
)
|
||||
|
||||
const outputDir = path.resolve(process.cwd(), 'public/icons')
|
||||
await fs.ensureDir(outputDir)
|
||||
await fs.emptyDir(outputDir)
|
||||
|
||||
const collectionsMeta: object[] = []
|
||||
for (const info of answers.collections) {
|
||||
const setData = await lookupCollection(info)
|
||||
|
||||
collectionsMeta.push({
|
||||
prefix: setData.prefix,
|
||||
info: setData.info,
|
||||
icons: Object.keys(setData.icons),
|
||||
})
|
||||
|
||||
const offlineFilePath = path.join(outputDir, `${info}-raw.json`)
|
||||
|
||||
if (answers.isOfflineUse) {
|
||||
await fs.writeJSON(offlineFilePath, setData)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/data.json'),
|
||||
collectionsMeta,
|
||||
)
|
||||
|
||||
// 使用 spawn 运行 eslint
|
||||
const eslint = spawn('eslint', ['src/iconify/data.json', 'src/iconify/index.json', '--cache', '--fix'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
})
|
||||
|
||||
eslint.on('error', (err) => {
|
||||
p.log.error(`ESLint 执行失败: ${err.message}`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
eslint.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
p.log.error(`ESLint 执行失败,退出码: ${code}`)
|
||||
process.exit(code)
|
||||
}
|
||||
spinner.stop('图标集生成完成!')
|
||||
})
|
||||
@@ -51,7 +51,7 @@ function handleError(error: any) {
|
||||
useAppAccountStore().requestLogout()
|
||||
}
|
||||
else {
|
||||
faToast.error('Error', {
|
||||
useFaToast().error('Error', {
|
||||
description: error.message,
|
||||
})
|
||||
}
|
||||
@@ -70,7 +70,7 @@ api.interceptors.response.use(
|
||||
if (typeof response.data === 'object') {
|
||||
if (response.data.status === 1) {
|
||||
if (response.data.error) {
|
||||
faToast.warning('Warning', {
|
||||
useFaToast().warning('Warning', {
|
||||
description: response.data.error,
|
||||
})
|
||||
return Promise.reject(response.data)
|
||||
|
||||
@@ -32,7 +32,7 @@ const form = useForm({
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
loading.value = true
|
||||
appAccountStore.editPassword(values).then(async () => {
|
||||
faToast.success('模拟修改成功,请重新登录')
|
||||
useFaToast().success('模拟修改成功,请重新登录')
|
||||
appAccountStore.logout()
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
@@ -61,7 +61,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -75,7 +75,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -89,7 +89,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -90,7 +90,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -104,7 +104,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -113,7 +113,7 @@ function testAccount(account: string) {
|
||||
<FormField v-slot="{ componentField }" type="checkbox" name="remember">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<FaCheckbox v-bind="componentField">
|
||||
<FaCheckbox :model-value="componentField.modelValue" @update:model-value="componentField['onUpdate:modelValue']?.($event)">
|
||||
记住我
|
||||
</FaCheckbox>
|
||||
</FormControl>
|
||||
|
||||
@@ -63,7 +63,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,11 +76,11 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</template>
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<FormDescription class="m-0">
|
||||
<FaPasswordStrength :password="value" />
|
||||
</FormDescription>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -94,7 +94,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -70,7 +70,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -81,7 +81,7 @@ function handleSendCaptcha() {
|
||||
<FaInputOTP :model-value="value" :name="componentField.name" :length="6" class="border-destructive" @update:model-value="val => setValue(val)" />
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -99,7 +99,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -80,13 +80,13 @@ export function useAppTabbar() {
|
||||
const index = appTabbarStore.list.findIndex(item => item.tabId === tabId)
|
||||
if (index < 0) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('关闭的标签页不存在', {
|
||||
!checkOnly && useFaToast().warning('关闭的标签页不存在', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
else if (appTabbarStore.list.length <= 1) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('当前只有一个标签页,不可关闭', {
|
||||
!checkOnly && useFaToast().warning('当前只有一个标签页,不可关闭', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -53,7 +53,7 @@ function handleCopy() {
|
||||
'columns-2': appSettingsStore.mode === 'pc',
|
||||
}"
|
||||
>
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
颜色方案
|
||||
@@ -83,7 +83,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.theme.colorAmblyopia" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="menu-mode">
|
||||
<FaTooltip text="侧边栏模式 (有主导航菜单)" :delay="500">
|
||||
<FaButton variant="outline" class="mode mode-side" :class="{ active: appSettingsStore.settings.menu.mode === 'side' }" @click="appSettingsStore.settings.menu.mode = 'side'">
|
||||
@@ -145,7 +145,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.menu.hotkeys" :disabled="appSettingsStore.settings.menu.mode === 'single'" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
标签栏
|
||||
@@ -175,7 +175,7 @@ function handleCopy() {
|
||||
</FaButtonGroup>
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
显示图标
|
||||
@@ -189,7 +189,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.tabbar.hotkeys" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div v-if="appSettingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
<FaIcon name="i-ic:twotone-double-arrow" />
|
||||
@@ -237,7 +237,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.toolbar.colorScheme" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
载入进度条
|
||||
@@ -248,7 +248,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.page.progress" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="p-4 pb-4 pt-14 border rounded-lg relative space-y-4">
|
||||
<div class="font-bold px-4 py-2 border-b border-e rounded-rb-lg inset-s-0 inset-t-0 absolute">
|
||||
账号
|
||||
|
||||
@@ -72,13 +72,13 @@ watch(() => route, (val) => {
|
||||
function tabbarScrollTip() {
|
||||
if (tabContainerRef.value?.$el.clientWidth > (tabsRef.value?.ref?.$el.clientWidth ?? 0) && !localStorage.has('tabbarScrollTip')) {
|
||||
localStorage.setItem('tabbarScrollTip', '')
|
||||
const tips = faToast.info('温馨提示', {
|
||||
const tips = useFaToast().info('温馨提示', {
|
||||
description: '标签栏数量超过展示区域范围,可以将鼠标移到标签栏上,通过鼠标滚轮滑动浏览',
|
||||
position: 'top-center',
|
||||
duration: Infinity,
|
||||
action: {
|
||||
label: '知道了',
|
||||
onClick: () => faToast.dismiss(tips),
|
||||
onClick: () => useFaToast().dismiss(tips),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
+10
-8
@@ -8,13 +8,15 @@ const mainPage = useAppPage()
|
||||
|
||||
const isAnimating = ref(false)
|
||||
|
||||
function handleClick() {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
|
||||
function handleCtrlClick() {
|
||||
location.reload()
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
location.reload()
|
||||
return
|
||||
}
|
||||
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,7 +30,7 @@ function handleCtrlClick() {
|
||||
<p>可切换为浏览器原生刷新</p>
|
||||
</div>
|
||||
</template>
|
||||
<FaButton variant="ghost" size="icon-sm" @click.exact="handleClick" @click.ctrl.exact="handleCtrlClick" @animationend="isAnimating = false">
|
||||
<FaButton variant="ghost" size="icon-sm" @click="handleClick" @animationend="isAnimating = false">
|
||||
<FaIcon name="i-iconoir:refresh-double" class="size-4" :class="{ animation: isAnimating }" />
|
||||
</FaButton>
|
||||
</FaTooltip>
|
||||
|
||||
@@ -8,7 +8,7 @@ defineOptions({
|
||||
const route = useRoute()
|
||||
const { copy, copied } = useClipboard()
|
||||
watch(copied, (val) => {
|
||||
val && faToast.success('复制成功')
|
||||
val && useFaToast().success('复制成功')
|
||||
})
|
||||
|
||||
function open() {
|
||||
|
||||
@@ -110,7 +110,7 @@ function extendClose(router: Router) {
|
||||
}
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface Router {
|
||||
interface _RouterClassic {
|
||||
/**
|
||||
* 本方法为框架扩展语法,会同时关闭当前标签页
|
||||
*
|
||||
|
||||
@@ -94,16 +94,6 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
await apiApp.passwordEdit(data)
|
||||
}
|
||||
|
||||
// 锁屏
|
||||
function lock() {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
// 解锁
|
||||
function unlock() {
|
||||
localStorage.setItem('token', token.value)
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
account,
|
||||
@@ -115,7 +105,5 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
requestLogout,
|
||||
getPermissions,
|
||||
editPassword,
|
||||
lock,
|
||||
unlock,
|
||||
}
|
||||
})
|
||||
|
||||
+2
-2
@@ -16,7 +16,6 @@ declare global {
|
||||
const defineComponent: typeof import('vue').defineComponent
|
||||
const defineStore: typeof import('pinia').defineStore
|
||||
const effectScope: typeof import('vue').effectScope
|
||||
const faToast: typeof import('@fantastic-admin/components').faToast
|
||||
const getActivePinia: typeof import('pinia').getActivePinia
|
||||
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||
@@ -84,10 +83,11 @@ declare global {
|
||||
const useFaDrawer: typeof import('@fantastic-admin/components').useFaDrawer
|
||||
const useFaImagePreview: typeof import('@fantastic-admin/components').useFaImagePreview
|
||||
const useFaModal: typeof import('@fantastic-admin/components').useFaModal
|
||||
const useFaToast: typeof import('@fantastic-admin/components').useFaToast
|
||||
const useId: typeof import('vue').useId
|
||||
const useLink: typeof import('vue-router').useLink
|
||||
const useModel: typeof import('vue').useModel
|
||||
const usePagination: typeof import('../composables/pagination').usePagination
|
||||
const usePagination: typeof import('@fantastic-admin/composables').usePagination
|
||||
const useRoute: typeof import('vue-router').useRoute
|
||||
const useRouter: typeof import('vue-router').useRouter
|
||||
const useSlots: typeof import('vue').useSlots
|
||||
|
||||
@@ -19,13 +19,17 @@ declare module 'vue' {
|
||||
AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -48,12 +52,15 @@ declare module 'vue' {
|
||||
FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
@@ -70,13 +77,17 @@ declare global {
|
||||
const AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
const AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
const AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
const FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
const FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
const FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
const FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
const FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
const FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
const FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
const FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
const FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
const FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
const FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
const FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
const FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
const FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -99,12 +110,15 @@ declare global {
|
||||
const FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
const FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
const FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
const FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
const FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
const FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
const FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
const FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
const FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
const FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
const FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
const FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
const FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
const FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
const FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
|
||||
@@ -33,12 +33,12 @@ const products = ref([
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'One-step-admin',
|
||||
tagline: '干啥都快人一步的 Vue 中后台系统框架',
|
||||
name: 'One-step Console',
|
||||
tagline: '像导播一样编排你的工作现场',
|
||||
logo: 'https://one-step-admin.hurui.me/logo.png',
|
||||
url: 'https://one-step-admin.hurui.me',
|
||||
images: [
|
||||
'https://one-step-admin.hurui.me/preview1.png',
|
||||
'https://one-step-admin.hurui.me/hero_preview.png',
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
@@ -47,7 +47,10 @@ export default defineConfig(({ mode, command }) => {
|
||||
},
|
||||
plugins: createVitePlugins(mode, command === 'build'),
|
||||
optimizeDeps: {
|
||||
exclude: ['@fantastic-admin/components'],
|
||||
exclude: [
|
||||
'@fantastic-admin/components',
|
||||
'@fantastic-admin/composables',
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PluginOption } from 'vite'
|
||||
import process from 'node:process'
|
||||
import { FantasticAutoImports, FantasticComponentsResolver, FantasticComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import { ComponentsAutoImports as FantasticAdminComponentsAutoImports, ComponentsResolver as FantasticAdminComponentsResolver, ComponentsType as FantasticAdminComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { ComposablesAutoImports as FantasticAdminComposablesAutoImports } from '@fantastic-admin/composables/resolver'
|
||||
import { createCopyrightPlugins as createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import VitePluginSvgSpritemap from '@spiriit/vite-plugin-svg-spritemap'
|
||||
import vueLegacy from '@vitejs/plugin-legacy'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -37,6 +38,7 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
launchEditor: viteEnv.VITE_LAUNCH_EDITOR,
|
||||
}),
|
||||
|
||||
// https://github.com/yue1123/vite-plugin-env-parse
|
||||
envParse({
|
||||
dtsPath: 'src/types/env.d.ts',
|
||||
}),
|
||||
@@ -47,7 +49,8 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
'vue',
|
||||
'vue-router',
|
||||
'pinia',
|
||||
FantasticAutoImports,
|
||||
FantasticAdminComponentsAutoImports,
|
||||
FantasticAdminComposablesAutoImports,
|
||||
],
|
||||
dts: './src/types/auto-imports.d.ts',
|
||||
dirs: [
|
||||
@@ -63,10 +66,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
],
|
||||
dts: './src/types/components.d.ts',
|
||||
resolvers: [
|
||||
FantasticComponentsResolver(),
|
||||
FantasticAdminComponentsResolver(),
|
||||
],
|
||||
types: [
|
||||
FantasticComponentsType,
|
||||
FantasticAdminComponentsType,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -78,9 +81,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
// https://github.com/condorheroblog/vite-plugin-fake-server
|
||||
vitePluginFakeServer({
|
||||
logger: !isBuild,
|
||||
include: 'src/api/modules',
|
||||
include: 'src/api/fake_modules',
|
||||
enableProd: isBuild && viteEnv.VITE_BUILD_FAKE,
|
||||
}),
|
||||
|
||||
// https://github.com/nonzzz/vite-plugin-compression
|
||||
viteEnv.VITE_BUILD_COMPRESS && compression({
|
||||
exclude: [/\.(br)$/, /\.(gz)$/],
|
||||
@@ -105,7 +109,6 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
(() => {
|
||||
const moduleId = 'virtual:fantastic-admin/turbo-console'
|
||||
const resolvedModuleId = `\0${moduleId}`
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-turbo-console-bridge',
|
||||
resolveId(id) {
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
"serve": "http-server ./dist -o",
|
||||
"serve:test": "http-server ./dist-test -o",
|
||||
"svgo": "svgo -f src/assets/icons",
|
||||
"generate:icons": "tsx ./scripts/generate.icons.ts",
|
||||
"generate:icons": "fa-iconify-tools",
|
||||
"lint": "vue-tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fantastic-admin/components": "workspace:*",
|
||||
"@fantastic-admin/composables": "workspace:*",
|
||||
"@fantastic-admin/settings": "workspace:*",
|
||||
"@fantastic-admin/types": "workspace:*",
|
||||
"@vee-validate/zod": "catalog:",
|
||||
@@ -27,7 +28,6 @@
|
||||
"eruda": "catalog:",
|
||||
"es-toolkit": "catalog:",
|
||||
"hotkeys-js": "catalog:",
|
||||
"lucide-vue-next": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"path-browserify": "catalog:",
|
||||
@@ -48,9 +48,9 @@
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "catalog:",
|
||||
"@faker-js/faker": "catalog:",
|
||||
"@fantastic-admin/copyright": "workspace:*",
|
||||
"@fantastic-admin/iconify-tools": "workspace:*",
|
||||
"@iconify/vue": "catalog:",
|
||||
"@spiriit/vite-plugin-svg-spritemap": "catalog:",
|
||||
"@types/nprogress": "catalog:",
|
||||
@@ -66,7 +66,6 @@
|
||||
"postcss-nested": "catalog:",
|
||||
"sass-embedded": "catalog:",
|
||||
"svgo": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"unplugin-auto-import": "catalog:",
|
||||
"unplugin-turbo-console": "catalog:",
|
||||
"unplugin-vue-components": "catalog:",
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import * as p from '@clack/prompts'
|
||||
import { lookupCollection, lookupCollections } from '@iconify/json'
|
||||
|
||||
// 拿到全部图标集的原始数据
|
||||
const raw = await lookupCollections()
|
||||
|
||||
let lastChoose = fs.readFileSync(path.resolve(process.cwd(), 'src/iconify/index.json'), 'utf-8')
|
||||
lastChoose = JSON.parse(lastChoose)
|
||||
|
||||
// 取出可使用的图标集数据用于选择,并按名称排序
|
||||
const collections = Object.entries(raw).map(([id, item]) => ({
|
||||
...item,
|
||||
id,
|
||||
})).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
p.intro('图标集生成工具')
|
||||
|
||||
/**
|
||||
* 分别会在对应目录下生成以下文件,其中(1)(3)用于离线下载并安装图标,(2)用于图标选择器使用
|
||||
* (1) src/iconify/index.json 记录用户交互信息
|
||||
* (2) src/iconify/data.json 包含多个图标集数据,仅记录图标名
|
||||
* (3) public/icons/*-raw.json 多个图标集的原始数据,独立存放,用于离线使用
|
||||
*/
|
||||
const answers = await p.group(
|
||||
{
|
||||
collections: () =>
|
||||
p.multiselect({
|
||||
message: '请选择需要生成的图标集',
|
||||
options: collections.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
hint: `${item.total} 个图标`,
|
||||
})),
|
||||
initialValues: lastChoose.collections,
|
||||
}),
|
||||
isOfflineUse: () =>
|
||||
p.confirm({
|
||||
message: '是否需要离线使用',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('操作已取消')
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const spinner = p.spinner()
|
||||
spinner.start('正在生成图标集...')
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/index.json'),
|
||||
{
|
||||
collections: answers.collections,
|
||||
isOfflineUse: answers.isOfflineUse,
|
||||
},
|
||||
)
|
||||
|
||||
const outputDir = path.resolve(process.cwd(), 'public/icons')
|
||||
await fs.ensureDir(outputDir)
|
||||
await fs.emptyDir(outputDir)
|
||||
|
||||
const collectionsMeta: object[] = []
|
||||
for (const info of answers.collections) {
|
||||
const setData = await lookupCollection(info)
|
||||
|
||||
collectionsMeta.push({
|
||||
prefix: setData.prefix,
|
||||
info: setData.info,
|
||||
icons: Object.keys(setData.icons),
|
||||
})
|
||||
|
||||
const offlineFilePath = path.join(outputDir, `${info}-raw.json`)
|
||||
|
||||
if (answers.isOfflineUse) {
|
||||
await fs.writeJSON(offlineFilePath, setData)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/data.json'),
|
||||
collectionsMeta,
|
||||
)
|
||||
|
||||
// 使用 spawn 运行 eslint
|
||||
const eslint = spawn('eslint', ['src/iconify/data.json', 'src/iconify/index.json', '--cache', '--fix'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
})
|
||||
|
||||
eslint.on('error', (err) => {
|
||||
p.log.error(`ESLint 执行失败: ${err.message}`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
eslint.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
p.log.error(`ESLint 执行失败,退出码: ${code}`)
|
||||
process.exit(code)
|
||||
}
|
||||
spinner.stop('图标集生成完成!')
|
||||
})
|
||||
@@ -51,7 +51,7 @@ function handleError(error: any) {
|
||||
useAppAccountStore().requestLogout()
|
||||
}
|
||||
else {
|
||||
faToast.error('Error', {
|
||||
useFaToast().error('Error', {
|
||||
description: error.message,
|
||||
})
|
||||
}
|
||||
@@ -70,7 +70,7 @@ api.interceptors.response.use(
|
||||
if (typeof response.data === 'object') {
|
||||
if (response.data.status === 1) {
|
||||
if (response.data.error) {
|
||||
faToast.warning('Warning', {
|
||||
useFaToast().warning('Warning', {
|
||||
description: response.data.error,
|
||||
})
|
||||
return Promise.reject(response.data)
|
||||
|
||||
@@ -32,7 +32,7 @@ const form = useForm({
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
loading.value = true
|
||||
appAccountStore.editPassword(values).then(async () => {
|
||||
faToast.success('模拟修改成功,请重新登录')
|
||||
useFaToast().success('模拟修改成功,请重新登录')
|
||||
appAccountStore.logout()
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
@@ -61,7 +61,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -75,7 +75,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -89,7 +89,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -90,7 +90,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -104,7 +104,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -113,7 +113,7 @@ function testAccount(account: string) {
|
||||
<FormField v-slot="{ componentField }" type="checkbox" name="remember">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<FaCheckbox v-bind="componentField">
|
||||
<FaCheckbox :model-value="componentField.modelValue" @update:model-value="componentField['onUpdate:modelValue']?.($event)">
|
||||
记住我
|
||||
</FaCheckbox>
|
||||
</FormControl>
|
||||
|
||||
@@ -63,7 +63,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,11 +76,11 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</template>
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<FormDescription class="m-0">
|
||||
<FaPasswordStrength :password="value" />
|
||||
</FormDescription>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -94,7 +94,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -70,7 +70,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -81,7 +81,7 @@ function handleSendCaptcha() {
|
||||
<FaInputOTP :model-value="value" :name="componentField.name" :length="6" class="border-destructive" @update:model-value="val => setValue(val)" />
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -99,7 +99,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -80,13 +80,13 @@ export function useAppTabbar() {
|
||||
const index = appTabbarStore.list.findIndex(item => item.tabId === tabId)
|
||||
if (index < 0) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('关闭的标签页不存在', {
|
||||
!checkOnly && useFaToast().warning('关闭的标签页不存在', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
else if (appTabbarStore.list.length <= 1) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('当前只有一个标签页,不可关闭', {
|
||||
!checkOnly && useFaToast().warning('当前只有一个标签页,不可关闭', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
export function usePagination() {
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
sort: null as string | null,
|
||||
order: null as string | null,
|
||||
})
|
||||
|
||||
function getParams() {
|
||||
return {
|
||||
// page,size 和 from,limit 是分页的两种方式,方便兼容两种接口
|
||||
page: pagination.value.page,
|
||||
size: pagination.value.size,
|
||||
from: (pagination.value.page - 1) * pagination.value.size,
|
||||
limit: pagination.value.size,
|
||||
...(
|
||||
pagination.value.sort && pagination.value.order && {
|
||||
sort: pagination.value.sort,
|
||||
order: pagination.value.order,
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async function onSizeChange(size: number) {
|
||||
pagination.value.size = size
|
||||
}
|
||||
|
||||
async function onCurrentChange(page: number) {
|
||||
pagination.value.page = page
|
||||
}
|
||||
|
||||
async function onSortChange(prop: string, order: string) {
|
||||
pagination.value.sort = prop
|
||||
pagination.value.order = order === 'ascending' ? 'asc' : 'desc'
|
||||
}
|
||||
|
||||
return {
|
||||
pagination,
|
||||
getParams,
|
||||
onSizeChange,
|
||||
onCurrentChange,
|
||||
onSortChange,
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -53,7 +53,7 @@ function handleCopy() {
|
||||
'columns-2': appSettingsStore.mode === 'pc',
|
||||
}"
|
||||
>
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="主题" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
颜色方案
|
||||
@@ -83,7 +83,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.theme.colorAmblyopia" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain v-if="appSettingsStore.mode === 'pc'" title="导航菜单" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="menu-mode">
|
||||
<FaTooltip text="侧边栏模式 (有主导航菜单)" :delay="500">
|
||||
<FaButton variant="outline" class="mode mode-side" :class="{ active: appSettingsStore.settings.menu.mode === 'side' }" @click="appSettingsStore.settings.menu.mode = 'side'">
|
||||
@@ -145,7 +145,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.menu.hotkeys" :disabled="appSettingsStore.settings.menu.mode === 'single'" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="顶栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
标签栏
|
||||
@@ -175,7 +175,7 @@ function handleCopy() {
|
||||
</FaButtonGroup>
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="标签栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
显示图标
|
||||
@@ -189,7 +189,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.tabbar.hotkeys" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="工具栏" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div v-if="appSettingsStore.mode === 'pc'" class="setting-item">
|
||||
<div class="label">
|
||||
<FaIcon name="i-ic:twotone-double-arrow" />
|
||||
@@ -237,7 +237,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.toolbar.colorScheme" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="页面" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="setting-item">
|
||||
<div class="label">
|
||||
载入进度条
|
||||
@@ -248,7 +248,7 @@ function handleCopy() {
|
||||
<FaSwitch v-model="appSettingsStore.settings.page.progress" />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="pb-0 border-none font-bold" main-class="space-y-4">
|
||||
<FaPageMain title="应用" class="m-0 mb-4 break-inside-avoid light:border-none" title-class="font-bold" main-class="space-y-4">
|
||||
<div class="p-4 pb-4 pt-14 border rounded-lg relative space-y-4">
|
||||
<div class="font-bold px-4 py-2 border-b border-e rounded-rb-lg inset-s-0 inset-t-0 absolute">
|
||||
账号
|
||||
|
||||
@@ -72,13 +72,13 @@ watch(() => route, (val) => {
|
||||
function tabbarScrollTip() {
|
||||
if (tabContainerRef.value?.$el.clientWidth > (tabsRef.value?.ref?.$el.clientWidth ?? 0) && !localStorage.has('tabbarScrollTip')) {
|
||||
localStorage.setItem('tabbarScrollTip', '')
|
||||
const tips = faToast.info('温馨提示', {
|
||||
const tips = useFaToast().info('温馨提示', {
|
||||
description: '标签栏数量超过展示区域范围,可以将鼠标移到标签栏上,通过鼠标滚轮滑动浏览',
|
||||
position: 'top-center',
|
||||
duration: Infinity,
|
||||
action: {
|
||||
label: '知道了',
|
||||
onClick: () => faToast.dismiss(tips),
|
||||
onClick: () => useFaToast().dismiss(tips),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@ const mainPage = useAppPage()
|
||||
|
||||
const isAnimating = ref(false)
|
||||
|
||||
function handleClick() {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
|
||||
function handleCtrlClick() {
|
||||
location.reload()
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
location.reload()
|
||||
return
|
||||
}
|
||||
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey) {
|
||||
isAnimating.value = true
|
||||
mainPage.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,7 +30,7 @@ function handleCtrlClick() {
|
||||
<p>可切换为浏览器原生刷新</p>
|
||||
</div>
|
||||
</template>
|
||||
<FaButton variant="ghost" size="icon-sm" @click.exact="handleClick" @click.ctrl.exact="handleCtrlClick" @animationend="isAnimating = false">
|
||||
<FaButton variant="ghost" size="icon-sm" @click="handleClick" @animationend="isAnimating = false">
|
||||
<FaIcon name="i-iconoir:refresh-double" class="size-4" :class="{ animation: isAnimating }" />
|
||||
</FaButton>
|
||||
</FaTooltip>
|
||||
|
||||
@@ -8,7 +8,7 @@ defineOptions({
|
||||
const route = useRoute()
|
||||
const { copy, copied } = useClipboard()
|
||||
watch(copied, (val) => {
|
||||
val && faToast.success('复制成功')
|
||||
val && useFaToast().success('复制成功')
|
||||
})
|
||||
|
||||
function open() {
|
||||
|
||||
@@ -110,7 +110,7 @@ function extendClose(router: Router) {
|
||||
}
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface Router {
|
||||
interface _RouterClassic {
|
||||
/**
|
||||
* 本方法为框架扩展语法,会同时关闭当前标签页
|
||||
*
|
||||
|
||||
@@ -94,16 +94,6 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
await apiApp.passwordEdit(data)
|
||||
}
|
||||
|
||||
// 锁屏
|
||||
function lock() {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
// 解锁
|
||||
function unlock() {
|
||||
localStorage.setItem('token', token.value)
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
account,
|
||||
@@ -115,7 +105,5 @@ export const useAppAccountStore = defineStore('appAccount', () => {
|
||||
requestLogout,
|
||||
getPermissions,
|
||||
editPassword,
|
||||
lock,
|
||||
unlock,
|
||||
}
|
||||
})
|
||||
|
||||
+2
-2
@@ -16,7 +16,6 @@ declare global {
|
||||
const defineComponent: typeof import('vue').defineComponent
|
||||
const defineStore: typeof import('pinia').defineStore
|
||||
const effectScope: typeof import('vue').effectScope
|
||||
const faToast: typeof import('@fantastic-admin/components').faToast
|
||||
const getActivePinia: typeof import('pinia').getActivePinia
|
||||
const getCurrentInstance: typeof import('vue').getCurrentInstance
|
||||
const getCurrentScope: typeof import('vue').getCurrentScope
|
||||
@@ -84,10 +83,11 @@ declare global {
|
||||
const useFaDrawer: typeof import('@fantastic-admin/components').useFaDrawer
|
||||
const useFaImagePreview: typeof import('@fantastic-admin/components').useFaImagePreview
|
||||
const useFaModal: typeof import('@fantastic-admin/components').useFaModal
|
||||
const useFaToast: typeof import('@fantastic-admin/components').useFaToast
|
||||
const useId: typeof import('vue').useId
|
||||
const useLink: typeof import('vue-router').useLink
|
||||
const useModel: typeof import('vue').useModel
|
||||
const usePagination: typeof import('../composables/pagination').usePagination
|
||||
const usePagination: typeof import('@fantastic-admin/composables').usePagination
|
||||
const useRoute: typeof import('vue-router').useRoute
|
||||
const useRouter: typeof import('vue-router').useRouter
|
||||
const useSlots: typeof import('vue').useSlots
|
||||
|
||||
+14
@@ -19,13 +19,17 @@ declare module 'vue' {
|
||||
AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -48,12 +52,15 @@ declare module 'vue' {
|
||||
FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
@@ -70,13 +77,17 @@ declare global {
|
||||
const AppNotAllowed: typeof import('./../components/AppNotAllowed/index.vue')['default']
|
||||
const AppNotSupportedMobile: typeof import('./../components/AppNotSupportedMobile/index.vue')['default']
|
||||
const AppSystemInfo: typeof import('./../components/AppSystemInfo/index.vue')['default']
|
||||
const FaAlert: typeof import('@fantastic-admin/components')['FaAlert']
|
||||
const FaAvatar: typeof import('@fantastic-admin/components')['FaAvatar']
|
||||
const FaBadge: typeof import('@fantastic-admin/components')['FaBadge']
|
||||
const FaButton: typeof import('@fantastic-admin/components')['FaButton']
|
||||
const FaButtonGroup: typeof import('@fantastic-admin/components')['FaButtonGroup']
|
||||
const FaCard: typeof import('@fantastic-admin/components')['FaCard']
|
||||
const FaCheckbox: typeof import('@fantastic-admin/components')['FaCheckbox']
|
||||
const FaCheckboxGroup: typeof import('@fantastic-admin/components')['FaCheckboxGroup']
|
||||
const FaCollapsible: typeof import('@fantastic-admin/components')['FaCollapsible']
|
||||
const FaContextMenu: typeof import('@fantastic-admin/components')['FaContextMenu']
|
||||
const FaDescriptions: typeof import('@fantastic-admin/components')['FaDescriptions']
|
||||
const FaDivider: typeof import('@fantastic-admin/components')['FaDivider']
|
||||
const FaDrawer: typeof import('@fantastic-admin/components')['FaDrawer']
|
||||
const FaDropdown: typeof import('@fantastic-admin/components')['FaDropdown']
|
||||
@@ -99,12 +110,15 @@ declare global {
|
||||
const FaPasswordStrength: typeof import('@fantastic-admin/components')['FaPasswordStrength']
|
||||
const FaPopover: typeof import('@fantastic-admin/components')['FaPopover']
|
||||
const FaProgress: typeof import('@fantastic-admin/components')['FaProgress']
|
||||
const FaRadioGroup: typeof import('@fantastic-admin/components')['FaRadioGroup']
|
||||
const FaScrollArea: typeof import('@fantastic-admin/components')['FaScrollArea']
|
||||
const FaSearchBar: typeof import('@fantastic-admin/components')['FaSearchBar']
|
||||
const FaSelect: typeof import('@fantastic-admin/components')['FaSelect']
|
||||
const FaSlider: typeof import('@fantastic-admin/components')['FaSlider']
|
||||
const FaSwitch: typeof import('@fantastic-admin/components')['FaSwitch']
|
||||
const FaTable: typeof import('@fantastic-admin/components')['FaTable']
|
||||
const FaTabs: typeof import('@fantastic-admin/components')['FaTabs']
|
||||
const FaTag: typeof import('@fantastic-admin/components')['FaTag']
|
||||
const FaTextarea: typeof import('@fantastic-admin/components')['FaTextarea']
|
||||
const FaToast: typeof import('@fantastic-admin/components')['FaToast']
|
||||
const FaTooltip: typeof import('@fantastic-admin/components')['FaTooltip']
|
||||
|
||||
@@ -33,12 +33,12 @@ const products = ref([
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'One-step-admin',
|
||||
tagline: '干啥都快人一步的 Vue 中后台系统框架',
|
||||
name: 'One-step Console',
|
||||
tagline: '像导播一样编排你的工作现场',
|
||||
logo: 'https://one-step-admin.hurui.me/logo.png',
|
||||
url: 'https://one-step-admin.hurui.me',
|
||||
images: [
|
||||
'https://one-step-admin.hurui.me/preview1.png',
|
||||
'https://one-step-admin.hurui.me/hero_preview.png',
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
@@ -47,7 +47,10 @@ export default defineConfig(({ mode, command }) => {
|
||||
},
|
||||
plugins: createVitePlugins(mode, command === 'build'),
|
||||
optimizeDeps: {
|
||||
exclude: ['@fantastic-admin/components'],
|
||||
exclude: [
|
||||
'@fantastic-admin/components',
|
||||
'@fantastic-admin/composables',
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PluginOption } from 'vite'
|
||||
import process from 'node:process'
|
||||
import { FantasticAutoImports, FantasticComponentsResolver, FantasticComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import { ComponentsAutoImports as FantasticAdminComponentsAutoImports, ComponentsResolver as FantasticAdminComponentsResolver, ComponentsType as FantasticAdminComponentsType } from '@fantastic-admin/components/resolver'
|
||||
import { ComposablesAutoImports as FantasticAdminComposablesAutoImports } from '@fantastic-admin/composables/resolver'
|
||||
import { createCopyrightPlugins as createFantasticAdminCopyrightPlugins } from '@fantastic-admin/copyright'
|
||||
import VitePluginSvgSpritemap from '@spiriit/vite-plugin-svg-spritemap'
|
||||
import vueLegacy from '@vitejs/plugin-legacy'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
@@ -37,6 +38,7 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
launchEditor: viteEnv.VITE_LAUNCH_EDITOR,
|
||||
}),
|
||||
|
||||
// https://github.com/yue1123/vite-plugin-env-parse
|
||||
envParse({
|
||||
dtsPath: 'src/types/env.d.ts',
|
||||
}),
|
||||
@@ -47,7 +49,8 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
'vue',
|
||||
'vue-router',
|
||||
'pinia',
|
||||
FantasticAutoImports,
|
||||
FantasticAdminComponentsAutoImports,
|
||||
FantasticAdminComposablesAutoImports,
|
||||
],
|
||||
dts: './src/types/auto-imports.d.ts',
|
||||
dirs: [
|
||||
@@ -63,10 +66,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
],
|
||||
dts: './src/types/components.d.ts',
|
||||
resolvers: [
|
||||
FantasticComponentsResolver(),
|
||||
FantasticAdminComponentsResolver(),
|
||||
],
|
||||
types: [
|
||||
FantasticComponentsType,
|
||||
FantasticAdminComponentsType,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -78,9 +81,10 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
// https://github.com/condorheroblog/vite-plugin-fake-server
|
||||
vitePluginFakeServer({
|
||||
logger: !isBuild,
|
||||
include: 'src/api/modules',
|
||||
include: 'src/api/fake_modules',
|
||||
enableProd: isBuild && viteEnv.VITE_BUILD_FAKE,
|
||||
}),
|
||||
|
||||
// https://github.com/nonzzz/vite-plugin-compression
|
||||
viteEnv.VITE_BUILD_COMPRESS && compression({
|
||||
exclude: [/\.(br)$/, /\.(gz)$/],
|
||||
@@ -105,7 +109,6 @@ export default function createVitePlugins(mode: string, isBuild = false) {
|
||||
(() => {
|
||||
const moduleId = 'virtual:fantastic-admin/turbo-console'
|
||||
const resolvedModuleId = `\0${moduleId}`
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-turbo-console-bridge',
|
||||
resolveId(id) {
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
"serve": "http-server ./dist -o",
|
||||
"serve:test": "http-server ./dist-test -o",
|
||||
"svgo": "svgo -f src/assets/icons",
|
||||
"generate:icons": "tsx ./scripts/generate.icons.ts",
|
||||
"generate:icons": "fa-iconify-tools",
|
||||
"lint": "vue-tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fantastic-admin/components": "workspace:*",
|
||||
"@fantastic-admin/composables": "workspace:*",
|
||||
"@fantastic-admin/settings": "workspace:*",
|
||||
"@fantastic-admin/types": "workspace:*",
|
||||
"@vee-validate/zod": "catalog:",
|
||||
@@ -27,7 +28,6 @@
|
||||
"eruda": "catalog:",
|
||||
"es-toolkit": "catalog:",
|
||||
"hotkeys-js": "catalog:",
|
||||
"lucide-vue-next": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"nprogress": "catalog:",
|
||||
"path-browserify": "catalog:",
|
||||
@@ -49,9 +49,9 @@
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clack/prompts": "catalog:",
|
||||
"@faker-js/faker": "catalog:",
|
||||
"@fantastic-admin/copyright": "workspace:*",
|
||||
"@fantastic-admin/iconify-tools": "workspace:*",
|
||||
"@iconify/vue": "catalog:",
|
||||
"@spiriit/vite-plugin-svg-spritemap": "catalog:",
|
||||
"@types/nprogress": "catalog:",
|
||||
@@ -66,7 +66,6 @@
|
||||
"postcss-nested": "catalog:",
|
||||
"sass-embedded": "catalog:",
|
||||
"svgo": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"unplugin-auto-import": "catalog:",
|
||||
"unplugin-turbo-console": "catalog:",
|
||||
"unplugin-vue-components": "catalog:",
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import * as p from '@clack/prompts'
|
||||
import { lookupCollection, lookupCollections } from '@iconify/json'
|
||||
|
||||
// 拿到全部图标集的原始数据
|
||||
const raw = await lookupCollections()
|
||||
|
||||
let lastChoose = fs.readFileSync(path.resolve(process.cwd(), 'src/iconify/index.json'), 'utf-8')
|
||||
lastChoose = JSON.parse(lastChoose)
|
||||
|
||||
// 取出可使用的图标集数据用于选择,并按名称排序
|
||||
const collections = Object.entries(raw).map(([id, item]) => ({
|
||||
...item,
|
||||
id,
|
||||
})).sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
p.intro('图标集生成工具')
|
||||
|
||||
/**
|
||||
* 分别会在对应目录下生成以下文件,其中(1)(3)用于离线下载并安装图标,(2)用于图标选择器使用
|
||||
* (1) src/iconify/index.json 记录用户交互信息
|
||||
* (2) src/iconify/data.json 包含多个图标集数据,仅记录图标名
|
||||
* (3) public/icons/*-raw.json 多个图标集的原始数据,独立存放,用于离线使用
|
||||
*/
|
||||
const answers = await p.group(
|
||||
{
|
||||
collections: () =>
|
||||
p.multiselect({
|
||||
message: '请选择需要生成的图标集',
|
||||
options: collections.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
hint: `${item.total} 个图标`,
|
||||
})),
|
||||
initialValues: lastChoose.collections,
|
||||
}),
|
||||
isOfflineUse: () =>
|
||||
p.confirm({
|
||||
message: '是否需要离线使用',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('操作已取消')
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const spinner = p.spinner()
|
||||
spinner.start('正在生成图标集...')
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/index.json'),
|
||||
{
|
||||
collections: answers.collections,
|
||||
isOfflineUse: answers.isOfflineUse,
|
||||
},
|
||||
)
|
||||
|
||||
const outputDir = path.resolve(process.cwd(), 'public/icons')
|
||||
await fs.ensureDir(outputDir)
|
||||
await fs.emptyDir(outputDir)
|
||||
|
||||
const collectionsMeta: object[] = []
|
||||
for (const info of answers.collections) {
|
||||
const setData = await lookupCollection(info)
|
||||
|
||||
collectionsMeta.push({
|
||||
prefix: setData.prefix,
|
||||
info: setData.info,
|
||||
icons: Object.keys(setData.icons),
|
||||
})
|
||||
|
||||
const offlineFilePath = path.join(outputDir, `${info}-raw.json`)
|
||||
|
||||
if (answers.isOfflineUse) {
|
||||
await fs.writeJSON(offlineFilePath, setData)
|
||||
}
|
||||
}
|
||||
|
||||
await fs.writeJSON(
|
||||
path.resolve(process.cwd(), 'src/iconify/data.json'),
|
||||
collectionsMeta,
|
||||
)
|
||||
|
||||
// 使用 spawn 运行 eslint
|
||||
const eslint = spawn('eslint', ['src/iconify/data.json', 'src/iconify/index.json', '--cache', '--fix'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
})
|
||||
|
||||
eslint.on('error', (err) => {
|
||||
p.log.error(`ESLint 执行失败: ${err.message}`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
eslint.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
p.log.error(`ESLint 执行失败,退出码: ${code}`)
|
||||
process.exit(code)
|
||||
}
|
||||
spinner.stop('图标集生成完成!')
|
||||
})
|
||||
@@ -51,7 +51,7 @@ function handleError(error: any) {
|
||||
useAppAccountStore().requestLogout()
|
||||
}
|
||||
else {
|
||||
faToast.error('Error', {
|
||||
useFaToast().error('Error', {
|
||||
description: error.message,
|
||||
})
|
||||
}
|
||||
@@ -70,7 +70,7 @@ api.interceptors.response.use(
|
||||
if (typeof response.data === 'object') {
|
||||
if (response.data.status === 1) {
|
||||
if (response.data.error) {
|
||||
faToast.warning('Warning', {
|
||||
useFaToast().warning('Warning', {
|
||||
description: response.data.error,
|
||||
})
|
||||
return Promise.reject(response.data)
|
||||
|
||||
@@ -32,7 +32,7 @@ const form = useForm({
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
loading.value = true
|
||||
appAccountStore.editPassword(values).then(async () => {
|
||||
faToast.success('模拟修改成功,请重新登录')
|
||||
useFaToast().success('模拟修改成功,请重新登录')
|
||||
appAccountStore.logout()
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
@@ -61,7 +61,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -75,7 +75,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -89,7 +89,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -90,7 +90,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -104,7 +104,7 @@ function testAccount(account: string) {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -113,7 +113,7 @@ function testAccount(account: string) {
|
||||
<FormField v-slot="{ componentField }" type="checkbox" name="remember">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<FaCheckbox v-bind="componentField">
|
||||
<FaCheckbox :model-value="componentField.modelValue" @update:model-value="componentField['onUpdate:modelValue']?.($event)">
|
||||
记住我
|
||||
</FaCheckbox>
|
||||
</FormControl>
|
||||
|
||||
@@ -63,7 +63,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -76,11 +76,11 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</template>
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
<FormDescription class="m-0">
|
||||
<FaPasswordStrength :password="value" />
|
||||
</FormDescription>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -94,7 +94,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -70,7 +70,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -81,7 +81,7 @@ function handleSendCaptcha() {
|
||||
<FaInputOTP :model-value="value" :name="componentField.name" :length="6" class="border-destructive" @update:model-value="val => setValue(val)" />
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -99,7 +99,7 @@ function handleSendCaptcha() {
|
||||
</FaInput>
|
||||
</FormControl>
|
||||
<Transition enter-active-class="transition-opacity" enter-from-class="opacity-0" leave-active-class="transition-opacity" leave-to-class="opacity-0">
|
||||
<FormMessage class="text-xs bottom-1 absolute" />
|
||||
<FormMessage class="text-xs m-0 bottom-1 absolute" />
|
||||
</Transition>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -80,13 +80,13 @@ export function useAppTabbar() {
|
||||
const index = appTabbarStore.list.findIndex(item => item.tabId === tabId)
|
||||
if (index < 0) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('关闭的标签页不存在', {
|
||||
!checkOnly && useFaToast().warning('关闭的标签页不存在', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
else if (appTabbarStore.list.length <= 1) {
|
||||
flag = false
|
||||
!checkOnly && faToast.warning('当前只有一个标签页,不可关闭', {
|
||||
!checkOnly && useFaToast().warning('当前只有一个标签页,不可关闭', {
|
||||
position: 'top-center',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
export function usePagination() {
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
sort: null as string | null,
|
||||
order: null as string | null,
|
||||
})
|
||||
|
||||
function getParams() {
|
||||
return {
|
||||
// page,size 和 from,limit 是分页的两种方式,方便兼容两种接口
|
||||
page: pagination.value.page,
|
||||
size: pagination.value.size,
|
||||
from: (pagination.value.page - 1) * pagination.value.size,
|
||||
limit: pagination.value.size,
|
||||
...(
|
||||
pagination.value.sort && pagination.value.order && {
|
||||
sort: pagination.value.sort,
|
||||
order: pagination.value.order,
|
||||
}
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async function onSizeChange(size: number) {
|
||||
pagination.value.size = size
|
||||
}
|
||||
|
||||
async function onCurrentChange(page: number) {
|
||||
pagination.value.page = page
|
||||
}
|
||||
|
||||
async function onSortChange(prop: string, order: string) {
|
||||
pagination.value.sort = prop
|
||||
pagination.value.order = order === 'ascending' ? 'asc' : 'desc'
|
||||
}
|
||||
|
||||
return {
|
||||
pagination,
|
||||
getParams,
|
||||
onSizeChange,
|
||||
onCurrentChange,
|
||||
onSortChange,
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user