Merge pull request #116 from LOG1997/96-ui-optimization
96 UI optimization
This commit is contained in:
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@@ -1433,42 +1433,36 @@ packages:
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm-musl@2.5.0':
|
||||
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-arm64-glibc@2.5.0':
|
||||
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-arm64-musl@2.5.0':
|
||||
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-linux-x64-glibc@2.5.0':
|
||||
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@parcel/watcher-linux-x64-musl@2.5.0':
|
||||
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@parcel/watcher-win32-arm64@2.5.0':
|
||||
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
|
||||
@@ -1539,67 +1533,56 @@ packages:
|
||||
resolution: {integrity: sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.52.0':
|
||||
resolution: {integrity: sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.52.0':
|
||||
resolution: {integrity: sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.52.0':
|
||||
resolution: {integrity: sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.52.0':
|
||||
resolution: {integrity: sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw==}
|
||||
@@ -1687,28 +1670,24 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.13':
|
||||
resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.13':
|
||||
resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.13':
|
||||
resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.13':
|
||||
resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==}
|
||||
@@ -1779,35 +1758,30 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-arm64-musl@2.9.5':
|
||||
resolution: {integrity: sha512-/gRBMnphS9E8riZ0LIbBhZ9Oy16A2rx/g3DGR0DcDBvUtkLfbL0lMu4s+sY85nkn9An15+cZ1ZK6d7AIqWahLA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tauri-apps/cli-linux-riscv64-gnu@2.9.5':
|
||||
resolution: {integrity: sha512-NOzjPF9YIBodjdkFcJmqINT0k3YDoR5ANM/jg6Z6s3Zmk8ScN6inI60jTxcfgfWyITiKsPy7GJyYou3Cm2XNzw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-gnu@2.9.5':
|
||||
resolution: {integrity: sha512-SfGbwgvTphM5y+J91NyU/psleMUlyyPkZyDCFg8WU1HX8DpKUT3Vwhb/W1xpUBGb56tJgGCO46FCVkr8w4Areg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tauri-apps/cli-linux-x64-musl@2.9.5':
|
||||
resolution: {integrity: sha512-ZfeoiASAOGDzyvN+TDAg8A1pCeS082h4uc0vZKvtWUN+9QBIMfz0yJwltAv+SN/afap6NS6DVkbPV3UVuI9V5A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tauri-apps/cli-win32-arm64-msvc@2.9.5':
|
||||
resolution: {integrity: sha512-ulg7irow+ekjaK4inFHVq7m1KQebDSYNb17DFKV+h+x7qnLZymz2gHK7df2u4YyEjqvzwRd3AJpU3HNxRurSFQ==}
|
||||
@@ -3988,28 +3962,24 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.1:
|
||||
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.1:
|
||||
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||
|
||||
1
src/components.d.ts
vendored
1
src/components.d.ts
vendored
@@ -60,6 +60,7 @@ declare module 'vue' {
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Sonner: typeof import('./components/ui/sonner/Sonner.vue')['default']
|
||||
SvgIcon: typeof import('./components/SvgIcon/index.vue')['default']
|
||||
Switch: typeof import('./components/ui/switch/Switch.vue')['default']
|
||||
ToTop: typeof import('./components/ToTop/index.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
38
src/components/ui/switch/Switch.vue
Normal file
38
src/components/ui/switch/Switch.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import type { SwitchRootEmits, SwitchRootProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import {
|
||||
SwitchRoot,
|
||||
SwitchThumb,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SwitchRootProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const emits = defineEmits<SwitchRootEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SwitchRoot
|
||||
v-slot="slotProps"
|
||||
data-slot="switch"
|
||||
v-bind="forwarded"
|
||||
:class="cn(
|
||||
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
<SwitchThumb
|
||||
data-slot="switch-thumb"
|
||||
:class="cn('bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0')"
|
||||
>
|
||||
<slot name="thumb" v-bind="slotProps" />
|
||||
</SwitchThumb>
|
||||
</SwitchRoot>
|
||||
</template>
|
||||
1
src/components/ui/switch/index.ts
Normal file
1
src/components/ui/switch/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Switch } from "./Switch.vue"
|
||||
@@ -15,7 +15,7 @@ export const configRoutes = {
|
||||
{
|
||||
path: '/log-lottery/config/person',
|
||||
name: 'PersonConfig',
|
||||
component: () => import('@/views/Config/Person/PersonConfig.vue'),
|
||||
component: () => import('@/views/Config/Person/index.vue'),
|
||||
meta: {
|
||||
title: i18n.global.t('sidebar.personConfiguration'),
|
||||
icon: 'person',
|
||||
@@ -37,7 +37,7 @@ export const configRoutes = {
|
||||
{
|
||||
path: '/log-lottery/config/person/already',
|
||||
name: 'AlreadyPerson',
|
||||
component: () => import('@/views/Config/Person/PersonAlready.vue'),
|
||||
component: () => import('@/views/Config/Person/PersonAlready/index.vue'),
|
||||
meta: {
|
||||
title: i18n.global.t('sidebar.winnerList'),
|
||||
icon: 'already',
|
||||
|
||||
@@ -18,7 +18,7 @@ export const useGlobalConfig = defineStore('global', {
|
||||
cardColor: '#ff79c6',
|
||||
cardWidth: 140,
|
||||
cardHeight: 200,
|
||||
textColor: '#ffffff',
|
||||
textColor: '#00000000',
|
||||
luckyCardColor: '#ECB1AC',
|
||||
textSize: 30,
|
||||
patternColor: '#1b66c9',
|
||||
@@ -280,7 +280,7 @@ export const useGlobalConfig = defineStore('global', {
|
||||
cardColor: '#ff79c6',
|
||||
cardWidth: 140,
|
||||
cardHeight: 200,
|
||||
textColor: '#ffffff',
|
||||
textColor: '#00000000',
|
||||
luckyCardColor: '#ECB1AC',
|
||||
textSize: 30,
|
||||
patternColor: '#1b66c9',
|
||||
|
||||
@@ -67,7 +67,7 @@ ul {
|
||||
/* IE9+, News */
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
/* @theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
@@ -103,9 +103,9 @@ ul {
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
} */
|
||||
|
||||
:root {
|
||||
/* :root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
@@ -173,8 +173,9 @@ ul {
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
}
|
||||
*/
|
||||
|
||||
@layer base {
|
||||
/* @layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
@@ -182,4 +183,4 @@ ul {
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
} */
|
||||
@@ -57,13 +57,13 @@ const disabledStyle = computed(() => {
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex justify-center items-center max-w-xs" :style="disabledStyle">
|
||||
<Popover v-model:open="open">
|
||||
<Popover v-model:open="open" class="w-full">
|
||||
<PopoverTrigger as-child :disabled="browserDisabled || disabled">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
:aria-expanded="open"
|
||||
class="w-full justify-between truncate bg-transparent hover:bg-transparent hover:text-inherit"
|
||||
class="w-full justify-between truncate hover:bg-transparent hover:text-inherit"
|
||||
@click="getFonts"
|
||||
>
|
||||
<span class="w-7/8 text-left truncate" :style="{ fontFamily: `${selectedFont}` }">
|
||||
@@ -72,7 +72,7 @@ const disabledStyle = computed(() => {
|
||||
<ChevronsUpDownIcon class="opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-full p-0">
|
||||
<PopoverContent class="w-full p-0 bg-base-100">
|
||||
<Command>
|
||||
<CommandInput class="h-9" placeholder="Search framework..." />
|
||||
<CommandList @scroll="handleScroll">
|
||||
@@ -82,7 +82,7 @@ const disabledStyle = computed(() => {
|
||||
v-for="[key, value] in fonts"
|
||||
:key="key"
|
||||
:value="key"
|
||||
class="w-full hover:bg-gray-200/50"
|
||||
class="w-full hover:bg-gray-200/60"
|
||||
@select="selectFont(key)"
|
||||
>
|
||||
<Popover :open="debouncedActiveKey === key" class="w-full">
|
||||
@@ -96,7 +96,7 @@ const disabledStyle = computed(() => {
|
||||
/>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-2" side="right" @mouseleave="handelActiveKey('')" @mouseenter="handelActiveKey(key)">
|
||||
<PopoverContent class="p-2 bg-base-100" side="right" @mouseleave="handelActiveKey('')" @mouseenter="handelActiveKey(key)">
|
||||
<PopoverArrow />
|
||||
<Command>
|
||||
<CommandGroup>
|
||||
@@ -104,7 +104,7 @@ const disabledStyle = computed(() => {
|
||||
v-for="child in value"
|
||||
:key="child.value"
|
||||
:value="child.value"
|
||||
class="w-full hover:bg-gray-200/50"
|
||||
class="w-full hover:bg-gray-200/60"
|
||||
:style="{ fontFamily: `${key}` }"
|
||||
@select="selectFont(child.value)"
|
||||
>
|
||||
|
||||
@@ -83,6 +83,11 @@ const patternColorValue = defineModel<string>('patternColorValue')
|
||||
<div class="flex flex-col items-center max-w-xs gap-1 form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">{{ t('table.textColor') }}</span>
|
||||
<div class="tooltip" data-tip="设置文本颜色会覆盖标题样式">
|
||||
<button class="btn btn-circle h-4 hover:bg-base-300">
|
||||
?
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<ColorPicker v-model="textColorValue" v-model:pure-color="textColorValue" />
|
||||
</div>
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
<!-- eslint-disable vue/no-parsing-error -->
|
||||
<script setup lang='ts'>
|
||||
import type { IPersonConfig } from '@/types/storeType'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import i18n from '@/locales/i18n'
|
||||
import useStore from '@/store'
|
||||
|
||||
const { t } = useI18n()
|
||||
const personConfig = useStore().personConfig
|
||||
|
||||
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
|
||||
// const personList = ref<any[]>(
|
||||
// alreadyPersonList
|
||||
// )
|
||||
|
||||
// const deleteAll = () => {
|
||||
// personConfig.deleteAllPerson()
|
||||
// }
|
||||
|
||||
const isDetail = ref(false)
|
||||
function handleMoveNotPerson(row: IPersonConfig) {
|
||||
personConfig.moveAlreadyToNot(row)
|
||||
}
|
||||
|
||||
const tableColumnsList = [
|
||||
{
|
||||
label: i18n.global.t('data.number'),
|
||||
props: 'uid',
|
||||
sort: true,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.name'),
|
||||
props: 'name',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.avatar'),
|
||||
props: 'avatar',
|
||||
formatValue(row: any) {
|
||||
return row.avatar ? `<img src="${row.avatar}" alt="avatar" style="width: 50px; height: 50px;"/>` : '-'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.department'),
|
||||
props: 'department',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.identity'),
|
||||
props: 'identity',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.prizeName'),
|
||||
props: 'prizeName',
|
||||
sort: true,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.operation'),
|
||||
actions: [
|
||||
{
|
||||
label: i18n.global.t('data.removePerson'),
|
||||
type: 'btn-info',
|
||||
onClick: (row: IPersonConfig) => {
|
||||
handleMoveNotPerson(row)
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
const tableColumnsDetail = [
|
||||
{
|
||||
label: i18n.global.t('data.number'),
|
||||
props: 'uid',
|
||||
sort: true,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.number'),
|
||||
props: 'name',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.avatar'),
|
||||
props: 'avatar',
|
||||
formatValue(row: any) {
|
||||
return row.avatar ? `<img src="${row.avatar}" alt="avatar" style="width: 50px; height: 50px;"/>` : '-'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.department'),
|
||||
props: 'department',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.identity'),
|
||||
props: 'identity',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.prizeName'),
|
||||
props: 'prizeName',
|
||||
sort: true,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.prizeTime'),
|
||||
props: 'prizeTime',
|
||||
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.operation'),
|
||||
actions: [
|
||||
{
|
||||
label: i18n.global.t('data.removePerson'),
|
||||
type: 'btn-info',
|
||||
onClick: (row: IPersonConfig) => {
|
||||
handleMoveNotPerson(row)
|
||||
},
|
||||
},
|
||||
|
||||
],
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="overflow-y-auto">
|
||||
<PageHeader :title="t('viewTitle.winnerManagement')">
|
||||
<template #buttons>
|
||||
<div class="flex items-center justify-start gap-10">
|
||||
<div>
|
||||
<span>{{ t('table.luckyPeopleNumber') }}:</span>
|
||||
<span>{{ alreadyPersonList.length }}</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="form-control">
|
||||
<label class="cursor-pointer label">
|
||||
<span class="label-text">{{ t('table.detail') }}:</span>
|
||||
<input v-model="isDetail" type="checkbox" class="border-solid toggle toggle-primary border-1">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<DaiysuiTable v-if="!isDetail" :table-columns="tableColumnsList" :data="alreadyPersonList" />
|
||||
|
||||
<DaiysuiTable v-if="isDetail" :table-columns="tableColumnsDetail" :data="alreadyPersonDetail" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped></style>
|
||||
58
src/views/Config/Person/PersonAlready/columns.ts
Normal file
58
src/views/Config/Person/PersonAlready/columns.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { IPersonConfig } from '@/types/storeType'
|
||||
import i18n from '@/locales/i18n'
|
||||
|
||||
interface IColumnsProps {
|
||||
showPrizeTime?: boolean
|
||||
handleDeletePerson: (row: IPersonConfig) => void
|
||||
}
|
||||
|
||||
export function tableColumns(props: IColumnsProps) {
|
||||
return [
|
||||
{
|
||||
label: i18n.global.t('data.number'),
|
||||
props: 'uid',
|
||||
sort: true,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.name'),
|
||||
props: 'name',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.avatar'),
|
||||
props: 'avatar',
|
||||
formatValue(row: any) {
|
||||
return row.avatar ? `<img src="${row.avatar}" alt="avatar" style="width: 50px; height: 50px;"/>` : '-'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.department'),
|
||||
props: 'department',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.identity'),
|
||||
props: 'identity',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.prizeName'),
|
||||
props: 'prizeName',
|
||||
sort: true,
|
||||
},
|
||||
props.showPrizeTime && {
|
||||
label: i18n.global.t('data.prizeTime'),
|
||||
props: 'prizeTime',
|
||||
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('data.operation'),
|
||||
actions: [
|
||||
{
|
||||
label: i18n.global.t('data.removePerson'),
|
||||
type: 'btn-info',
|
||||
onClick: (row: IPersonConfig) => {
|
||||
props.handleDeletePerson(row)
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
43
src/views/Config/Person/PersonAlready/index.vue
Normal file
43
src/views/Config/Person/PersonAlready/index.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<script setup lang='ts'>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { useViewModel } from './useViewModel'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { alreadyPersonList, alreadyPersonDetail, isDetail, tableColumnsList, tableColumnsDetail } = useViewModel()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="overflow-y-auto">
|
||||
<PageHeader :title="t('viewTitle.winnerManagement')">
|
||||
<template #buttons>
|
||||
<div class="flex items-center justify-start gap-10">
|
||||
<div>
|
||||
<span>{{ t('table.luckyPeopleNumber') }}:</span>
|
||||
<span>{{ alreadyPersonList.length }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="form-control">
|
||||
<label class="label flex items-center gap-2">
|
||||
<p class="label-text">{{ t('table.detail') }}:</p>
|
||||
<div class="flex items-center">
|
||||
<Switch v-model="isDetail" class="cursor-pointer" />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<DaiysuiTable v-if="!isDetail" :table-columns="tableColumnsList" :data="alreadyPersonList" />
|
||||
|
||||
<DaiysuiTable v-if="isDetail" :table-columns="tableColumnsDetail" :data="alreadyPersonDetail" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped></style>
|
||||
26
src/views/Config/Person/PersonAlready/useViewModel.ts
Normal file
26
src/views/Config/Person/PersonAlready/useViewModel.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { IPersonConfig } from '@/types/storeType'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import useStore from '@/store'
|
||||
import { tableColumns } from './columns'
|
||||
|
||||
export function useViewModel() {
|
||||
const personConfig = useStore().personConfig
|
||||
|
||||
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
|
||||
|
||||
const isDetail = ref(false)
|
||||
function handleMoveNotPerson(row: IPersonConfig) {
|
||||
personConfig.moveAlreadyToNot(row)
|
||||
}
|
||||
|
||||
const tableColumnsList = tableColumns({ showPrizeTime: false, handleDeletePerson: handleMoveNotPerson })
|
||||
const tableColumnsDetail = tableColumns({ showPrizeTime: true, handleDeletePerson: handleMoveNotPerson })
|
||||
return {
|
||||
alreadyPersonList,
|
||||
alreadyPersonDetail,
|
||||
isDetail,
|
||||
tableColumnsList,
|
||||
tableColumnsDetail,
|
||||
}
|
||||
}
|
||||
@@ -1,143 +1,13 @@
|
||||
<script setup lang='ts'>
|
||||
import type { IPrizeConfig } from '@/types/storeType'
|
||||
import localforage from 'localforage'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { Grip } from 'lucide-vue-next'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import i18n from '@/locales/i18n'
|
||||
import useStore from '@/store'
|
||||
import { usePrizeConfig } from './usePrizeConfig'
|
||||
|
||||
const { addPrize, resetDefault, delAll, delItem, prizeList, currentPrize, selectedPrize, submitData, changePrizePerson, changePrizeStatus, selectPrize, localImageList } = usePrizeConfig()
|
||||
const { t } = useI18n()
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
})
|
||||
const prizeConfig = useStore().prizeConfig
|
||||
const globalConfig = useStore().globalConfig
|
||||
const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
||||
|
||||
const { getImageList: localImageList } = storeToRefs(globalConfig)
|
||||
const prizeList = ref(cloneDeep(localPrizeList.value))
|
||||
const imgList = ref<any[]>([])
|
||||
|
||||
const selectedPrize = ref<IPrizeConfig | null>()
|
||||
|
||||
function addPrize() {
|
||||
const defaultPrizeCOnfig: IPrizeConfig = {
|
||||
id: new Date().getTime().toString(),
|
||||
name: i18n.global.t('data.prizeName'),
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: false,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isUsed: false,
|
||||
isShow: true,
|
||||
frequency: 1,
|
||||
}
|
||||
prizeConfig.addPrizeConfig(defaultPrizeCOnfig)
|
||||
}
|
||||
|
||||
function selectPrize(item: IPrizeConfig) {
|
||||
selectedPrize.value = item
|
||||
selectedPrize.value.isUsedCount = 0
|
||||
selectedPrize.value.isUsed = false
|
||||
|
||||
if (selectedPrize.value.separateCount.countList.length > 1) {
|
||||
return
|
||||
}
|
||||
selectedPrize.value.separateCount = {
|
||||
enable: true,
|
||||
countList: [
|
||||
{
|
||||
id: '0',
|
||||
count: item.count,
|
||||
isUsedCount: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
function changePrizeStatus(item: IPrizeConfig) {
|
||||
// if (item.isUsed == true) {
|
||||
// item.isUsedCount = 0;
|
||||
// if (item.separateCount && item.separateCount.countList.length) {
|
||||
// item.separateCount.countList.forEach((countItem: any) => {
|
||||
// countItem.isUsedCount = 0;
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// item.isUsedCount = item.count;
|
||||
// if (item.separateCount && item.separateCount.countList.length) {
|
||||
// item.separateCount.countList.forEach((countItem: any) => {
|
||||
// countItem.isUsedCount = countItem.count;
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
item.isUsed ? item.isUsedCount = 0 : item.isUsedCount = item.count
|
||||
item.separateCount.countList = []
|
||||
item.isUsed = !item.isUsed
|
||||
}
|
||||
|
||||
function changePrizePerson(item: IPrizeConfig) {
|
||||
let indexPrize = -1
|
||||
for (let i = 0; i < prizeList.value.length; i++) {
|
||||
if (prizeList.value[i].id === item.id) {
|
||||
indexPrize = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (indexPrize > -1) {
|
||||
prizeList.value[indexPrize].separateCount.countList = []
|
||||
prizeList.value[indexPrize].isUsed ? prizeList.value[indexPrize].isUsedCount = prizeList.value[indexPrize].count : prizeList.value[indexPrize].isUsedCount = 0
|
||||
}
|
||||
}
|
||||
function submitData(value: any) {
|
||||
selectedPrize.value!.separateCount.countList = value
|
||||
selectedPrize.value = null
|
||||
}
|
||||
function resetDefault() {
|
||||
prizeConfig.resetDefault()
|
||||
}
|
||||
|
||||
async function getImageDbStore() {
|
||||
const keys = await imageDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
imageDbStore.iterate((value, key) => {
|
||||
imgList.value.push({
|
||||
key,
|
||||
value,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function delItem(item: IPrizeConfig) {
|
||||
prizeConfig.deletePrizeConfig(item.id)
|
||||
}
|
||||
async function delAll() {
|
||||
await prizeConfig.deleteAllPrizeConfig()
|
||||
}
|
||||
onMounted(() => {
|
||||
getImageDbStore()
|
||||
})
|
||||
watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
prizeConfig.setPrizeConfig(val)
|
||||
}, { deep: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -176,7 +46,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
>
|
||||
<div
|
||||
v-for="item in prizeList" :key="item.id" class="flex items-center justify-center gap-10 py-5"
|
||||
:class="currentPrize.id === item.id ? 'border-1 border-dotted rounded-xl' : null"
|
||||
:class="currentPrize.id === item.id ? 'border border-dotted rounded-xl' : null"
|
||||
>
|
||||
<label class="flex items-center justify-center max-w-xs px-2 handle form-control">
|
||||
<Grip class="w-10 h-10 cursor-move handle" />
|
||||
@@ -195,7 +65,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
<span class="label-text">{{ t('table.fullParticipation') }}</span>
|
||||
</div>
|
||||
<input
|
||||
type="checkbox" :checked="item.isAll" class="border-solid checkbox checkbox-secondary border-1"
|
||||
type="checkbox" :checked="item.isAll" class="border-solid checkbox checkbox-secondary border"
|
||||
@change="item.isAll = !item.isAll"
|
||||
>
|
||||
</label>
|
||||
@@ -216,7 +86,7 @@ watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
<span class="label-text">{{ t('table.isDone') }}</span>
|
||||
</div>
|
||||
<input
|
||||
type="checkbox" :checked="item.isUsed" class="border-solid checkbox checkbox-secondary border-1"
|
||||
type="checkbox" :checked="item.isUsed" class="border-solid checkbox checkbox-secondary border"
|
||||
@change="changePrizeStatus(item)"
|
||||
>
|
||||
</label>
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import type { IPrizeConfig } from '@/types/storeType'
|
||||
import localforage from 'localforage'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { Grip } from 'lucide-vue-next'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import { toast } from 'vue-sonner'
|
||||
import i18n from '@/locales/i18n'
|
||||
import useStore from '@/store'
|
||||
|
||||
export function usePrizeConfig() {
|
||||
const { t } = useI18n()
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
})
|
||||
@@ -84,6 +79,41 @@ export function usePrizeConfig() {
|
||||
|
||||
function delItem(item: IPrizeConfig) {
|
||||
prizeConfig.deletePrizeConfig(item.id)
|
||||
toast.success('删除成功')
|
||||
}
|
||||
function addPrize() {
|
||||
const defaultPrizeCOnfig: IPrizeConfig = {
|
||||
id: new Date().getTime().toString(),
|
||||
name: i18n.global.t('data.prizeName'),
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: false,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isUsed: false,
|
||||
isShow: true,
|
||||
frequency: 1,
|
||||
}
|
||||
prizeList.value.push(defaultPrizeCOnfig)
|
||||
toast.success('添加成功')
|
||||
}
|
||||
function resetDefault() {
|
||||
prizeConfig.resetDefault()
|
||||
prizeList.value = cloneDeep(localPrizeList.value)
|
||||
toast.success('重置成功')
|
||||
}
|
||||
async function delAll() {
|
||||
prizeList.value = []
|
||||
toast.success('删除成功')
|
||||
}
|
||||
onMounted(() => {
|
||||
getImageDbStore()
|
||||
@@ -93,7 +123,17 @@ export function usePrizeConfig() {
|
||||
}, { deep: true })
|
||||
|
||||
return {
|
||||
addPrize,
|
||||
resetDefault,
|
||||
delAll,
|
||||
delItem,
|
||||
prizeList,
|
||||
currentPrize,
|
||||
|
||||
selectedPrize,
|
||||
submitData,
|
||||
changePrizePerson,
|
||||
changePrizeStatus,
|
||||
selectPrize,
|
||||
localImageList,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,113 +1,29 @@
|
||||
<script setup lang='ts'>
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
import { ChevronRight, ChevronsUpDownIcon } from 'lucide-vue-next'
|
||||
import { PopoverArrow } from 'reka-ui'
|
||||
import { ref } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover'
|
||||
|
||||
import { useLocalFonts } from '@/hooks/useLocalFonts'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const { getFonts, disabled, fonts } = useLocalFonts()
|
||||
const open = ref(false)
|
||||
const activeKey = ref('Arial')
|
||||
const debouncedActiveKey = refDebounced(activeKey, 20)
|
||||
const selectedFont = ref('')
|
||||
|
||||
function selectFont(selectedValue: any) {
|
||||
open.value = false
|
||||
activeKey.value = ''
|
||||
selectedFont.value = selectedValue
|
||||
}
|
||||
|
||||
function handelActiveKey(val: string) {
|
||||
activeKey.value = val
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
activeKey.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex justify-center items-center">
|
||||
<Popover v-model:open="open">
|
||||
<PopoverTrigger as-child :disabled="disabled">
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
:aria-expanded="open"
|
||||
class="w-[200px] justify-between"
|
||||
@click="getFonts"
|
||||
>
|
||||
{{ selectedFont || "选择字体..." }}
|
||||
<ChevronsUpDownIcon class="opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput class="h-9" placeholder="Search framework..." />
|
||||
<CommandList @scroll="handleScroll">
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="[key, value] in fonts"
|
||||
:key="key"
|
||||
:value="key"
|
||||
class="w-full hover:bg-gray-200/50"
|
||||
@select="selectFont(key)"
|
||||
>
|
||||
<Popover :open="debouncedActiveKey === key" class="w-full">
|
||||
<PopoverTrigger class="w-full">
|
||||
<div :style="{ fontFamily: `${key}` }" class="w-full flex justify-between items-center" @mouseleave="handelActiveKey('')" @mouseenter="handelActiveKey(key)">
|
||||
{{ key }}
|
||||
<ChevronRight
|
||||
:class="cn(
|
||||
'ml-auto',
|
||||
)"
|
||||
/>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-2" side="right" @mouseleave="handelActiveKey('')" @mouseenter="handelActiveKey(key)">
|
||||
<PopoverArrow />
|
||||
<Command>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="child in value"
|
||||
:key="child.value"
|
||||
:value="child.value"
|
||||
class="w-full hover:bg-gray-200/50"
|
||||
:style="{ fontFamily: `${key}` }"
|
||||
@select="selectFont(child.value)"
|
||||
>
|
||||
{{ child.name }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div>
|
||||
<h2 class="text-3xl animate-pulse bg-linear-to-r from-primary via-secondary to-accent bg-clip-text text-transparent">
|
||||
两京一十三省
|
||||
</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
|
||||
<h2>两京一十三省</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
.dark-title {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<script setup lang='ts'>
|
||||
import type { CSSProperties } from 'vue'
|
||||
import { computed, toRefs } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useRouter } from 'vue-router'
|
||||
import { rgbToHex } from '@/utils/color'
|
||||
|
||||
interface Props {
|
||||
textSize: number
|
||||
@@ -18,24 +19,21 @@ interface Props {
|
||||
const props = defineProps<Props>()
|
||||
const router = useRouter()
|
||||
const { tableData, textSize, textColor, topTitle, setDefaultPersonList, titleFont, titleFontSyncGlobal } = toRefs(props)
|
||||
|
||||
const isTextColor = computed(() => {
|
||||
return rgbToHex(textColor.value) !== '#00000000'
|
||||
})
|
||||
const titleStyle = computed(() => {
|
||||
const baseStyle = {
|
||||
const style: CSSProperties = {
|
||||
fontSize: `${textSize.value * 1.5}px`,
|
||||
color: textColor.value,
|
||||
}
|
||||
if (!titleFontSyncGlobal.value) {
|
||||
style.fontFamily = titleFont.value
|
||||
}
|
||||
if (isTextColor.value) {
|
||||
style.color = textColor.value
|
||||
}
|
||||
|
||||
if (titleFontSyncGlobal.value) {
|
||||
return {
|
||||
...baseStyle,
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
...baseStyle,
|
||||
fontFamily: titleFont.value,
|
||||
}
|
||||
}
|
||||
return style
|
||||
})
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
@@ -43,7 +41,8 @@ const { t } = useI18n()
|
||||
<template>
|
||||
<div class="absolute z-10 flex flex-col items-center justify-center -translate-x-1/2 left-1/2">
|
||||
<h2
|
||||
class="pt-12 m-0 mb-12 tracking-wide text-center leading-12 header-title"
|
||||
class="pt-12 m-0 mb-12 tracking-wide text-center leading-12"
|
||||
:class="{ 'animate-pulse bg-linear-to-r from-primary via-secondary to-accent bg-clip-text text-transparent': !isTextColor }"
|
||||
:style="titleStyle"
|
||||
>
|
||||
{{ topTitle }}
|
||||
|
||||
@@ -39,7 +39,8 @@ async function getImageStoreItem(item: any): Promise<string> {
|
||||
let image = ''
|
||||
if (item.url === 'Storage') {
|
||||
const key = item.id
|
||||
image = await imageDbStore.getItem(key) as string
|
||||
const imageData = await imageDbStore.getItem(key) as any
|
||||
image = imageData.dataUrl
|
||||
}
|
||||
else {
|
||||
image = item.url
|
||||
|
||||
Reference in New Issue
Block a user