@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "log-lottery",
|
||||
"private": true,
|
||||
"version": "0.5.2",
|
||||
"version": "0.5.3",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -77,7 +77,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "app"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
@@ -21,5 +21,5 @@ tauri-build = { version = "2.5.3", features = [] }
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
tauri = { version = "2.9.4", features = [] }
|
||||
tauri = { version = "2.9.4", features = ["devtools"] }
|
||||
tauri-plugin-log = "2"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "log-lottery",
|
||||
"version": "0.5.2",
|
||||
"version": "0.5.3",
|
||||
"identifier": "to2026.xyz",
|
||||
"build": {
|
||||
"frontendDist": "../dist",
|
||||
|
||||
@@ -2,61 +2,61 @@ import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosReq
|
||||
import axios from 'axios'
|
||||
|
||||
class Request {
|
||||
private instance: AxiosInstance
|
||||
private instance: AxiosInstance
|
||||
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
this.instance = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 10000,
|
||||
...config,
|
||||
})
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
this.instance = axios.create({
|
||||
baseURL: '/api',
|
||||
timeout: 10000,
|
||||
...config,
|
||||
})
|
||||
|
||||
// 添加请求拦截器
|
||||
this.instance.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
// 在发送请求之前做些什么
|
||||
console.log('请求拦截器被触发')
|
||||
// 添加请求拦截器
|
||||
this.instance.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
// 在发送请求之前做些什么
|
||||
console.log('请求拦截器被触发')
|
||||
|
||||
return config
|
||||
},
|
||||
(error: any) => {
|
||||
// 对请求错误做些什么
|
||||
console.error('请求拦截器发生错误:', error)
|
||||
return config
|
||||
},
|
||||
(error: any) => {
|
||||
// 对请求错误做些什么
|
||||
console.error('请求拦截器发生错误:', error)
|
||||
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
// 添加响应拦截器
|
||||
this.instance.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
// 对响应数据做些什么
|
||||
console.log('响应拦截器被触发')
|
||||
const responseData = response.data
|
||||
// 添加响应拦截器
|
||||
this.instance.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
// 对响应数据做些什么
|
||||
console.log('响应拦截器被触发')
|
||||
const responseData = response.data
|
||||
|
||||
return responseData
|
||||
},
|
||||
(error: any) => {
|
||||
// 对响应错误做些什么
|
||||
console.error('响应拦截器发生错误:', error)
|
||||
return responseData
|
||||
},
|
||||
(error: any) => {
|
||||
// 对响应错误做些什么
|
||||
console.error('响应拦截器发生错误:', error)
|
||||
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
public async request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.instance.request(config)
|
||||
public async request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||
const response: AxiosResponse<T> = await this.instance.request(config)
|
||||
|
||||
return response.data
|
||||
}
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
// 函数
|
||||
function request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||
const instance = new Request(config)
|
||||
const instance = new Request(config)
|
||||
|
||||
return instance.request(config)
|
||||
return instance.request(config)
|
||||
}
|
||||
|
||||
export default request
|
||||
|
||||
@@ -3,28 +3,28 @@ import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as any,
|
||||
default: [] as any[],
|
||||
},
|
||||
tableColumns: {
|
||||
type: Array,
|
||||
default: [] as any[],
|
||||
},
|
||||
data: {
|
||||
type: Array as any,
|
||||
default: [] as any[],
|
||||
},
|
||||
tableColumns: {
|
||||
type: Array,
|
||||
default: [] as any[],
|
||||
},
|
||||
})
|
||||
const { t } = useI18n()
|
||||
const dataColumns = computed<any[]>(() => {
|
||||
// 不带有actions的列
|
||||
const columns = props.tableColumns.filter((item: any) => !item.actions)
|
||||
// 不带有actions的列
|
||||
const columns = props.tableColumns.filter((item: any) => !item.actions)
|
||||
|
||||
return columns
|
||||
return columns
|
||||
})
|
||||
|
||||
const actionsColumns = computed<any[]>(() => {
|
||||
// 带有actions的列
|
||||
const columns = props.tableColumns.filter((item: any) => item.actions)
|
||||
// 带有actions的列
|
||||
const columns = props.tableColumns.filter((item: any) => item.actions)
|
||||
|
||||
return columns
|
||||
return columns
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,40 +3,40 @@ import { onMounted, ref, toRefs } from 'vue'
|
||||
import i18n from '@/locales/i18n'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
desc?: string
|
||||
cancelText?: string
|
||||
submitText?: string
|
||||
submitFunc?: () => void
|
||||
cancelFunc?: () => void
|
||||
title: string
|
||||
desc?: string
|
||||
cancelText?: string
|
||||
submitText?: string
|
||||
submitFunc?: () => void
|
||||
cancelFunc?: () => void
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
cancelText: i18n.global.t('button.cancel'),
|
||||
submitText: i18n.global.t('button.confirm'),
|
||||
cancelFunc: () => {},
|
||||
cancelText: i18n.global.t('button.cancel'),
|
||||
submitText: i18n.global.t('button.confirm'),
|
||||
cancelFunc: () => {},
|
||||
})
|
||||
const visible = defineModel('visible', {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
|
||||
const dialogRef = ref <HTMLDialogElement | null> (null)
|
||||
function defaultCancelFunc() {
|
||||
dialogRef.value?.close()
|
||||
dialogRef.value?.close()
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
dialogRef.value?.showModal()
|
||||
dialogRef.value?.showModal()
|
||||
}
|
||||
defineExpose({
|
||||
showDialog,
|
||||
closed,
|
||||
showDialog,
|
||||
closed,
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
dialogRef.value?.addEventListener('close', () => {
|
||||
visible.value = false
|
||||
})
|
||||
dialogRef.value?.addEventListener('close', () => {
|
||||
visible.value = false
|
||||
})
|
||||
})
|
||||
const { title, desc, cancelText, submitText, submitFunc, cancelFunc = defaultCancelFunc } = toRefs(props)
|
||||
</script>
|
||||
|
||||
@@ -4,16 +4,16 @@ import { ref } from 'vue'
|
||||
const drawerTriggerRef = ref <HTMLDialogElement | null> (null)
|
||||
const visible = ref(false)
|
||||
function showDrawer() {
|
||||
drawerTriggerRef.value?.click()
|
||||
visible.value = true
|
||||
drawerTriggerRef.value?.click()
|
||||
visible.value = true
|
||||
}
|
||||
function closeDrawer() {
|
||||
drawerTriggerRef.value?.click()
|
||||
visible.value = false
|
||||
drawerTriggerRef.value?.click()
|
||||
visible.value = false
|
||||
}
|
||||
defineExpose({
|
||||
showDrawer,
|
||||
closeDrawer,
|
||||
showDrawer,
|
||||
closeDrawer,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,38 +2,38 @@
|
||||
import type { IFileData } from './type'
|
||||
import { ListMusic, Upload, X } from 'lucide-vue-next'
|
||||
import { ref } from 'vue'
|
||||
import { getBlobObjectUrl, readFileAsJsonData, readFileData, readFileDataAsBlob } from '@/utils/file'
|
||||
import { getBlobObjectUrl, readFileAsJsonData, readFileDataAsBlob } from '@/utils/file'
|
||||
|
||||
const props = defineProps<{
|
||||
limitType?: string
|
||||
mode?: 'file' | 'json'
|
||||
limitType?: string
|
||||
mode?: 'file' | 'json'
|
||||
}>()
|
||||
|
||||
const emits = defineEmits<{
|
||||
uploadFile: [fileData: IFileData | null]
|
||||
uploadFile: [fileData: IFileData | null]
|
||||
}>()
|
||||
const originFileName = ref<string | null>(null)
|
||||
const fileData = ref<IFileData | null>(null)
|
||||
|
||||
async function handleFileChange(e: Event) {
|
||||
const file = ((e.target as HTMLInputElement).files as FileList)[0]
|
||||
const type = file.type
|
||||
if (props.mode === 'json') {
|
||||
const fileRes = await readFileAsJsonData(file)
|
||||
const jsonData = JSON.parse(fileRes)
|
||||
fileData.value = { data: jsonData, fileName: file.name, type }
|
||||
originFileName.value = file.name
|
||||
const file = ((e.target as HTMLInputElement).files as FileList)[0]
|
||||
const type = file.type
|
||||
if (props.mode === 'json') {
|
||||
const fileRes = await readFileAsJsonData(file)
|
||||
const jsonData = JSON.parse(fileRes)
|
||||
fileData.value = { data: jsonData, fileName: file.name, type }
|
||||
originFileName.value = file.name
|
||||
emits('uploadFile', fileData.value)
|
||||
return
|
||||
}
|
||||
const { data: blobData, fileName } = await readFileDataAsBlob(file)
|
||||
fileData.value = { data: blobData, fileName, type }
|
||||
originFileName.value = fileName
|
||||
emits('uploadFile', fileData.value)
|
||||
return
|
||||
}
|
||||
const { data: blobData, fileName } = await readFileDataAsBlob(file)
|
||||
fileData.value = { data: blobData, fileName, type }
|
||||
originFileName.value = fileName
|
||||
emits('uploadFile', fileData.value)
|
||||
}
|
||||
function removeFile() {
|
||||
fileData.value = null
|
||||
emits('uploadFile', null)
|
||||
fileData.value = null
|
||||
emits('uploadFile', null)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ defineProps<{ msg: string }>()
|
||||
|
||||
const count = ref(0)
|
||||
function addCount() {
|
||||
count.value++
|
||||
count.value++
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,31 +5,31 @@ import localforage from 'localforage'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
interface IProps {
|
||||
imgItem: IImage
|
||||
imgItem: IImage
|
||||
}
|
||||
const props = defineProps<IProps>()
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
name: 'imgStore',
|
||||
})
|
||||
|
||||
const imgUrl = ref('')
|
||||
|
||||
async function getImageStoreItem(item: IImage): Promise<string> {
|
||||
let image = ''
|
||||
if (item.url === 'Storage') {
|
||||
const key = item.id
|
||||
const imageData = await imageDbStore.getItem<IFileData>(key)
|
||||
image = URL.createObjectURL(imageData?.data as Blob)
|
||||
}
|
||||
else {
|
||||
image = item.url as string
|
||||
}
|
||||
let image = ''
|
||||
if (item.url === 'Storage') {
|
||||
const key = item.id
|
||||
const imageData = await imageDbStore.getItem<IFileData>(key)
|
||||
image = URL.createObjectURL(imageData?.data as Blob)
|
||||
}
|
||||
else {
|
||||
image = item.url as string
|
||||
}
|
||||
|
||||
return image
|
||||
return image
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
imgUrl.value = await getImageStoreItem(props.imgItem)
|
||||
imgUrl.value = await getImageStoreItem(props.imgItem)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import { onMounted, ref, toRefs, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({
|
||||
totalNumber: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
separatedNumber: {
|
||||
type: Array<Separate>,
|
||||
default: [],
|
||||
},
|
||||
totalNumber: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
separatedNumber: {
|
||||
type: Array<Separate>,
|
||||
default: [],
|
||||
},
|
||||
})
|
||||
const emits = defineEmits(['submitData'])
|
||||
const { t } = useI18n()
|
||||
@@ -19,55 +19,55 @@ const separatedNumberRef = ref()
|
||||
const { separatedNumber, totalNumber } = toRefs(props)
|
||||
const scaleList = ref<number[]>([])
|
||||
function editScale(item: number) {
|
||||
if (item === totalNumber.value) {
|
||||
return
|
||||
}
|
||||
if (scaleList.value.includes(item)) {
|
||||
const index = scaleList.value.indexOf(item)
|
||||
scaleList.value.splice(index, 1)
|
||||
separatedNumber.value.splice(index, 1)
|
||||
}
|
||||
else {
|
||||
scaleList.value.push(item)
|
||||
scaleList.value.sort((a, b) => a - b)
|
||||
}
|
||||
if (item === totalNumber.value) {
|
||||
return
|
||||
}
|
||||
if (scaleList.value.includes(item)) {
|
||||
const index = scaleList.value.indexOf(item)
|
||||
scaleList.value.splice(index, 1)
|
||||
separatedNumber.value.splice(index, 1)
|
||||
}
|
||||
else {
|
||||
scaleList.value.push(item)
|
||||
scaleList.value.sort((a, b) => a - b)
|
||||
}
|
||||
}
|
||||
function clearData() {
|
||||
emits('submitData', separatedNumber.value)
|
||||
separatedNumberRef.value.close()
|
||||
emits('submitData', separatedNumber.value)
|
||||
separatedNumberRef.value.close()
|
||||
}
|
||||
watch(scaleList, (val: number[]) => {
|
||||
separatedNumber.value.length = 0
|
||||
for (let i = 1; i < scaleList.value.length; i++) {
|
||||
separatedNumber.value[i - 1] = {
|
||||
id: i.toString(),
|
||||
count: val[i] - val[i - 1],
|
||||
isUsedCount: 0,
|
||||
separatedNumber.value.length = 0
|
||||
for (let i = 1; i < scaleList.value.length; i++) {
|
||||
separatedNumber.value[i - 1] = {
|
||||
id: i.toString(),
|
||||
count: val[i] - val[i - 1],
|
||||
isUsedCount: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
watch(totalNumber, (val) => {
|
||||
if (val <= 0) {
|
||||
return
|
||||
}
|
||||
separatedNumberRef.value.showModal()
|
||||
// scaleList.value = [0, val]
|
||||
scaleList.value = Array.from({ length: separatedNumber.value.length + 1 }).fill(totalNumber.value) as number[]
|
||||
for (let i = separatedNumber.value.length - 1; i >= 0; i--) {
|
||||
scaleList.value[i] = scaleList.value[i + 1] - separatedNumber.value[i].count
|
||||
}
|
||||
if (scaleList.value[0] !== 0) {
|
||||
scaleList.value.unshift(0)
|
||||
}
|
||||
if (val <= 0) {
|
||||
return
|
||||
}
|
||||
separatedNumberRef.value.showModal()
|
||||
// scaleList.value = [0, val]
|
||||
scaleList.value = Array.from({ length: separatedNumber.value.length + 1 }).fill(totalNumber.value) as number[]
|
||||
for (let i = separatedNumber.value.length - 1; i >= 0; i--) {
|
||||
scaleList.value[i] = scaleList.value[i + 1] - separatedNumber.value[i].count
|
||||
}
|
||||
if (scaleList.value[0] !== 0) {
|
||||
scaleList.value.unshift(0)
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
// 阻止esc事件
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
// 阻止esc事件
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang='ts'>
|
||||
const props = defineProps<{
|
||||
title: string
|
||||
title: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,22 +2,22 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
prefix: {
|
||||
type: String,
|
||||
default: 'icon',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#242424',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '24px',
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: 'icon',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#242424',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: '24px',
|
||||
},
|
||||
})
|
||||
|
||||
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
|
||||
|
||||
@@ -6,16 +6,16 @@ import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
// 布局参数 Props
|
||||
interface MasonryWaterfallProps {
|
||||
columnWidth?: number | string // 列宽(px/选择器)
|
||||
gutter?: number // 列/行间距
|
||||
fitWidth?: boolean // 容器宽度自适应居中
|
||||
columnWidth?: number | string // 列宽(px/选择器)
|
||||
gutter?: number // 列/行间距
|
||||
fitWidth?: boolean // 容器宽度自适应居中
|
||||
}
|
||||
|
||||
// 默认参数
|
||||
const props = withDefaults(defineProps<MasonryWaterfallProps>(), {
|
||||
columnWidth: 120,
|
||||
gutter: 16,
|
||||
fitWidth: true,
|
||||
columnWidth: 120,
|
||||
gutter: 16,
|
||||
fitWidth: true,
|
||||
})
|
||||
|
||||
// Vue Ref 管理 DOM 容器和 masonry 实例
|
||||
@@ -24,52 +24,52 @@ const masonryInstance: Ref<Masonry | null> = ref(null)
|
||||
|
||||
// 初始化 masonry(仅执行一次,因卡片固定)
|
||||
async function initMasonry() {
|
||||
if (!masonryContainer.value)
|
||||
return
|
||||
if (!masonryContainer.value)
|
||||
return
|
||||
|
||||
// 等待插槽内容(固定卡片)完全渲染
|
||||
await nextTick()
|
||||
// 等待插槽内容(固定卡片)完全渲染
|
||||
await nextTick()
|
||||
|
||||
// 初始化 masonry 实例(固定卡片无需销毁旧实例)
|
||||
masonryInstance.value = new Masonry(masonryContainer.value, {
|
||||
itemSelector: '.masonry-container > *', // 匹配所有固定子项
|
||||
columnWidth: props.columnWidth,
|
||||
gutter: props.gutter,
|
||||
fitWidth: props.fitWidth,
|
||||
initLayout: true, // 固定卡片直接初始化布局
|
||||
})
|
||||
// 初始化 masonry 实例(固定卡片无需销毁旧实例)
|
||||
masonryInstance.value = new Masonry(masonryContainer.value, {
|
||||
itemSelector: '.masonry-container > *', // 匹配所有固定子项
|
||||
columnWidth: props.columnWidth,
|
||||
gutter: props.gutter,
|
||||
fitWidth: props.fitWidth,
|
||||
initLayout: true, // 固定卡片直接初始化布局
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新布局(仅用于卡片内部内容高度变化)
|
||||
async function refreshLayout() {
|
||||
await nextTick()
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.layout?.()
|
||||
}
|
||||
await nextTick()
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.layout?.()
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口缩放节流重排(优化性能)
|
||||
const handleResize = throttle(() => {
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.layout?.()
|
||||
}
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.layout?.()
|
||||
}
|
||||
}, 300)
|
||||
|
||||
// 生命周期:挂载时初始化,卸载时清理
|
||||
onMounted(async () => {
|
||||
await initMasonry()
|
||||
window.addEventListener('resize', handleResize)
|
||||
await initMasonry()
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 销毁实例 + 释放内存
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.destroy?.()
|
||||
masonryInstance.value = null
|
||||
}
|
||||
// 移除监听 + 取消节流任务
|
||||
window.removeEventListener('resize', handleResize)
|
||||
handleResize.cancel()
|
||||
// 销毁实例 + 释放内存
|
||||
if (masonryInstance.value) {
|
||||
masonryInstance.value.destroy?.()
|
||||
masonryInstance.value = null
|
||||
}
|
||||
// 移除监听 + 取消节流任务
|
||||
window.removeEventListener('resize', handleResize)
|
||||
handleResize.cancel()
|
||||
})
|
||||
|
||||
// 仅暴露刷新方法(适配卡片内部内容变化)
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { PrimitiveProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import type { ButtonVariants } from "."
|
||||
import { Primitive } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "."
|
||||
import type { PrimitiveProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '.'
|
||||
import { Primitive } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '.'
|
||||
|
||||
interface Props extends PrimitiveProps {
|
||||
variant?: ButtonVariants["variant"]
|
||||
size?: ButtonVariants["size"]
|
||||
class?: HTMLAttributes["class"]
|
||||
variant?: ButtonVariants['variant']
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
as: "button",
|
||||
as: 'button',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
import type { VariantProps } from "class-variance-authority"
|
||||
import { cva } from "class-variance-authority"
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
import { cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Button } from "./Button.vue"
|
||||
export { default as Button } from './Button.vue'
|
||||
|
||||
export const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||
outline:
|
||||
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost:
|
||||
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
"default": "h-9 px-4 py-2 has-[>svg]:px-3",
|
||||
"sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
||||
"lg": "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||
"icon": "size-9",
|
||||
"icon-sm": "size-8",
|
||||
"icon-lg": "size-10",
|
||||
},
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
||||
outline:
|
||||
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost:
|
||||
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
'default': 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||
'sm': 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
|
||||
'lg': 'h-10 rounded-md px-6 has-[>svg]:px-4',
|
||||
'icon': 'size-9',
|
||||
'icon-sm': 'size-8',
|
||||
'icon-lg': 'size-10',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
)
|
||||
export type ButtonVariants = VariantProps<typeof buttonVariants>
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListboxRootEmits, ListboxRootProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ListboxRoot, useFilter, useForwardPropsEmits } from "reka-ui"
|
||||
import { reactive, ref, watch } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { provideCommandContext } from "."
|
||||
import type { ListboxRootEmits, ListboxRootProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ListboxRoot, useFilter, useForwardPropsEmits } from 'reka-ui'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { provideCommandContext } from '.'
|
||||
|
||||
const props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes["class"] }>(), {
|
||||
modelValue: "",
|
||||
const props = withDefaults(defineProps<ListboxRootProps & { class?: HTMLAttributes['class'] }>(), {
|
||||
modelValue: '',
|
||||
})
|
||||
|
||||
const emits = defineEmits<ListboxRootEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
const allItems = ref<Map<string, string>>(new Map())
|
||||
const allGroups = ref<Map<string, Set<string>>>(new Map())
|
||||
|
||||
const { contains } = useFilter({ sensitivity: "base" })
|
||||
const { contains } = useFilter({ sensitivity: 'base' })
|
||||
const filterState = reactive({
|
||||
search: "",
|
||||
filtered: {
|
||||
search: '',
|
||||
filtered: {
|
||||
/** The count of all visible items. */
|
||||
count: 0,
|
||||
/** Map from visible item id to its search score. */
|
||||
items: new Map() as Map<string, number>,
|
||||
/** Set of groups with at least one visible item. */
|
||||
groups: new Set() as Set<string>,
|
||||
},
|
||||
count: 0,
|
||||
/** Map from visible item id to its search score. */
|
||||
items: new Map() as Map<string, number>,
|
||||
/** Set of groups with at least one visible item. */
|
||||
groups: new Set() as Set<string>,
|
||||
},
|
||||
})
|
||||
|
||||
function filterItems() {
|
||||
if (!filterState.search) {
|
||||
filterState.filtered.count = allItems.value.size
|
||||
// Do nothing, each item will know to show itself because search is empty
|
||||
return
|
||||
}
|
||||
|
||||
// Reset the groups
|
||||
filterState.filtered.groups = new Set()
|
||||
let itemCount = 0
|
||||
|
||||
// Check which items should be included
|
||||
for (const [id, value] of allItems.value) {
|
||||
const score = contains(value, filterState.search)
|
||||
filterState.filtered.items.set(id, score ? 1 : 0)
|
||||
if (score)
|
||||
itemCount++
|
||||
}
|
||||
|
||||
// Check which groups have at least 1 item shown
|
||||
for (const [groupId, group] of allGroups.value) {
|
||||
for (const itemId of group) {
|
||||
if (filterState.filtered.items.get(itemId)! > 0) {
|
||||
filterState.filtered.groups.add(groupId)
|
||||
break
|
||||
}
|
||||
if (!filterState.search) {
|
||||
filterState.filtered.count = allItems.value.size
|
||||
// Do nothing, each item will know to show itself because search is empty
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
filterState.filtered.count = itemCount
|
||||
// Reset the groups
|
||||
filterState.filtered.groups = new Set()
|
||||
let itemCount = 0
|
||||
|
||||
// Check which items should be included
|
||||
for (const [id, value] of allItems.value) {
|
||||
const score = contains(value, filterState.search)
|
||||
filterState.filtered.items.set(id, score ? 1 : 0)
|
||||
if (score)
|
||||
itemCount++
|
||||
}
|
||||
|
||||
// Check which groups have at least 1 item shown
|
||||
for (const [groupId, group] of allGroups.value) {
|
||||
for (const itemId of group) {
|
||||
if (filterState.filtered.items.get(itemId)! > 0) {
|
||||
filterState.filtered.groups.add(groupId)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterState.filtered.count = itemCount
|
||||
}
|
||||
|
||||
watch(() => filterState.search, () => {
|
||||
filterItems()
|
||||
filterItems()
|
||||
})
|
||||
|
||||
provideCommandContext({
|
||||
allItems,
|
||||
allGroups,
|
||||
filterState,
|
||||
allItems,
|
||||
allGroups,
|
||||
filterState,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogRootEmits, DialogRootProps } from "reka-ui"
|
||||
import { useForwardPropsEmits } from "reka-ui"
|
||||
import type { DialogRootEmits, DialogRootProps } from 'reka-ui'
|
||||
import { useForwardPropsEmits } from 'reka-ui'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import Command from "./Command.vue"
|
||||
import Command from './Command.vue'
|
||||
|
||||
const props = withDefaults(defineProps<DialogRootProps & {
|
||||
title?: string
|
||||
description?: string
|
||||
title?: string
|
||||
description?: string
|
||||
}>(), {
|
||||
title: "Command Palette",
|
||||
description: "Search for a command to run...",
|
||||
title: 'Command Palette',
|
||||
description: 'Search for a command to run...',
|
||||
})
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { PrimitiveProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Primitive } from "reka-ui"
|
||||
import { computed } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useCommand } from "."
|
||||
import type { PrimitiveProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Primitive } from 'reka-ui'
|
||||
import { computed } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useCommand } from '.'
|
||||
|
||||
const props = defineProps<PrimitiveProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const { filterState } = useCommand()
|
||||
const isRender = computed(() => !!filterState.search && filterState.filtered.count === 0,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListboxGroupProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ListboxGroup, ListboxGroupLabel, useId } from "reka-ui"
|
||||
import { computed, onMounted, onUnmounted } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { provideCommandGroupContext, useCommand } from "."
|
||||
import type { ListboxGroupProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ListboxGroup, ListboxGroupLabel, useId } from 'reka-ui'
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { provideCommandGroupContext, useCommand } from '.'
|
||||
|
||||
const props = defineProps<ListboxGroupProps & {
|
||||
class?: HTMLAttributes["class"]
|
||||
heading?: string
|
||||
class?: HTMLAttributes['class']
|
||||
heading?: string
|
||||
}>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const { allGroups, filterState } = useCommand()
|
||||
const id = useId()
|
||||
@@ -21,11 +21,11 @@ const isRender = computed(() => !filterState.search ? true : filterState.filtere
|
||||
|
||||
provideCommandGroupContext({ id })
|
||||
onMounted(() => {
|
||||
if (!allGroups.value.has(id))
|
||||
allGroups.value.set(id, new Set())
|
||||
if (!allGroups.value.has(id))
|
||||
allGroups.value.set(id, new Set())
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allGroups.value.delete(id)
|
||||
allGroups.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListboxFilterProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Search } from "lucide-vue-next"
|
||||
import { ListboxFilter, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useCommand } from "."
|
||||
import type { ListboxFilterProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Search } from 'lucide-vue-next'
|
||||
import { ListboxFilter, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useCommand } from '.'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<ListboxFilterProps & {
|
||||
class?: HTMLAttributes["class"]
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListboxItemEmits, ListboxItemProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit, useCurrentElement } from "@vueuse/core"
|
||||
import { ListboxItem, useForwardPropsEmits, useId } from "reka-ui"
|
||||
import { computed, onMounted, onUnmounted, ref } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useCommand, useCommandGroup } from "."
|
||||
import type { ListboxItemEmits, ListboxItemProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit, useCurrentElement } from '@vueuse/core'
|
||||
import { ListboxItem, useForwardPropsEmits, useId } from 'reka-ui'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useCommand, useCommandGroup } from '.'
|
||||
|
||||
const props = defineProps<ListboxItemProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<ListboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<ListboxItemEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
|
||||
@@ -19,43 +19,43 @@ const { filterState, allItems, allGroups } = useCommand()
|
||||
const groupContext = useCommandGroup()
|
||||
|
||||
const isRender = computed(() => {
|
||||
if (!filterState.search) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
const filteredCurrentItem = filterState.filtered.items.get(id)
|
||||
// If the filtered items is undefined means not in the all times map yet
|
||||
// Do the first render to add into the map
|
||||
if (filteredCurrentItem === undefined) {
|
||||
return true
|
||||
if (!filterState.search) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
const filteredCurrentItem = filterState.filtered.items.get(id)
|
||||
// If the filtered items is undefined means not in the all times map yet
|
||||
// Do the first render to add into the map
|
||||
if (filteredCurrentItem === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check with filter
|
||||
return filteredCurrentItem > 0
|
||||
}
|
||||
// Check with filter
|
||||
return filteredCurrentItem > 0
|
||||
}
|
||||
})
|
||||
|
||||
const itemRef = ref()
|
||||
const currentElement = useCurrentElement(itemRef)
|
||||
onMounted(() => {
|
||||
if (!(currentElement.value instanceof HTMLElement))
|
||||
return
|
||||
if (!(currentElement.value instanceof HTMLElement))
|
||||
return
|
||||
|
||||
// textValue to perform filter
|
||||
allItems.value.set(id, currentElement.value.textContent ?? (props.value?.toString() ?? ""))
|
||||
// textValue to perform filter
|
||||
allItems.value.set(id, currentElement.value.textContent ?? (props.value?.toString() ?? ''))
|
||||
|
||||
const groupId = groupContext?.id
|
||||
if (groupId) {
|
||||
if (!allGroups.value.has(groupId)) {
|
||||
allGroups.value.set(groupId, new Set([id]))
|
||||
const groupId = groupContext?.id
|
||||
if (groupId) {
|
||||
if (!allGroups.value.has(groupId)) {
|
||||
allGroups.value.set(groupId, new Set([id]))
|
||||
}
|
||||
else {
|
||||
allGroups.value.get(groupId)?.add(id)
|
||||
}
|
||||
}
|
||||
else {
|
||||
allGroups.value.get(groupId)?.add(id)
|
||||
}
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
allItems.value.delete(id)
|
||||
allItems.value.delete(id)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { ListboxContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ListboxContent, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { ListboxContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ListboxContent, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<ListboxContentProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<ListboxContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { SeparatorProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Separator } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { SeparatorProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Separator } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<SeparatorProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import type { Ref } from "vue"
|
||||
import { createContext } from "reka-ui"
|
||||
import type { Ref } from 'vue'
|
||||
import { createContext } from 'reka-ui'
|
||||
|
||||
export { default as Command } from "./Command.vue"
|
||||
export { default as CommandDialog } from "./CommandDialog.vue"
|
||||
export { default as CommandEmpty } from "./CommandEmpty.vue"
|
||||
export { default as CommandGroup } from "./CommandGroup.vue"
|
||||
export { default as CommandInput } from "./CommandInput.vue"
|
||||
export { default as CommandItem } from "./CommandItem.vue"
|
||||
export { default as CommandList } from "./CommandList.vue"
|
||||
export { default as CommandSeparator } from "./CommandSeparator.vue"
|
||||
export { default as CommandShortcut } from "./CommandShortcut.vue"
|
||||
export { default as Command } from './Command.vue'
|
||||
export { default as CommandDialog } from './CommandDialog.vue'
|
||||
export { default as CommandEmpty } from './CommandEmpty.vue'
|
||||
export { default as CommandGroup } from './CommandGroup.vue'
|
||||
export { default as CommandInput } from './CommandInput.vue'
|
||||
export { default as CommandItem } from './CommandItem.vue'
|
||||
export { default as CommandList } from './CommandList.vue'
|
||||
export { default as CommandSeparator } from './CommandSeparator.vue'
|
||||
export { default as CommandShortcut } from './CommandShortcut.vue'
|
||||
|
||||
export const [useCommand, provideCommandContext] = createContext<{
|
||||
allItems: Ref<Map<string, string>>
|
||||
allGroups: Ref<Map<string, Set<string>>>
|
||||
filterState: {
|
||||
search: string
|
||||
filtered: { count: number, items: Map<string, number>, groups: Set<string> }
|
||||
}
|
||||
}>("Command")
|
||||
allItems: Ref<Map<string, string>>
|
||||
allGroups: Ref<Map<string, Set<string>>>
|
||||
filterState: {
|
||||
search: string
|
||||
filtered: { count: number, items: Map<string, number>, groups: Set<string> }
|
||||
}
|
||||
}>('Command')
|
||||
|
||||
export const [useCommandGroup, provideCommandGroupContext] = createContext<{
|
||||
id?: string
|
||||
}>("CommandGroup")
|
||||
id?: string
|
||||
}>('CommandGroup')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogRootEmits, DialogRootProps } from "reka-ui"
|
||||
import { DialogRoot, useForwardPropsEmits } from "reka-ui"
|
||||
import type { DialogRootEmits, DialogRootProps } from 'reka-ui'
|
||||
import { DialogRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DialogRootProps>()
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogCloseProps } from "reka-ui"
|
||||
import { DialogClose } from "reka-ui"
|
||||
import type { DialogCloseProps } from 'reka-ui'
|
||||
import { DialogClose } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DialogCloseProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { X } from "lucide-vue-next"
|
||||
import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import {
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import DialogOverlay from "./DialogOverlay.vue"
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
import DialogOverlay from './DialogOverlay.vue'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<DialogContentProps & { class?: HTMLAttributes["class"], showCloseButton?: boolean }>(), {
|
||||
showCloseButton: true,
|
||||
const props = withDefaults(defineProps<DialogContentProps & { class?: HTMLAttributes['class'], showCloseButton?: boolean }>(), {
|
||||
showCloseButton: true,
|
||||
})
|
||||
const emits = defineEmits<DialogContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogDescriptionProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogDescription, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { DialogDescriptionProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogDescription, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogOverlayProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogOverlay } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { DialogOverlayProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogOverlay } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogContentEmits, DialogContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { X } from "lucide-vue-next"
|
||||
import type { DialogContentEmits, DialogContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { X } from 'lucide-vue-next'
|
||||
import {
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = defineProps<DialogContentProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<DialogContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogTitleProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DialogTitle, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { DialogTitleProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DialogTitle, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DialogTriggerProps } from "reka-ui"
|
||||
import { DialogTrigger } from "reka-ui"
|
||||
import type { DialogTriggerProps } from 'reka-ui'
|
||||
import { DialogTrigger } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DialogTriggerProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export { default as Dialog } from "./Dialog.vue"
|
||||
export { default as DialogClose } from "./DialogClose.vue"
|
||||
export { default as DialogContent } from "./DialogContent.vue"
|
||||
export { default as DialogDescription } from "./DialogDescription.vue"
|
||||
export { default as DialogFooter } from "./DialogFooter.vue"
|
||||
export { default as DialogHeader } from "./DialogHeader.vue"
|
||||
export { default as DialogOverlay } from "./DialogOverlay.vue"
|
||||
export { default as DialogScrollContent } from "./DialogScrollContent.vue"
|
||||
export { default as DialogTitle } from "./DialogTitle.vue"
|
||||
export { default as DialogTrigger } from "./DialogTrigger.vue"
|
||||
export { default as Dialog } from './Dialog.vue'
|
||||
export { default as DialogClose } from './DialogClose.vue'
|
||||
export { default as DialogContent } from './DialogContent.vue'
|
||||
export { default as DialogDescription } from './DialogDescription.vue'
|
||||
export { default as DialogFooter } from './DialogFooter.vue'
|
||||
export { default as DialogHeader } from './DialogHeader.vue'
|
||||
export { default as DialogOverlay } from './DialogOverlay.vue'
|
||||
export { default as DialogScrollContent } from './DialogScrollContent.vue'
|
||||
export { default as DialogTitle } from './DialogTitle.vue'
|
||||
export { default as DialogTrigger } from './DialogTrigger.vue'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuRootEmits, DropdownMenuRootProps } from "reka-ui"
|
||||
import { DropdownMenuRoot, useForwardPropsEmits } from "reka-ui"
|
||||
import type { DropdownMenuRootEmits, DropdownMenuRootProps } from 'reka-ui'
|
||||
import { DropdownMenuRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DropdownMenuRootProps>()
|
||||
const emits = defineEmits<DropdownMenuRootEmits>()
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuCheckboxItemEmits, DropdownMenuCheckboxItemProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Check } from "lucide-vue-next"
|
||||
import type { DropdownMenuCheckboxItemEmits, DropdownMenuCheckboxItemProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Check } from 'lucide-vue-next'
|
||||
import {
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuItemIndicator,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuItemIndicator,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuContentEmits, DropdownMenuContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import type { DropdownMenuContentEmits, DropdownMenuContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import {
|
||||
DropdownMenuContent,
|
||||
DropdownMenuPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuContent,
|
||||
DropdownMenuPortal,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes["class"] }>(),
|
||||
{
|
||||
sideOffset: 4,
|
||||
},
|
||||
defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(),
|
||||
{
|
||||
sideOffset: 4,
|
||||
},
|
||||
)
|
||||
const emits = defineEmits<DropdownMenuContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuGroupProps } from "reka-ui"
|
||||
import { DropdownMenuGroup } from "reka-ui"
|
||||
import type { DropdownMenuGroupProps } from 'reka-ui'
|
||||
import { DropdownMenuGroup } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DropdownMenuGroupProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItemProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DropdownMenuItem, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { DropdownMenuItemProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DropdownMenuItem, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<DropdownMenuItemProps & {
|
||||
class?: HTMLAttributes["class"]
|
||||
inset?: boolean
|
||||
variant?: "default" | "destructive"
|
||||
class?: HTMLAttributes['class']
|
||||
inset?: boolean
|
||||
variant?: 'default' | 'destructive'
|
||||
}>(), {
|
||||
variant: "default",
|
||||
variant: 'default',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "inset", "variant", "class")
|
||||
const delegatedProps = reactiveOmit(props, 'inset', 'variant', 'class')
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuLabelProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { DropdownMenuLabel, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { DropdownMenuLabelProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { DropdownMenuLabel, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes["class"], inset?: boolean }>()
|
||||
const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class", "inset")
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'inset')
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuRadioGroupEmits, DropdownMenuRadioGroupProps } from "reka-ui"
|
||||
import type { DropdownMenuRadioGroupEmits, DropdownMenuRadioGroupProps } from 'reka-ui'
|
||||
import {
|
||||
DropdownMenuRadioGroup,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
DropdownMenuRadioGroup,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
|
||||
const props = defineProps<DropdownMenuRadioGroupProps>()
|
||||
const emits = defineEmits<DropdownMenuRadioGroupEmits>()
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Circle } from "lucide-vue-next"
|
||||
import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { Circle } from 'lucide-vue-next'
|
||||
import {
|
||||
DropdownMenuItemIndicator,
|
||||
DropdownMenuRadioItem,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuItemIndicator,
|
||||
DropdownMenuRadioItem,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const emits = defineEmits<DropdownMenuRadioItemEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuSeparatorProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import type { DropdownMenuSeparatorProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import {
|
||||
DropdownMenuSeparator,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuSeparator,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuSeparatorProps & {
|
||||
class?: HTMLAttributes["class"]
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuSubEmits, DropdownMenuSubProps } from "reka-ui"
|
||||
import type { DropdownMenuSubEmits, DropdownMenuSubProps } from 'reka-ui'
|
||||
import {
|
||||
DropdownMenuSub,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
DropdownMenuSub,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
|
||||
const props = defineProps<DropdownMenuSubProps>()
|
||||
const emits = defineEmits<DropdownMenuSubEmits>()
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuSubContentEmits, DropdownMenuSubContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import type { DropdownMenuSubContentEmits, DropdownMenuSubContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import {
|
||||
DropdownMenuSubContent,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuSubContent,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<DropdownMenuSubContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuSubTriggerProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ChevronRight } from "lucide-vue-next"
|
||||
import type { DropdownMenuSubTriggerProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronRight } from 'lucide-vue-next'
|
||||
import {
|
||||
DropdownMenuSubTrigger,
|
||||
useForwardProps,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
DropdownMenuSubTrigger,
|
||||
useForwardProps,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes["class"], inset?: boolean }>()
|
||||
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class", "inset")
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'inset')
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuTriggerProps } from "reka-ui"
|
||||
import { DropdownMenuTrigger, useForwardProps } from "reka-ui"
|
||||
import type { DropdownMenuTriggerProps } from 'reka-ui'
|
||||
import { DropdownMenuTrigger, useForwardProps } from 'reka-ui'
|
||||
|
||||
const props = defineProps<DropdownMenuTriggerProps>()
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
export { default as DropdownMenu } from "./DropdownMenu.vue"
|
||||
export { default as DropdownMenu } from './DropdownMenu.vue'
|
||||
|
||||
export { default as DropdownMenuCheckboxItem } from "./DropdownMenuCheckboxItem.vue"
|
||||
export { default as DropdownMenuContent } from "./DropdownMenuContent.vue"
|
||||
export { default as DropdownMenuGroup } from "./DropdownMenuGroup.vue"
|
||||
export { default as DropdownMenuItem } from "./DropdownMenuItem.vue"
|
||||
export { default as DropdownMenuLabel } from "./DropdownMenuLabel.vue"
|
||||
export { default as DropdownMenuRadioGroup } from "./DropdownMenuRadioGroup.vue"
|
||||
export { default as DropdownMenuRadioItem } from "./DropdownMenuRadioItem.vue"
|
||||
export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.vue"
|
||||
export { default as DropdownMenuShortcut } from "./DropdownMenuShortcut.vue"
|
||||
export { default as DropdownMenuSub } from "./DropdownMenuSub.vue"
|
||||
export { default as DropdownMenuSubContent } from "./DropdownMenuSubContent.vue"
|
||||
export { default as DropdownMenuSubTrigger } from "./DropdownMenuSubTrigger.vue"
|
||||
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue"
|
||||
export { DropdownMenuPortal } from "reka-ui"
|
||||
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
|
||||
export { default as DropdownMenuContent } from './DropdownMenuContent.vue'
|
||||
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue'
|
||||
export { default as DropdownMenuItem } from './DropdownMenuItem.vue'
|
||||
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue'
|
||||
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
|
||||
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
|
||||
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
|
||||
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
|
||||
export { default as DropdownMenuSub } from './DropdownMenuSub.vue'
|
||||
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue'
|
||||
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
|
||||
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
|
||||
export { DropdownMenuPortal } from 'reka-ui'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { PopoverRootEmits, PopoverRootProps } from "reka-ui"
|
||||
import { PopoverRoot, useForwardPropsEmits } from "reka-ui"
|
||||
import type { PopoverRootEmits, PopoverRootProps } from 'reka-ui'
|
||||
import { PopoverRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
|
||||
const props = defineProps<PopoverRootProps>()
|
||||
const emits = defineEmits<PopoverRootEmits>()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { PopoverAnchorProps } from "reka-ui"
|
||||
import { PopoverAnchor } from "reka-ui"
|
||||
import type { PopoverAnchorProps } from 'reka-ui'
|
||||
import { PopoverAnchor } from 'reka-ui'
|
||||
|
||||
const props = defineProps<PopoverAnchorProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import type { PopoverContentEmits, PopoverContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import type { PopoverContentEmits, PopoverContentProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import {
|
||||
PopoverContent,
|
||||
PopoverPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
PopoverContent,
|
||||
PopoverPortal,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<PopoverContentProps & { class?: HTMLAttributes["class"] }>(),
|
||||
{
|
||||
align: "center",
|
||||
sideOffset: 4,
|
||||
},
|
||||
defineProps<PopoverContentProps & { class?: HTMLAttributes['class'] }>(),
|
||||
{
|
||||
align: 'center',
|
||||
sideOffset: 4,
|
||||
},
|
||||
)
|
||||
const emits = defineEmits<PopoverContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { PopoverTriggerProps } from "reka-ui"
|
||||
import { PopoverTrigger } from "reka-ui"
|
||||
import type { PopoverTriggerProps } from 'reka-ui'
|
||||
import { PopoverTrigger } from 'reka-ui'
|
||||
|
||||
const props = defineProps<PopoverTriggerProps>()
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { default as Popover } from "./Popover.vue"
|
||||
export { default as PopoverAnchor } from "./PopoverAnchor.vue"
|
||||
export { default as PopoverContent } from "./PopoverContent.vue"
|
||||
export { default as PopoverTrigger } from "./PopoverTrigger.vue"
|
||||
export { default as Popover } from './Popover.vue'
|
||||
export { default as PopoverAnchor } from './PopoverAnchor.vue'
|
||||
export { default as PopoverContent } from './PopoverContent.vue'
|
||||
export { default as PopoverTrigger } from './PopoverTrigger.vue'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ToasterProps } from "vue-sonner"
|
||||
import { CircleCheckIcon, InfoIcon, Loader2Icon, OctagonXIcon, TriangleAlertIcon, XIcon } from "lucide-vue-next"
|
||||
import { Toaster as Sonner } from "vue-sonner"
|
||||
import { cn } from "@/lib/utils"
|
||||
import type { ToasterProps } from 'vue-sonner'
|
||||
import { CircleCheckIcon, InfoIcon, Loader2Icon, OctagonXIcon, TriangleAlertIcon, XIcon } from 'lucide-vue-next'
|
||||
import { Toaster as Sonner } from 'vue-sonner'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<ToasterProps>()
|
||||
</script>
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as Toaster } from "./Sonner.vue"
|
||||
export { default as Toaster } from './Sonner.vue'
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { SwitchRootEmits, SwitchRootProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
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"
|
||||
SwitchRoot,
|
||||
SwitchThumb,
|
||||
useForwardPropsEmits,
|
||||
} from 'reka-ui'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<SwitchRootProps & { class?: HTMLAttributes["class"] }>()
|
||||
const props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const emits = defineEmits<SwitchRootEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default as Switch } from "./Switch.vue"
|
||||
export { default as Switch } from './Switch.vue'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export const footerList = {
|
||||
data: [
|
||||
{
|
||||
id: 0,
|
||||
name: 'Github',
|
||||
url: 'https://github.com/LOG1997',
|
||||
icon: 'github',
|
||||
},
|
||||
],
|
||||
data: [
|
||||
{
|
||||
id: 0,
|
||||
name: 'Github',
|
||||
url: 'https://github.com/LOG1997',
|
||||
icon: 'github',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { footerList } from './config'
|
||||
|
||||
function skip(url: string) {
|
||||
window.open(url)
|
||||
window.open(url)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
export const navList = [
|
||||
{
|
||||
id: 0,
|
||||
name: '首页',
|
||||
url: 'home',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: '项目',
|
||||
url: 'project',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '关于',
|
||||
url: 'about',
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
name: '首页',
|
||||
url: 'home',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: '项目',
|
||||
url: 'project',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '关于',
|
||||
url: 'about',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { navList } from './config'
|
||||
|
||||
function skip(url: string) {
|
||||
window.open(url, '_self')
|
||||
window.open(url, '_self')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -16,18 +16,18 @@ const settingRef = ref()
|
||||
const fullScreenRef = ref()
|
||||
|
||||
function enterConfig() {
|
||||
router.push('/log-lottery/config')
|
||||
router.push('/log-lottery/config')
|
||||
}
|
||||
function enterHome() {
|
||||
router.push('/log-lottery')
|
||||
router.push('/log-lottery')
|
||||
}
|
||||
onMounted(() => {
|
||||
settingRef.value.addEventListener('mouseenter', () => {
|
||||
fullScreenRef.value.style.display = 'block'
|
||||
})
|
||||
settingRef.value.addEventListener('mouseleave', () => {
|
||||
fullScreenRef.value.style.display = 'none'
|
||||
})
|
||||
settingRef.value.addEventListener('mouseenter', () => {
|
||||
fullScreenRef.value.style.display = 'block'
|
||||
})
|
||||
settingRef.value.addEventListener('mouseleave', () => {
|
||||
fullScreenRef.value.style.display = 'none'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ const mainContainer = ref<HTMLElement | null>(null)
|
||||
const { y } = useScroll(mainContainer)
|
||||
|
||||
function scrollToTop() {
|
||||
mainContainer.value?.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
mainContainer.value?.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ClassValue } from "clsx"
|
||||
import { clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import type { ClassValue } from 'clsx'
|
||||
import { clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
||||
@@ -6,27 +6,27 @@ import zhCn from './zhCn'
|
||||
export type Language = 'en' | 'zhCn'
|
||||
|
||||
export const languageList = [
|
||||
{
|
||||
key: 'zhCn',
|
||||
name: '中文',
|
||||
flag: 'zh-cn',
|
||||
},
|
||||
{
|
||||
key: 'en',
|
||||
name: 'English',
|
||||
flag: 'en-us',
|
||||
},
|
||||
{
|
||||
key: 'zhCn',
|
||||
name: '中文',
|
||||
flag: 'zh-cn',
|
||||
},
|
||||
{
|
||||
key: 'en',
|
||||
name: 'English',
|
||||
flag: 'en-us',
|
||||
},
|
||||
]
|
||||
export const browserLanguage = navigator.language.toLowerCase().includes('zh') ? 'zhCn' : 'en'
|
||||
const globalConfig = JSON.parse(localStorage.getItem('globalConfig') || '{}').globalConfig || {}
|
||||
// 创建i18n
|
||||
const i18n = createI18n({
|
||||
locale: globalConfig.language || browserLanguage,
|
||||
legacy: false,
|
||||
messages: {
|
||||
zhCn,
|
||||
en,
|
||||
},
|
||||
locale: globalConfig.language || browserLanguage,
|
||||
legacy: false,
|
||||
messages: {
|
||||
zhCn,
|
||||
en,
|
||||
},
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
export const buttonEn = {
|
||||
enterLottery: 'Enter Lottery',
|
||||
start: 'Start',
|
||||
selectLucky: 'Draw the Lucky',
|
||||
continue: 'Continue',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel',
|
||||
setting: 'Setting',
|
||||
delete: 'Delete',
|
||||
allDelete: 'Delete All',
|
||||
downloadTemplate: 'Download Template',
|
||||
importData: 'Import Data',
|
||||
resetData: 'Reset Data',
|
||||
exportResult: 'Export Result',
|
||||
add: 'Add',
|
||||
resetDefault: 'Reset Default',
|
||||
resetAllData: 'Reset All Data',
|
||||
clearPattern: 'Clear Pattern',
|
||||
DefaultPattern: 'Default Pattern',
|
||||
upload: 'Upload',
|
||||
reset: 'Reset',
|
||||
play: 'Play',
|
||||
setLayout: 'Set Layout',
|
||||
close: 'Close',
|
||||
noInfoAndImport: 'No Info and import it',
|
||||
useDefault: 'Use Default Data',
|
||||
loading: 'Loading...',
|
||||
enterLottery: 'Enter Lottery',
|
||||
start: 'Start',
|
||||
selectLucky: 'Draw the Lucky',
|
||||
continue: 'Continue',
|
||||
confirm: 'Confirm',
|
||||
cancel: 'Cancel',
|
||||
setting: 'Setting',
|
||||
delete: 'Delete',
|
||||
allDelete: 'Delete All',
|
||||
downloadTemplate: 'Download Template',
|
||||
importData: 'Import Data',
|
||||
resetData: 'Reset Data',
|
||||
exportResult: 'Export Result',
|
||||
add: 'Add',
|
||||
resetDefault: 'Reset Default',
|
||||
resetAllData: 'Reset All Data',
|
||||
clearPattern: 'Clear Pattern',
|
||||
DefaultPattern: 'Default Pattern',
|
||||
upload: 'Upload',
|
||||
reset: 'Reset',
|
||||
play: 'Play',
|
||||
setLayout: 'Set Layout',
|
||||
close: 'Close',
|
||||
noInfoAndImport: 'No Info and import it',
|
||||
useDefault: 'Use Default Data',
|
||||
loading: 'Loading...',
|
||||
}
|
||||
|
||||
export const buttonZhCn = {
|
||||
enterLottery: '进入抽奖',
|
||||
start: '开始',
|
||||
selectLucky: '抽取幸运儿',
|
||||
continue: '继续',
|
||||
confirm: '确认',
|
||||
cancel: '取消',
|
||||
setting: '设置',
|
||||
delete: '删除',
|
||||
allDelete: '删除全部',
|
||||
downloadTemplate: '下载模板',
|
||||
importData: '导入数据',
|
||||
resetData: '重置数据',
|
||||
exportResult: '导出结果',
|
||||
add: '添加',
|
||||
resetDefault: '重置为默认',
|
||||
resetAllData: '重置所有数据',
|
||||
clearPattern: '清除图案',
|
||||
DefaultPattern: '默认图案',
|
||||
upload: '上传',
|
||||
reset: '重置',
|
||||
play: '播放',
|
||||
setLayout: '重设布局',
|
||||
close: '关闭',
|
||||
noInfoAndImport: '暂无人员信息,前往导入',
|
||||
useDefault: '使用默认数据',
|
||||
loading: '加载中...',
|
||||
enterLottery: '进入抽奖',
|
||||
start: '开始',
|
||||
selectLucky: '抽取幸运儿',
|
||||
continue: '继续',
|
||||
confirm: '确认',
|
||||
cancel: '取消',
|
||||
setting: '设置',
|
||||
delete: '删除',
|
||||
allDelete: '删除全部',
|
||||
downloadTemplate: '下载模板',
|
||||
importData: '导入数据',
|
||||
resetData: '重置数据',
|
||||
exportResult: '导出结果',
|
||||
add: '添加',
|
||||
resetDefault: '重置为默认',
|
||||
resetAllData: '重置所有数据',
|
||||
clearPattern: '清除图案',
|
||||
DefaultPattern: '默认图案',
|
||||
upload: '上传',
|
||||
reset: '重置',
|
||||
play: '播放',
|
||||
setLayout: '重设布局',
|
||||
close: '关闭',
|
||||
noInfoAndImport: '暂无人员信息,前往导入',
|
||||
useDefault: '使用默认数据',
|
||||
loading: '加载中...',
|
||||
}
|
||||
|
||||
// 导出一个值
|
||||
export const button = {
|
||||
en: buttonEn,
|
||||
zhCn: buttonZhCn,
|
||||
en: buttonEn,
|
||||
zhCn: buttonZhCn,
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
export const dialogEn = {
|
||||
titleTip: 'Tip!',
|
||||
titleTemporary: 'Add Temporary Activity',
|
||||
dialogPCWeb: 'Please use a PC browser to access for optimal display performance',
|
||||
dialogDelAllPerson: 'This operation will delete all personnel list data. Do you want to continue?',
|
||||
dialogResetWinner: 'This operation will clear the winning information of personnel. Do you want to continue?',
|
||||
dialogResetAllData: 'This operation will reset all data. Do you want to continue?',
|
||||
dialogSingleDrawLimit: 'Only 10 characters can be extracted in a single draw',
|
||||
dialogLatestBrowser: 'Please use the latest version of Chrome or Edge browser',
|
||||
tipResetPrize: 'Performing operations may reset data and cant recover, please proceed with caution',
|
||||
uploadFileTitle: 'Upload File',
|
||||
uploadImageTitle: 'Upload Image',
|
||||
uploadAudioTitle: 'Upload Audio',
|
||||
titleTip: 'Tip!',
|
||||
titleTemporary: 'Add Temporary Activity',
|
||||
dialogPCWeb: 'Please use a PC browser to access for optimal display performance',
|
||||
dialogDelAllPerson: 'This operation will delete all personnel list data. Do you want to continue?',
|
||||
dialogResetWinner: 'This operation will clear the winning information of personnel. Do you want to continue?',
|
||||
dialogResetAllData: 'This operation will reset all data. Do you want to continue?',
|
||||
dialogSingleDrawLimit: 'Only 10 characters can be extracted in a single draw',
|
||||
dialogLatestBrowser: 'Please use the latest version of Chrome or Edge browser',
|
||||
tipResetPrize: 'Performing operations may reset data and cant recover, please proceed with caution',
|
||||
uploadFileTitle: 'Upload File',
|
||||
uploadImageTitle: 'Upload Image',
|
||||
uploadAudioTitle: 'Upload Audio',
|
||||
}
|
||||
|
||||
export const dialogZhCn = {
|
||||
titleTip: '提示!',
|
||||
titleTemporary: '增加临时抽奖',
|
||||
dialogPCWeb: '请使用PC进行访问以获得最佳显示效果',
|
||||
dialogDelAllPerson: '该操作会删除所有人员数据,是否继续?',
|
||||
dialogResetWinner: '该操作会清空人员中奖信息,是否继续?',
|
||||
dialogResetAllData: '该操作会重置所有数据,是否继续?',
|
||||
dialogSingleDrawLimit: '单次抽取只能抽取10位',
|
||||
dialogLatestBrowser: '请使用最新版Chrome或者Edge浏览器',
|
||||
tipResetPrize: '进行操作可能会重置数据并不可恢复,请谨慎操作',
|
||||
uploadFileTitle: '上传文件',
|
||||
uploadImageTitle: '上传图片',
|
||||
uploadAudioTitle: '上传音频',
|
||||
titleTip: '提示!',
|
||||
titleTemporary: '增加临时抽奖',
|
||||
dialogPCWeb: '请使用PC进行访问以获得最佳显示效果',
|
||||
dialogDelAllPerson: '该操作会删除所有人员数据,是否继续?',
|
||||
dialogResetWinner: '该操作会清空人员中奖信息,是否继续?',
|
||||
dialogResetAllData: '该操作会重置所有数据,是否继续?',
|
||||
dialogSingleDrawLimit: '单次抽取只能抽取10位',
|
||||
dialogLatestBrowser: '请使用最新版Chrome或者Edge浏览器',
|
||||
tipResetPrize: '进行操作可能会重置数据并不可恢复,请谨慎操作',
|
||||
uploadFileTitle: '上传文件',
|
||||
uploadImageTitle: '上传图片',
|
||||
uploadAudioTitle: '上传音频',
|
||||
}
|
||||
|
||||
export const dialog = {
|
||||
en: dialogEn,
|
||||
zhCn: dialogZhCn,
|
||||
en: dialogEn,
|
||||
zhCn: dialogZhCn,
|
||||
}
|
||||
|
||||
@@ -1,60 +1,58 @@
|
||||
import { success } from 'zod'
|
||||
|
||||
export const errorEn = {
|
||||
require: 'required field',
|
||||
requireNumber: 'please enter a number',
|
||||
minNumber1: 'the minimum is 1',
|
||||
maxNumber100: 'the maximum is 100',
|
||||
uploadSuccess: 'Upload Success',
|
||||
uploadFail: 'Upload Failed',
|
||||
notImage: 'Not Image',
|
||||
personIsAllDone: 'All Person Is Done',
|
||||
personNotEnough: 'Person Is Not Enough',
|
||||
startDraw: 'Now Draw {count} {leftover} people',
|
||||
completeInformation: 'Please provide complete information',
|
||||
notJsonFile: 'it isn\'t a JSON file',
|
||||
notAudioFile: 'it isn\'t an audio file',
|
||||
personNameEmpty: 'Please enter name',
|
||||
excelFileError: 'The header is inconsistent, please download the template, modify it, and then upload it',
|
||||
exportSuccess: 'Export Success',
|
||||
exportFail: 'Export Failed',
|
||||
importSuccess: 'Import Success',
|
||||
importFail: 'Import Failed',
|
||||
downloadSuccess: '下载成功',
|
||||
deleteSuccess: '删除成功',
|
||||
deleteFail: '删除失败',
|
||||
success: 'Success',
|
||||
fail: 'Failed',
|
||||
require: 'required field',
|
||||
requireNumber: 'please enter a number',
|
||||
minNumber1: 'the minimum is 1',
|
||||
maxNumber100: 'the maximum is 100',
|
||||
uploadSuccess: 'Upload Success',
|
||||
uploadFail: 'Upload Failed',
|
||||
notImage: 'Not Image',
|
||||
personIsAllDone: 'All Person Is Done',
|
||||
personNotEnough: 'Person Is Not Enough',
|
||||
startDraw: 'Now Draw {count} {leftover} people',
|
||||
completeInformation: 'Please provide complete information',
|
||||
notJsonFile: 'it isn\'t a JSON file',
|
||||
notAudioFile: 'it isn\'t an audio file',
|
||||
personNameEmpty: 'Please enter name',
|
||||
excelFileError: 'The header is inconsistent, please download the template, modify it, and then upload it',
|
||||
exportSuccess: 'Export Success',
|
||||
exportFail: 'Export Failed',
|
||||
importSuccess: 'Import Success',
|
||||
importFail: 'Import Failed',
|
||||
downloadSuccess: '下载成功',
|
||||
deleteSuccess: '删除成功',
|
||||
deleteFail: '删除失败',
|
||||
success: 'Success',
|
||||
fail: 'Failed',
|
||||
}
|
||||
|
||||
export const errorZhCn = {
|
||||
require: '必填项',
|
||||
requireNumber: '请输入数字',
|
||||
minNumber1: '最小为1',
|
||||
maxNumber100: '最大为100',
|
||||
uploadSuccess: '上传成功',
|
||||
uploadFail: '上传失败',
|
||||
notImage: '不是图片',
|
||||
personIsAllDone: '抽奖抽完了',
|
||||
personNotEnough: '抽奖人数不足',
|
||||
startDraw: '现在抽取{count}{leftover}人',
|
||||
completeInformation: '请填写完整信息',
|
||||
notJsonFile: '这不是一个JSON文件',
|
||||
notAudioFile: '这不是一个音频文件',
|
||||
personNameEmpty: '请填写姓名',
|
||||
excelFileError: '表头不一致,请先下载模板然后修改后再上传',
|
||||
exportSuccess: '导出成功',
|
||||
exportFail: '导出失败',
|
||||
importSuccess: '导入成功',
|
||||
importFail: '导入失败',
|
||||
downloadSuccess: '下载成功',
|
||||
deleteSuccess: '删除成功',
|
||||
deleteFail: '删除失败',
|
||||
success: '成功',
|
||||
fail: '失败',
|
||||
require: '必填项',
|
||||
requireNumber: '请输入数字',
|
||||
minNumber1: '最小为1',
|
||||
maxNumber100: '最大为100',
|
||||
uploadSuccess: '上传成功',
|
||||
uploadFail: '上传失败',
|
||||
notImage: '不是图片',
|
||||
personIsAllDone: '抽奖抽完了',
|
||||
personNotEnough: '抽奖人数不足',
|
||||
startDraw: '现在抽取{count}{leftover}人',
|
||||
completeInformation: '请填写完整信息',
|
||||
notJsonFile: '这不是一个JSON文件',
|
||||
notAudioFile: '这不是一个音频文件',
|
||||
personNameEmpty: '请填写姓名',
|
||||
excelFileError: '表头不一致,请先下载模板然后修改后再上传',
|
||||
exportSuccess: '导出成功',
|
||||
exportFail: '导出失败',
|
||||
importSuccess: '导入成功',
|
||||
importFail: '导入失败',
|
||||
downloadSuccess: '下载成功',
|
||||
deleteSuccess: '删除成功',
|
||||
deleteFail: '删除失败',
|
||||
success: '成功',
|
||||
fail: '失败',
|
||||
}
|
||||
|
||||
export const error = {
|
||||
en: errorEn,
|
||||
zhCn: errorZhCn,
|
||||
en: errorEn,
|
||||
zhCn: errorZhCn,
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
export const placeHolderEn = {
|
||||
enterTitle: 'Enter Title',
|
||||
name: 'Name',
|
||||
winnerCount: 'Lucky Person Count',
|
||||
selectFont: 'Select Font',
|
||||
timedStop: 'will stop at a scheduled time after starting',
|
||||
imageName: 'Image Name',
|
||||
personName: 'Please enter name',
|
||||
enterTitle: 'Enter Title',
|
||||
name: 'Name',
|
||||
winnerCount: 'Lucky Person Count',
|
||||
selectFont: 'Select Font',
|
||||
timedStop: 'will stop at a scheduled time after starting',
|
||||
imageName: 'Image Name',
|
||||
personName: 'Please enter name',
|
||||
}
|
||||
|
||||
export const placeHolderZhCn = {
|
||||
enterTitle: '输入标题',
|
||||
name: '名称',
|
||||
winnerCount: '中奖人数',
|
||||
selectFont: '选择字体',
|
||||
timedStop: '开始后定时抽取',
|
||||
imageName: '图片名称',
|
||||
personName: '请填写姓名',
|
||||
enterTitle: '输入标题',
|
||||
name: '名称',
|
||||
winnerCount: '中奖人数',
|
||||
selectFont: '选择字体',
|
||||
timedStop: '开始后定时抽取',
|
||||
imageName: '图片名称',
|
||||
personName: '请填写姓名',
|
||||
}
|
||||
|
||||
export const placeHolder = {
|
||||
en: placeHolderEn,
|
||||
zhCn: placeHolderZhCn,
|
||||
en: placeHolderEn,
|
||||
zhCn: placeHolderZhCn,
|
||||
}
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
export const tooltipEn = {
|
||||
settingConfiguration: 'Setting/Configuration',
|
||||
nextSong: 'Right Click to Next Song',
|
||||
noSongPlay: 'No Song to Play',
|
||||
prizeList: 'Prize List',
|
||||
addActivity: 'Add Activity',
|
||||
downloadTemplateTip: 'After downloading the file, please fill in the data in Excel and save it in xlsx format',
|
||||
uploadExcelTip: 'Upload the modified Excel file',
|
||||
leftClick: 'Left Click to Slice',
|
||||
toHome: 'to Home',
|
||||
resetLayout: 'This item is time-consuming and performance intensive',
|
||||
defaultLayout: 'The default pattern setting is valid for 17 columns, please set the number of other columns yourself',
|
||||
doneCount: 'Number of winners',
|
||||
edit: 'Edit',
|
||||
delete: 'Delete',
|
||||
timedStop: 'After the lottery begins, it will stop at a scheduled time by default, set to 0, with the unit in seconds. A value of 0 disables the scheduled stopping function',
|
||||
uploadImage: 'Upload Image',
|
||||
pleaseGoto: 'Please go to',
|
||||
settingConfiguration: 'Setting/Configuration',
|
||||
nextSong: 'Right Click to Next Song',
|
||||
noSongPlay: 'No Song to Play',
|
||||
prizeList: 'Prize List',
|
||||
addActivity: 'Add Activity',
|
||||
downloadTemplateTip: 'After downloading the file, please fill in the data in Excel and save it in xlsx format',
|
||||
uploadExcelTip: 'Upload the modified Excel file',
|
||||
leftClick: 'Left Click to Slice',
|
||||
toHome: 'to Home',
|
||||
resetLayout: 'This item is time-consuming and performance intensive',
|
||||
defaultLayout: 'The default pattern setting is valid for 17 columns, please set the number of other columns yourself',
|
||||
doneCount: 'Number of winners',
|
||||
edit: 'Edit',
|
||||
delete: 'Delete',
|
||||
timedStop: 'After the lottery begins, it will stop at a scheduled time by default, set to 0, with the unit in seconds. A value of 0 disables the scheduled stopping function',
|
||||
uploadImage: 'Upload Image',
|
||||
pleaseGoto: 'Please go to',
|
||||
}
|
||||
|
||||
export const tooltipZhCn = {
|
||||
settingConfiguration: '设置/配置',
|
||||
nextSong: '右键点击下一首',
|
||||
noSongPlay: '没有音乐可以播放',
|
||||
prizeList: '奖项列表',
|
||||
addActivity: '添加抽奖',
|
||||
downloadTemplateTip: '下载文件后,请在excel中填写数据,并保存为xlsx格式',
|
||||
uploadExcelTip: '上传修改好的excel文件',
|
||||
leftClick: '左键切割',
|
||||
toHome: '主页',
|
||||
resetLayout: '该项比较耗费时间和性能',
|
||||
defaultLayout: '默认图案设置针对17列时有效,其他列数请自行设置',
|
||||
doneCount: '已抽取',
|
||||
edit: '编辑',
|
||||
delete: '删除',
|
||||
timedStop: '开始抽奖过后定时停止,默认为0,单位为秒,0为关闭定时停止功能',
|
||||
uploadImage: '上传图片',
|
||||
pleaseGoto: '请先前往',
|
||||
settingConfiguration: '设置/配置',
|
||||
nextSong: '右键点击下一首',
|
||||
noSongPlay: '没有音乐可以播放',
|
||||
prizeList: '奖项列表',
|
||||
addActivity: '添加抽奖',
|
||||
downloadTemplateTip: '下载文件后,请在excel中填写数据,并保存为xlsx格式',
|
||||
uploadExcelTip: '上传修改好的excel文件',
|
||||
leftClick: '左键切割',
|
||||
toHome: '主页',
|
||||
resetLayout: '该项比较耗费时间和性能',
|
||||
defaultLayout: '默认图案设置针对17列时有效,其他列数请自行设置',
|
||||
doneCount: '已抽取',
|
||||
edit: '编辑',
|
||||
delete: '删除',
|
||||
timedStop: '开始抽奖过后定时停止,默认为0,单位为秒,0为关闭定时停止功能',
|
||||
uploadImage: '上传图片',
|
||||
pleaseGoto: '请先前往',
|
||||
}
|
||||
|
||||
export const tooltip = {
|
||||
en: tooltipEn,
|
||||
zhCn: tooltipZhCn,
|
||||
en: tooltipEn,
|
||||
zhCn: tooltipZhCn,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import { usePrizeConfig } from './prizeConfig'
|
||||
import { useSystem } from './system'
|
||||
|
||||
export default function useStore() {
|
||||
return {
|
||||
personConfig: usePersonConfig(),
|
||||
prizeConfig: usePrizeConfig(),
|
||||
globalConfig: useGlobalConfig(),
|
||||
system: useSystem(),
|
||||
}
|
||||
return {
|
||||
personConfig: usePersonConfig(),
|
||||
prizeConfig: usePrizeConfig(),
|
||||
globalConfig: useGlobalConfig(),
|
||||
system: useSystem(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,175 +3,175 @@ import { defineStore } from 'pinia'
|
||||
import { defaultCurrentPrize, defaultPrizeList } from './data'
|
||||
|
||||
export const usePrizeConfig = defineStore('prize', {
|
||||
state() {
|
||||
return {
|
||||
prizeConfig: {
|
||||
prizeList: defaultPrizeList,
|
||||
currentPrize: defaultCurrentPrize,
|
||||
temporaryPrize: {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig,
|
||||
},
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
state() {
|
||||
return {
|
||||
prizeConfig: {
|
||||
prizeList: defaultPrizeList,
|
||||
currentPrize: defaultCurrentPrize,
|
||||
temporaryPrize: {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig,
|
||||
},
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
// 获取全部配置
|
||||
getPrizeConfigAll(state) {
|
||||
return state.prizeConfig
|
||||
},
|
||||
// 获取奖品列表
|
||||
getPrizeConfig(state) {
|
||||
return state.prizeConfig.prizeList
|
||||
},
|
||||
// 根据id获取配置
|
||||
getPrizeConfigById(state) {
|
||||
return (id: number | string) => {
|
||||
return state.prizeConfig.prizeList.find(item => item.id === id)
|
||||
}
|
||||
},
|
||||
// 获取当前奖项
|
||||
getCurrentPrize(state) {
|
||||
return state.prizeConfig.currentPrize
|
||||
},
|
||||
// 获取临时的奖项
|
||||
getTemporaryPrize(state) {
|
||||
return state.prizeConfig.temporaryPrize
|
||||
},
|
||||
getPrizeConfigAll(state) {
|
||||
return state.prizeConfig
|
||||
},
|
||||
// 获取奖品列表
|
||||
getPrizeConfig(state) {
|
||||
return state.prizeConfig.prizeList
|
||||
},
|
||||
// 根据id获取配置
|
||||
getPrizeConfigById(state) {
|
||||
return (id: number | string) => {
|
||||
return state.prizeConfig.prizeList.find(item => item.id === id)
|
||||
}
|
||||
},
|
||||
// 获取当前奖项
|
||||
getCurrentPrize(state) {
|
||||
return state.prizeConfig.currentPrize
|
||||
},
|
||||
// 获取临时的奖项
|
||||
getTemporaryPrize(state) {
|
||||
return state.prizeConfig.temporaryPrize
|
||||
},
|
||||
|
||||
},
|
||||
actions: {
|
||||
},
|
||||
actions: {
|
||||
// 设置奖项
|
||||
setPrizeConfig(prizeList: IPrizeConfig[]) {
|
||||
this.prizeConfig.prizeList = prizeList
|
||||
},
|
||||
// 添加奖项
|
||||
addPrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||
this.prizeConfig.prizeList.push(prizeConfigItem)
|
||||
},
|
||||
// 删除奖项
|
||||
deletePrizeConfig(prizeConfigItemId: number | string) {
|
||||
this.prizeConfig.prizeList = this.prizeConfig.prizeList.filter(item => item.id !== prizeConfigItemId)
|
||||
},
|
||||
// 更新奖项数据
|
||||
updatePrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||
const prizeListLength = this.prizeConfig.prizeList.length
|
||||
if (prizeConfigItem.isUsed && prizeListLength) {
|
||||
for (let i = 0; i < prizeListLength; i++) {
|
||||
if (!this.prizeConfig.prizeList[i].isUsed) {
|
||||
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return
|
||||
}
|
||||
this.resetTemporaryPrize()
|
||||
},
|
||||
// 删除全部奖项
|
||||
deleteAllPrizeConfig() {
|
||||
this.prizeConfig.prizeList = [] as IPrizeConfig[]
|
||||
},
|
||||
// 设置当前奖项
|
||||
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
||||
this.prizeConfig.currentPrize = prizeConfigItem
|
||||
},
|
||||
// 设置临时奖项
|
||||
setTemporaryPrize(prizeItem: IPrizeConfig) {
|
||||
if (prizeItem.isShow === false) {
|
||||
for (let i = 0; i < this.prizeConfig.prizeList.length; i++) {
|
||||
if (this.prizeConfig.prizeList[i].isUsed === false) {
|
||||
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
this.resetTemporaryPrize()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.prizeConfig.temporaryPrize = prizeItem
|
||||
},
|
||||
// 重置临时奖项
|
||||
resetTemporaryPrize() {
|
||||
this.prizeConfig.temporaryPrize = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
setPrizeConfig(prizeList: IPrizeConfig[]) {
|
||||
this.prizeConfig.prizeList = prizeList
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
// 添加奖项
|
||||
addPrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||
this.prizeConfig.prizeList.push(prizeConfigItem)
|
||||
},
|
||||
// 删除奖项
|
||||
deletePrizeConfig(prizeConfigItemId: number | string) {
|
||||
this.prizeConfig.prizeList = this.prizeConfig.prizeList.filter(item => item.id !== prizeConfigItemId)
|
||||
},
|
||||
// 更新奖项数据
|
||||
updatePrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||
const prizeListLength = this.prizeConfig.prizeList.length
|
||||
if (prizeConfigItem.isUsed && prizeListLength) {
|
||||
for (let i = 0; i < prizeListLength; i++) {
|
||||
if (!this.prizeConfig.prizeList[i].isUsed) {
|
||||
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return
|
||||
}
|
||||
this.resetTemporaryPrize()
|
||||
},
|
||||
// 删除全部奖项
|
||||
deleteAllPrizeConfig() {
|
||||
this.prizeConfig.prizeList = [] as IPrizeConfig[]
|
||||
},
|
||||
// 设置当前奖项
|
||||
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
||||
this.prizeConfig.currentPrize = prizeConfigItem
|
||||
},
|
||||
// 设置临时奖项
|
||||
setTemporaryPrize(prizeItem: IPrizeConfig) {
|
||||
if (prizeItem.isShow === false) {
|
||||
for (let i = 0; i < this.prizeConfig.prizeList.length; i++) {
|
||||
if (this.prizeConfig.prizeList[i].isUsed === false) {
|
||||
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
this.resetTemporaryPrize()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.prizeConfig.temporaryPrize = prizeItem
|
||||
},
|
||||
// 重置临时奖项
|
||||
resetTemporaryPrize() {
|
||||
this.prizeConfig.temporaryPrize = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig
|
||||
},
|
||||
// 重置所有配置
|
||||
resetDefault() {
|
||||
this.prizeConfig = {
|
||||
prizeList: defaultPrizeList,
|
||||
currentPrize: defaultCurrentPrize,
|
||||
temporaryPrize: {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig,
|
||||
}
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig
|
||||
},
|
||||
// 重置所有配置
|
||||
resetDefault() {
|
||||
this.prizeConfig = {
|
||||
prizeList: defaultPrizeList,
|
||||
currentPrize: defaultCurrentPrize,
|
||||
temporaryPrize: {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 0,
|
||||
isAll: false,
|
||||
count: 1,
|
||||
isUsedCount: 0,
|
||||
picture: {
|
||||
id: '-1',
|
||||
name: '',
|
||||
url: '',
|
||||
},
|
||||
separateCount: {
|
||||
enable: true,
|
||||
countList: [],
|
||||
},
|
||||
desc: '',
|
||||
isShow: false,
|
||||
isUsed: false,
|
||||
frequency: 1,
|
||||
} as IPrizeConfig,
|
||||
}
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
// 如果要存储在localStorage中
|
||||
storage: localStorage,
|
||||
key: 'prizeConfig',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
// 如果要存储在localStorage中
|
||||
storage: localStorage,
|
||||
key: 'prizeConfig',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import { defineStore } from 'pinia'
|
||||
// import { IPrizeConfig } from '@/types/storeType';
|
||||
export const useSystem = defineStore('system', {
|
||||
state() {
|
||||
return {
|
||||
isMobile: false,
|
||||
isChrome: true,
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getIsMobile(state) {
|
||||
return state.isMobile
|
||||
state() {
|
||||
return {
|
||||
isMobile: false,
|
||||
isChrome: true,
|
||||
}
|
||||
},
|
||||
getIsChrome(state) {
|
||||
return state.isChrome
|
||||
getters: {
|
||||
getIsMobile(state) {
|
||||
return state.isMobile
|
||||
},
|
||||
getIsChrome(state) {
|
||||
return state.isChrome
|
||||
},
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setIsMobile(isMobile: boolean) {
|
||||
this.isMobile = isMobile
|
||||
actions: {
|
||||
setIsMobile(isMobile: boolean) {
|
||||
this.isMobile = isMobile
|
||||
},
|
||||
setIsChrome(isChrome: boolean) {
|
||||
this.isChrome = isChrome
|
||||
},
|
||||
},
|
||||
setIsChrome(isChrome: boolean) {
|
||||
this.isChrome = isChrome
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
// 如果要存储在localStorage中
|
||||
// storage: localStorage,
|
||||
// key: 'globalConfig',
|
||||
// paths: ['globalConfig'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
// 如果要存储在localStorage中
|
||||
// storage: localStorage,
|
||||
// key: 'globalConfig',
|
||||
// paths: ['globalConfig'],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function getToken() {
|
||||
return window.localStorage.getItem('userToken')
|
||||
return window.localStorage.getItem('userToken')
|
||||
}
|
||||
|
||||
@@ -42,32 +42,32 @@ export function rgba(color: string, opacity: number) {
|
||||
|
||||
export function rgbToHex(color: string) {
|
||||
// 去掉字符串中的空格
|
||||
color = color.replace(/\s+/g, '');
|
||||
color = color.replace(/\s+/g, '')
|
||||
if (isHex(color)) {
|
||||
return color
|
||||
}
|
||||
// 匹配rgba或rgb格式的字符串
|
||||
const rgbaMatch = color.match(/^rgba?\((\d+),(\d+),(\d+),?(\d*\.?\d+)?\)$/i);
|
||||
const rgbaMatch = color.match(/^rgba?\((\d+),(\d+),(\d+),?(\d+(?:\.\d+)?|\.\d+)?\)$/i)
|
||||
if (!rgbaMatch) {
|
||||
throw new Error('Invalid color format');
|
||||
throw new Error('Invalid color format')
|
||||
}
|
||||
|
||||
const r = parseInt(rgbaMatch[1], 10);
|
||||
const g = parseInt(rgbaMatch[2], 10);
|
||||
const b = parseInt(rgbaMatch[3], 10);
|
||||
const a = rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : undefined;
|
||||
const r = Number.parseInt(rgbaMatch[1], 10)
|
||||
const g = Number.parseInt(rgbaMatch[2], 10)
|
||||
const b = Number.parseInt(rgbaMatch[3], 10)
|
||||
const a = rgbaMatch[4] !== undefined ? Number.parseFloat(rgbaMatch[4]) : undefined
|
||||
|
||||
// 将RGB值转换为十六进制
|
||||
let hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
|
||||
let hex = `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`
|
||||
|
||||
// 如果提供了alpha值,则将其转换为十六进制并附加到结果中
|
||||
if (a !== undefined) {
|
||||
let alphaHex = Math.round(a * 255).toString(16).toUpperCase();
|
||||
let alphaHex = Math.round(a * 255).toString(16).toUpperCase()
|
||||
if (alphaHex.length === 1) {
|
||||
alphaHex = "0" + alphaHex; // 确保alpha值是两位数
|
||||
alphaHex = `0${alphaHex}` // 确保alpha值是两位数
|
||||
}
|
||||
hex += alphaHex;
|
||||
hex += alphaHex
|
||||
}
|
||||
|
||||
return hex;
|
||||
return hex
|
||||
}
|
||||
@@ -20,19 +20,19 @@ export function readFileData(file: File): Promise<{ data: string, fileName: stri
|
||||
|
||||
export function readFileDataAsBlob(file: File): Promise<{ data: Blob, fileName: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = () => {
|
||||
// 直接使用原始文件作为 Blob
|
||||
resolve({ data: file, fileName: file.name });
|
||||
};
|
||||
resolve({ data: file, fileName: file.name })
|
||||
}
|
||||
|
||||
reader.onerror = () => {
|
||||
reject(new Error('文件读取失败'));
|
||||
};
|
||||
reject(new Error('文件读取失败'))
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
reader.readAsArrayBuffer(file)
|
||||
})
|
||||
}
|
||||
|
||||
export async function readLocalFileAsArraybuffer(path: string): Promise<ArrayBuffer> {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// 提取有哪些字段
|
||||
export function extractFields(data: any) {
|
||||
const item = data[0]
|
||||
// 排除id x y,其他都加入数组
|
||||
const keys = Object.keys(item).filter(key => key !== 'id' && key !== 'x' && key !== 'y')
|
||||
if (keys.length > 0) {
|
||||
const item = data[0]
|
||||
// 排除id x y,其他都加入数组
|
||||
const keys = Object.keys(item).filter(key => key !== 'id' && key !== 'x' && key !== 'y')
|
||||
if (keys.length > 0) {
|
||||
// 返回数组key value
|
||||
return keys.map(key => ({ label: key, value: true }))
|
||||
}
|
||||
return keys.map(key => ({ label: key, value: true }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,36 +2,36 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
rowCount: {
|
||||
type: Number,
|
||||
default: 17,
|
||||
},
|
||||
cardColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
patternColor: {
|
||||
type: String,
|
||||
default: '#000',
|
||||
},
|
||||
patternList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
rowCount: {
|
||||
type: Number,
|
||||
default: 17,
|
||||
},
|
||||
cardColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
patternColor: {
|
||||
type: String,
|
||||
default: '#000',
|
||||
},
|
||||
patternList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
const data = computed(() => {
|
||||
return props
|
||||
return props
|
||||
})
|
||||
|
||||
function updatePatternList(event: Event, item: number) {
|
||||
if (data.value.patternList.includes(item)) {
|
||||
const index = data.value.patternList.indexOf(item)
|
||||
data.value.patternList.splice(index, 1)
|
||||
}
|
||||
else {
|
||||
data.value.patternList.push(item)
|
||||
}
|
||||
// emits
|
||||
if (data.value.patternList.includes(item)) {
|
||||
const index = data.value.patternList.indexOf(item)
|
||||
data.value.patternList.splice(index, 1)
|
||||
}
|
||||
else {
|
||||
data.value.patternList.push(item)
|
||||
}
|
||||
// emits
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,27 +6,27 @@ import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '@/components/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover'
|
||||
import { useLocalFonts } from '@/hooks/useLocalFonts'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
disabled?: boolean
|
||||
disabled?: boolean
|
||||
}>()
|
||||
const selectedFont = defineModel('selectedFont', {
|
||||
type: String,
|
||||
required: true,
|
||||
type: String,
|
||||
required: true,
|
||||
})
|
||||
const { getFonts, disabled: browserDisabled, fonts } = useLocalFonts()
|
||||
const open = ref(false)
|
||||
@@ -34,25 +34,25 @@ const activeKey = ref('')
|
||||
const debouncedActiveKey = refDebounced(activeKey, 20)
|
||||
const { t } = useI18n()
|
||||
function selectFont(selectedValue: any) {
|
||||
open.value = false
|
||||
activeKey.value = ''
|
||||
selectedFont.value = selectedValue
|
||||
open.value = false
|
||||
activeKey.value = ''
|
||||
selectedFont.value = selectedValue
|
||||
}
|
||||
|
||||
function handelActiveKey(val: string) {
|
||||
activeKey.value = val
|
||||
activeKey.value = val
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
activeKey.value = ''
|
||||
activeKey.value = ''
|
||||
}
|
||||
const disabledStyle = computed(() => {
|
||||
if (props.disabled || browserDisabled) {
|
||||
return {
|
||||
cursor: 'not-allowed',
|
||||
if (props.disabled || browserDisabled) {
|
||||
return {
|
||||
cursor: 'not-allowed',
|
||||
}
|
||||
}
|
||||
}
|
||||
return {}
|
||||
return {}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -7,48 +7,48 @@ import CustomDialog from '@/components/Dialog/index.vue'
|
||||
import FileUpload from '@/components/FileUpload/index.vue'
|
||||
|
||||
interface Props {
|
||||
importAllConfigData: (data: any) => void
|
||||
importAllConfigData: (data: any) => void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const toast = useToast()
|
||||
const limitType = ref('application/json')
|
||||
const visible = defineModel('visible', {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
type: Boolean,
|
||||
required: true,
|
||||
})
|
||||
const jsonFileData = ref<IFileData | null>(null)
|
||||
const { t } = useI18n()
|
||||
const uploadDialogRef = ref()
|
||||
|
||||
async function uploadFile(fileData: IFileData | null) {
|
||||
if (!fileData) {
|
||||
jsonFileData.value = null
|
||||
return
|
||||
}
|
||||
const isJson = /application\/json/.test(fileData?.type || '')
|
||||
if (!isJson) {
|
||||
toast.open({
|
||||
message: t('error.notJsonFile'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
jsonFileData.value = fileData
|
||||
if (!fileData) {
|
||||
jsonFileData.value = null
|
||||
return
|
||||
}
|
||||
const isJson = /application\/json/.test(fileData?.type || '')
|
||||
if (!isJson) {
|
||||
toast.open({
|
||||
message: t('error.notJsonFile'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
jsonFileData.value = fileData
|
||||
}
|
||||
|
||||
function submitUpload() {
|
||||
if (jsonFileData.value) {
|
||||
if (jsonFileData.value) {
|
||||
// 把文件转化为json数据
|
||||
const jsonData = jsonFileData.value.data
|
||||
props.importAllConfigData(jsonData)
|
||||
}
|
||||
const jsonData = jsonFileData.value.data
|
||||
props.importAllConfigData(jsonData)
|
||||
}
|
||||
}
|
||||
watch(visible, (newVal) => {
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,38 +6,38 @@ import { useViewModel } from './useViewModel'
|
||||
|
||||
const { t } = useI18n()
|
||||
const {
|
||||
resetData,
|
||||
topTitleValue,
|
||||
languageValue,
|
||||
textSizeValue,
|
||||
currentFontValue,
|
||||
currentTitleFontValue,
|
||||
titleFontSyncGlobalValue,
|
||||
languageList,
|
||||
formErr,
|
||||
formData,
|
||||
cardSizeValue,
|
||||
isShowPrizeListValue,
|
||||
isShowAvatarValue,
|
||||
resetPersonLayout,
|
||||
isRowCountChange,
|
||||
themeValue,
|
||||
backgroundImageValue,
|
||||
cardColorValue,
|
||||
luckyCardColorValue,
|
||||
textColorValue,
|
||||
patternColorValue,
|
||||
imageList,
|
||||
rowCount,
|
||||
cardColor,
|
||||
patternColor,
|
||||
patternList,
|
||||
clearPattern,
|
||||
resetPattern,
|
||||
exportAllConfigData,
|
||||
importAllConfigData,
|
||||
definiteTimeValue,
|
||||
isWinMusicValue,
|
||||
resetData,
|
||||
topTitleValue,
|
||||
languageValue,
|
||||
textSizeValue,
|
||||
currentFontValue,
|
||||
currentTitleFontValue,
|
||||
titleFontSyncGlobalValue,
|
||||
languageList,
|
||||
formErr,
|
||||
formData,
|
||||
cardSizeValue,
|
||||
isShowPrizeListValue,
|
||||
isShowAvatarValue,
|
||||
resetPersonLayout,
|
||||
isRowCountChange,
|
||||
themeValue,
|
||||
backgroundImageValue,
|
||||
cardColorValue,
|
||||
luckyCardColorValue,
|
||||
textColorValue,
|
||||
patternColorValue,
|
||||
imageList,
|
||||
rowCount,
|
||||
cardColor,
|
||||
patternColor,
|
||||
patternList,
|
||||
clearPattern,
|
||||
resetPattern,
|
||||
exportAllConfigData,
|
||||
importAllConfigData,
|
||||
definiteTimeValue,
|
||||
isWinMusicValue,
|
||||
} = useViewModel()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useI18n } from 'vue-i18n'
|
||||
import UploadJsonModal from '../components/UploadDialog.vue'
|
||||
|
||||
interface Props {
|
||||
resetData: () => void
|
||||
exportAllConfigData: () => void
|
||||
importAllConfigData: (data: any) => void
|
||||
resetData: () => void
|
||||
exportAllConfigData: () => void
|
||||
importAllConfigData: (data: any) => void
|
||||
}
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
interface Props {
|
||||
resetPersonLayout: () => void
|
||||
isRowCountChange: number
|
||||
resetPersonLayout: () => void
|
||||
isRowCountChange: number
|
||||
}
|
||||
defineProps<Props>()
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ import { useI18n } from 'vue-i18n'
|
||||
import PatternEdit from '../components/PatternEdit.vue'
|
||||
|
||||
interface Props {
|
||||
rowCount: number
|
||||
cardColor: string
|
||||
patternColor: string
|
||||
patternList: number[]
|
||||
clearPattern: () => void
|
||||
resetPattern: () => void
|
||||
rowCount: number
|
||||
cardColor: string
|
||||
patternColor: string
|
||||
patternList: number[]
|
||||
clearPattern: () => void
|
||||
resetPattern: () => void
|
||||
}
|
||||
defineProps<Props>()
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -8,7 +8,7 @@ import { daisyuiThemes } from '@/constant/theme'
|
||||
import 'vue3-colorpicker/style.css'
|
||||
|
||||
interface Props {
|
||||
imageList: Array<IImage>
|
||||
imageList: Array<IImage>
|
||||
}
|
||||
defineProps<Props>()
|
||||
const themeList = reactive(daisyuiThemes)
|
||||
|
||||
@@ -7,235 +7,235 @@ import { themeChange } from '@/utils'
|
||||
import { clearAllDbStore } from '@/utils/localforage'
|
||||
|
||||
export function useViewModel() {
|
||||
type ValidatePayload = zod.infer<typeof schema>
|
||||
const globalConfig = useStore().globalConfig
|
||||
const personConfig = useStore().personConfig
|
||||
const prizeConfig = useStore().prizeConfig
|
||||
const {
|
||||
getGlobalConfig: globalConfigData,
|
||||
getTopTitle: topTitle,
|
||||
getTheme: localTheme,
|
||||
getPatterColor: patternColor,
|
||||
getPatternList: patternList,
|
||||
getCardColor: cardColor,
|
||||
getLuckyColor: luckyCardColor,
|
||||
getTextColor: textColor,
|
||||
getCardSize: cardSize,
|
||||
getTextSize: textSize,
|
||||
getRowCount: rowCount,
|
||||
getIsShowPrizeList: isShowPrizeList,
|
||||
getLanguage: userLanguage,
|
||||
getBackground: backgroundImage,
|
||||
getFont: currentFont,
|
||||
getTitleFont: currentTitleFont,
|
||||
getTitleFontSyncGlobal: titleFontSyncGlobal,
|
||||
getImageList: imageList,
|
||||
getIsShowAvatar: isShowAvatar,
|
||||
getDefiniteTime: definiteTime,
|
||||
getWinMusic: isWinMusic,
|
||||
} = storeToRefs(globalConfig)
|
||||
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
|
||||
type ValidatePayload = zod.infer<typeof schema>
|
||||
const globalConfig = useStore().globalConfig
|
||||
const personConfig = useStore().personConfig
|
||||
const prizeConfig = useStore().prizeConfig
|
||||
const {
|
||||
getGlobalConfig: globalConfigData,
|
||||
getTopTitle: topTitle,
|
||||
getTheme: localTheme,
|
||||
getPatterColor: patternColor,
|
||||
getPatternList: patternList,
|
||||
getCardColor: cardColor,
|
||||
getLuckyColor: luckyCardColor,
|
||||
getTextColor: textColor,
|
||||
getCardSize: cardSize,
|
||||
getTextSize: textSize,
|
||||
getRowCount: rowCount,
|
||||
getIsShowPrizeList: isShowPrizeList,
|
||||
getLanguage: userLanguage,
|
||||
getBackground: backgroundImage,
|
||||
getFont: currentFont,
|
||||
getTitleFont: currentTitleFont,
|
||||
getTitleFontSyncGlobal: titleFontSyncGlobal,
|
||||
getImageList: imageList,
|
||||
getIsShowAvatar: isShowAvatar,
|
||||
getDefiniteTime: definiteTime,
|
||||
getWinMusic: isWinMusic,
|
||||
} = storeToRefs(globalConfig)
|
||||
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
|
||||
|
||||
const isRowCountChange = ref(0) // 0未改变,1改变,2加载中
|
||||
const themeValue = ref(localTheme.value.name)
|
||||
const topTitleValue = ref(structuredClone(topTitle.value))
|
||||
const cardColorValue = ref(structuredClone(cardColor.value))
|
||||
const luckyCardColorValue = ref(structuredClone(luckyCardColor.value))
|
||||
const textColorValue = ref(structuredClone(textColor.value))
|
||||
const cardSizeValue = ref(structuredClone(cardSize.value))
|
||||
const textSizeValue = ref(structuredClone(textSize.value))
|
||||
const rowCountValue = ref(structuredClone(rowCount.value))
|
||||
const languageValue = ref(structuredClone(userLanguage.value))
|
||||
const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
|
||||
const isShowAvatarValue = ref(structuredClone(isShowAvatar.value))
|
||||
const patternColorValue = ref(structuredClone(patternColor.value))
|
||||
const backgroundImageValue = ref(backgroundImage.value)
|
||||
const currentFontValue = ref(structuredClone(currentFont.value))
|
||||
const currentTitleFontValue = ref(structuredClone(currentTitleFont.value))
|
||||
const titleFontSyncGlobalValue = ref(structuredClone(titleFontSyncGlobal.value))
|
||||
const definiteTimeValue = ref(structuredClone(definiteTime.value))
|
||||
const isWinMusicValue = ref(structuredClone(isWinMusic.value))
|
||||
const formData = ref({
|
||||
rowCount: rowCountValue,
|
||||
})
|
||||
const formErr = ref({
|
||||
rowCount: '',
|
||||
})
|
||||
const schema = zod.object({
|
||||
rowCount: zod.number({
|
||||
error: i18n.global.t('error.require'),
|
||||
// required_error: i18n.global.t('error.require'),
|
||||
// invalid_type_error: i18n.global.t('error.requireNumber'),
|
||||
const isRowCountChange = ref(0) // 0未改变,1改变,2加载中
|
||||
const themeValue = ref(localTheme.value.name)
|
||||
const topTitleValue = ref(structuredClone(topTitle.value))
|
||||
const cardColorValue = ref(structuredClone(cardColor.value))
|
||||
const luckyCardColorValue = ref(structuredClone(luckyCardColor.value))
|
||||
const textColorValue = ref(structuredClone(textColor.value))
|
||||
const cardSizeValue = ref(structuredClone(cardSize.value))
|
||||
const textSizeValue = ref(structuredClone(textSize.value))
|
||||
const rowCountValue = ref(structuredClone(rowCount.value))
|
||||
const languageValue = ref(structuredClone(userLanguage.value))
|
||||
const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
|
||||
const isShowAvatarValue = ref(structuredClone(isShowAvatar.value))
|
||||
const patternColorValue = ref(structuredClone(patternColor.value))
|
||||
const backgroundImageValue = ref(backgroundImage.value)
|
||||
const currentFontValue = ref(structuredClone(currentFont.value))
|
||||
const currentTitleFontValue = ref(structuredClone(currentTitleFont.value))
|
||||
const titleFontSyncGlobalValue = ref(structuredClone(titleFontSyncGlobal.value))
|
||||
const definiteTimeValue = ref(structuredClone(definiteTime.value))
|
||||
const isWinMusicValue = ref(structuredClone(isWinMusic.value))
|
||||
const formData = ref({
|
||||
rowCount: rowCountValue,
|
||||
})
|
||||
.min(1, i18n.global.t('error.minNumber1'))
|
||||
.max(100, i18n.global.t('error.maxNumber100')),
|
||||
// 格式化
|
||||
|
||||
})
|
||||
const payload: ValidatePayload = {
|
||||
rowCount: formData.value.rowCount,
|
||||
}
|
||||
function parseSchema(props: ValidatePayload) {
|
||||
return schema.parseAsync(props)
|
||||
}
|
||||
|
||||
function resetPersonLayout() {
|
||||
isRowCountChange.value = 2
|
||||
setTimeout(() => {
|
||||
const alreadyLen = alreadyPersonList.value.length
|
||||
const notLen = notPersonList.value.length
|
||||
if (alreadyLen <= 0 && notLen <= 0) {
|
||||
return
|
||||
}
|
||||
const allPersonList = alreadyPersonList.value.concat(notPersonList.value)
|
||||
const newAlreadyPersonList = allPersonList.slice(0, alreadyLen)
|
||||
const newNotPersonList = allPersonList.slice(alreadyLen, notLen + alreadyLen)
|
||||
personConfig.deleteAllPerson()
|
||||
personConfig.addNotPersonList(newNotPersonList)
|
||||
personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
|
||||
|
||||
isRowCountChange.value = 0
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
function clearPattern() {
|
||||
globalConfig.setPatternList([] as number[])
|
||||
}
|
||||
function resetPattern() {
|
||||
globalConfig.resetPatternList()
|
||||
}
|
||||
|
||||
function resetData() {
|
||||
globalConfig.reset()
|
||||
personConfig.reset()
|
||||
prizeConfig.resetDefault()
|
||||
// 删除所有indexDb
|
||||
clearAllDbStore()
|
||||
// 刷新页面
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
function exportAllConfigData() {
|
||||
// const globalConfigData = globalConfig.getGlobalConfig()
|
||||
// console.log(globalConfigData.value)
|
||||
// const globalConfigData = globalConfig.getGlobalConfig()
|
||||
const dataStr = JSON.stringify(globalConfigData.value, null, 2)
|
||||
const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`
|
||||
|
||||
const exportFileDefaultName = 'global-config.json'
|
||||
|
||||
const linkElement = document.createElement('a')
|
||||
linkElement.setAttribute('href', dataUri)
|
||||
linkElement.setAttribute('download', exportFileDefaultName)
|
||||
linkElement.click()
|
||||
}
|
||||
function importAllConfigData(data: any) {
|
||||
globalConfig.setGlobalConfig(data)
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
watch(() => formData.value.rowCount, () => {
|
||||
payload.rowCount = formData.value.rowCount
|
||||
parseSchema(payload).then((res) => {
|
||||
if (res.rowCount) {
|
||||
isRowCountChange.value = 1
|
||||
globalConfig.setRowCount(res.rowCount)
|
||||
}
|
||||
}).catch((err) => {
|
||||
formErr.value.rowCount = err.issues[0].message
|
||||
const formErr = ref({
|
||||
rowCount: '',
|
||||
})
|
||||
})
|
||||
const schema = zod.object({
|
||||
rowCount: zod.number({
|
||||
error: i18n.global.t('error.require'),
|
||||
// required_error: i18n.global.t('error.require'),
|
||||
// invalid_type_error: i18n.global.t('error.requireNumber'),
|
||||
})
|
||||
.min(1, i18n.global.t('error.minNumber1'))
|
||||
.max(100, i18n.global.t('error.maxNumber100')),
|
||||
// 格式化
|
||||
|
||||
watch(topTitleValue, (val) => {
|
||||
globalConfig.setTopTitle(val)
|
||||
})
|
||||
watch(themeValue, (val: any) => {
|
||||
globalConfig.setTheme({ name: val })
|
||||
themeChange(val)
|
||||
}, { deep: true })
|
||||
})
|
||||
const payload: ValidatePayload = {
|
||||
rowCount: formData.value.rowCount,
|
||||
}
|
||||
function parseSchema(props: ValidatePayload) {
|
||||
return schema.parseAsync(props)
|
||||
}
|
||||
|
||||
watch(cardColorValue, (val: string) => {
|
||||
globalConfig.setCardColor(val)
|
||||
}, { deep: true })
|
||||
watch(luckyCardColorValue, (val: string) => {
|
||||
globalConfig.setLuckyCardColor(val)
|
||||
}, { deep: true })
|
||||
watch(patternColorValue, (val: string) => {
|
||||
globalConfig.setPatterColor(val)
|
||||
})
|
||||
watch(textColorValue, (val: string) => {
|
||||
globalConfig.setTextColor(val)
|
||||
}, { deep: true })
|
||||
function resetPersonLayout() {
|
||||
isRowCountChange.value = 2
|
||||
setTimeout(() => {
|
||||
const alreadyLen = alreadyPersonList.value.length
|
||||
const notLen = notPersonList.value.length
|
||||
if (alreadyLen <= 0 && notLen <= 0) {
|
||||
return
|
||||
}
|
||||
const allPersonList = alreadyPersonList.value.concat(notPersonList.value)
|
||||
const newAlreadyPersonList = allPersonList.slice(0, alreadyLen)
|
||||
const newNotPersonList = allPersonList.slice(alreadyLen, notLen + alreadyLen)
|
||||
personConfig.deleteAllPerson()
|
||||
personConfig.addNotPersonList(newNotPersonList)
|
||||
personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
|
||||
|
||||
watch(cardSizeValue, (val: { width: number, height: number }) => {
|
||||
globalConfig.setCardSize(val)
|
||||
}, { deep: true })
|
||||
isRowCountChange.value = 0
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
watch(isShowPrizeListValue, () => {
|
||||
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
||||
})
|
||||
watch(backgroundImageValue, (val) => {
|
||||
globalConfig.setBackground(val)
|
||||
})
|
||||
watch(currentFontValue, (val) => {
|
||||
globalConfig.setFont(val)
|
||||
document.documentElement.style.setProperty('--app-font-family', `"${val}", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`)
|
||||
})
|
||||
watch(currentTitleFontValue, (val) => {
|
||||
globalConfig.setTitleFont(val)
|
||||
})
|
||||
watch(titleFontSyncGlobalValue, (val) => {
|
||||
globalConfig.setTitleFontSyncGlobal(val)
|
||||
})
|
||||
watch(languageValue, (val: string) => {
|
||||
globalConfig.setLanguage(val)
|
||||
})
|
||||
watch(isShowAvatarValue, () => {
|
||||
globalConfig.setIsShowAvatar(isShowAvatarValue.value)
|
||||
})
|
||||
watch(definiteTimeValue, () => {
|
||||
globalConfig.setDefiniteTime(definiteTimeValue.value)
|
||||
})
|
||||
watch(isWinMusicValue, () => {
|
||||
globalConfig.setIsPlayWinMusic(isWinMusicValue.value)
|
||||
})
|
||||
watch(textSizeValue, (val: number) => {
|
||||
globalConfig.setTextSize(val)
|
||||
})
|
||||
onMounted(() => {
|
||||
})
|
||||
return {
|
||||
resetData,
|
||||
topTitleValue,
|
||||
languageValue,
|
||||
textSizeValue,
|
||||
currentFontValue,
|
||||
currentTitleFontValue,
|
||||
titleFontSyncGlobalValue,
|
||||
languageList,
|
||||
formErr,
|
||||
formData,
|
||||
cardSizeValue,
|
||||
isShowPrizeListValue,
|
||||
isShowAvatarValue,
|
||||
resetPersonLayout,
|
||||
isRowCountChange,
|
||||
themeValue,
|
||||
backgroundImageValue,
|
||||
cardColorValue,
|
||||
luckyCardColorValue,
|
||||
textColorValue,
|
||||
patternColorValue,
|
||||
imageList,
|
||||
rowCount,
|
||||
cardColor,
|
||||
patternColor,
|
||||
patternList,
|
||||
clearPattern,
|
||||
resetPattern,
|
||||
exportAllConfigData,
|
||||
importAllConfigData,
|
||||
definiteTimeValue,
|
||||
isWinMusicValue,
|
||||
}
|
||||
function clearPattern() {
|
||||
globalConfig.setPatternList([] as number[])
|
||||
}
|
||||
function resetPattern() {
|
||||
globalConfig.resetPatternList()
|
||||
}
|
||||
|
||||
function resetData() {
|
||||
globalConfig.reset()
|
||||
personConfig.reset()
|
||||
prizeConfig.resetDefault()
|
||||
// 删除所有indexDb
|
||||
clearAllDbStore()
|
||||
// 刷新页面
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
function exportAllConfigData() {
|
||||
// const globalConfigData = globalConfig.getGlobalConfig()
|
||||
// console.log(globalConfigData.value)
|
||||
// const globalConfigData = globalConfig.getGlobalConfig()
|
||||
const dataStr = JSON.stringify(globalConfigData.value, null, 2)
|
||||
const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`
|
||||
|
||||
const exportFileDefaultName = 'global-config.json'
|
||||
|
||||
const linkElement = document.createElement('a')
|
||||
linkElement.setAttribute('href', dataUri)
|
||||
linkElement.setAttribute('download', exportFileDefaultName)
|
||||
linkElement.click()
|
||||
}
|
||||
function importAllConfigData(data: any) {
|
||||
globalConfig.setGlobalConfig(data)
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
watch(() => formData.value.rowCount, () => {
|
||||
payload.rowCount = formData.value.rowCount
|
||||
parseSchema(payload).then((res) => {
|
||||
if (res.rowCount) {
|
||||
isRowCountChange.value = 1
|
||||
globalConfig.setRowCount(res.rowCount)
|
||||
}
|
||||
}).catch((err) => {
|
||||
formErr.value.rowCount = err.issues[0].message
|
||||
})
|
||||
})
|
||||
|
||||
watch(topTitleValue, (val) => {
|
||||
globalConfig.setTopTitle(val)
|
||||
})
|
||||
watch(themeValue, (val: any) => {
|
||||
globalConfig.setTheme({ name: val })
|
||||
themeChange(val)
|
||||
}, { deep: true })
|
||||
|
||||
watch(cardColorValue, (val: string) => {
|
||||
globalConfig.setCardColor(val)
|
||||
}, { deep: true })
|
||||
watch(luckyCardColorValue, (val: string) => {
|
||||
globalConfig.setLuckyCardColor(val)
|
||||
}, { deep: true })
|
||||
watch(patternColorValue, (val: string) => {
|
||||
globalConfig.setPatterColor(val)
|
||||
})
|
||||
watch(textColorValue, (val: string) => {
|
||||
globalConfig.setTextColor(val)
|
||||
}, { deep: true })
|
||||
|
||||
watch(cardSizeValue, (val: { width: number, height: number }) => {
|
||||
globalConfig.setCardSize(val)
|
||||
}, { deep: true })
|
||||
|
||||
watch(isShowPrizeListValue, () => {
|
||||
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
||||
})
|
||||
watch(backgroundImageValue, (val) => {
|
||||
globalConfig.setBackground(val)
|
||||
})
|
||||
watch(currentFontValue, (val) => {
|
||||
globalConfig.setFont(val)
|
||||
document.documentElement.style.setProperty('--app-font-family', `"${val}", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`)
|
||||
})
|
||||
watch(currentTitleFontValue, (val) => {
|
||||
globalConfig.setTitleFont(val)
|
||||
})
|
||||
watch(titleFontSyncGlobalValue, (val) => {
|
||||
globalConfig.setTitleFontSyncGlobal(val)
|
||||
})
|
||||
watch(languageValue, (val: string) => {
|
||||
globalConfig.setLanguage(val)
|
||||
})
|
||||
watch(isShowAvatarValue, () => {
|
||||
globalConfig.setIsShowAvatar(isShowAvatarValue.value)
|
||||
})
|
||||
watch(definiteTimeValue, () => {
|
||||
globalConfig.setDefiniteTime(definiteTimeValue.value)
|
||||
})
|
||||
watch(isWinMusicValue, () => {
|
||||
globalConfig.setIsPlayWinMusic(isWinMusicValue.value)
|
||||
})
|
||||
watch(textSizeValue, (val: number) => {
|
||||
globalConfig.setTextSize(val)
|
||||
})
|
||||
onMounted(() => {
|
||||
})
|
||||
return {
|
||||
resetData,
|
||||
topTitleValue,
|
||||
languageValue,
|
||||
textSizeValue,
|
||||
currentFontValue,
|
||||
currentTitleFontValue,
|
||||
titleFontSyncGlobalValue,
|
||||
languageList,
|
||||
formErr,
|
||||
formData,
|
||||
cardSizeValue,
|
||||
isShowPrizeListValue,
|
||||
isShowAvatarValue,
|
||||
resetPersonLayout,
|
||||
isRowCountChange,
|
||||
themeValue,
|
||||
backgroundImageValue,
|
||||
cardColorValue,
|
||||
luckyCardColorValue,
|
||||
textColorValue,
|
||||
patternColorValue,
|
||||
imageList,
|
||||
rowCount,
|
||||
cardColor,
|
||||
patternColor,
|
||||
patternList,
|
||||
clearPattern,
|
||||
resetPattern,
|
||||
exportAllConfigData,
|
||||
importAllConfigData,
|
||||
definiteTimeValue,
|
||||
isWinMusicValue,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,72 +12,72 @@ const { t } = useI18n()
|
||||
const limitType = ref('image/*')
|
||||
const imgUploadToast = ref(0) // 0是不显示,1是成功,2是失败,3是不是图片
|
||||
const visible = defineModel('visible', {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
type: Boolean,
|
||||
required: true,
|
||||
})
|
||||
const globalConfig = useStore().globalConfig
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
name: 'imgStore',
|
||||
})
|
||||
const imageData = ref<IFileData | null>(null)
|
||||
|
||||
const fileName = computed({
|
||||
get() {
|
||||
return imageData.value?.fileName || null
|
||||
},
|
||||
set(value) {
|
||||
if (imageData.value && value) {
|
||||
imageData.value.fileName = value
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return imageData.value?.fileName || null
|
||||
},
|
||||
set(value) {
|
||||
if (imageData.value && value) {
|
||||
imageData.value.fileName = value
|
||||
}
|
||||
},
|
||||
})
|
||||
const uploadDialogRef = ref()
|
||||
|
||||
async function uploadFile(fileData: IFileData | null) {
|
||||
if (!fileData) {
|
||||
imageData.value = null
|
||||
return
|
||||
}
|
||||
const isImage = /image*/.test(fileData?.type || '')
|
||||
if (!isImage) {
|
||||
imgUploadToast.value = 3
|
||||
return
|
||||
}
|
||||
imageData.value = fileData
|
||||
if (!fileData) {
|
||||
imageData.value = null
|
||||
return
|
||||
}
|
||||
const isImage = /image*/.test(fileData?.type || '')
|
||||
if (!isImage) {
|
||||
imgUploadToast.value = 3
|
||||
return
|
||||
}
|
||||
imageData.value = fileData
|
||||
}
|
||||
async function getImageDbStore() {
|
||||
const keys = await imageDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
imageDbStore.iterate((value: { fileName: string, data: Blob }, key: string) => {
|
||||
globalConfig.addImage({
|
||||
id: key,
|
||||
name: value.fileName,
|
||||
url: 'Storage',
|
||||
})
|
||||
})
|
||||
}
|
||||
const keys = await imageDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
imageDbStore.iterate((value: { fileName: string, data: Blob }, key: string) => {
|
||||
globalConfig.addImage({
|
||||
id: key,
|
||||
name: value.fileName,
|
||||
url: 'Storage',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
function submitUpload() {
|
||||
if (imageData.value) {
|
||||
const { data, fileName } = imageData.value
|
||||
const uniqueId = uuidv4()
|
||||
imageDbStore.setItem(uniqueId, {
|
||||
data,
|
||||
fileName,
|
||||
})
|
||||
.then(() => {
|
||||
imgUploadToast.value = 1
|
||||
getImageDbStore()
|
||||
})
|
||||
.catch(() => {
|
||||
imgUploadToast.value = 2
|
||||
})
|
||||
}
|
||||
if (imageData.value) {
|
||||
const { data, fileName } = imageData.value
|
||||
const uniqueId = uuidv4()
|
||||
imageDbStore.setItem(uniqueId, {
|
||||
data,
|
||||
fileName,
|
||||
})
|
||||
.then(() => {
|
||||
imgUploadToast.value = 1
|
||||
getImageDbStore()
|
||||
})
|
||||
.catch(() => {
|
||||
imgUploadToast.value = 2
|
||||
})
|
||||
}
|
||||
}
|
||||
watch(visible, (newVal) => {
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -14,25 +14,25 @@ const globalConfig = useStore().globalConfig
|
||||
const { getImageList: localImageList } = storeToRefs(globalConfig)
|
||||
const imgUploadToast = ref(0) // 0是不显示,1是成功,2是失败,3是不是图片
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
name: 'imgStore',
|
||||
})
|
||||
|
||||
const uploadVisible = ref(false)
|
||||
|
||||
function removeImage(item: IImage) {
|
||||
if (item.url === 'Storage') {
|
||||
imageDbStore.removeItem(item.id).then(() => {
|
||||
globalConfig.removeImage(item.id)
|
||||
})
|
||||
}
|
||||
globalConfig.removeImage(item.id)
|
||||
if (item.url === 'Storage') {
|
||||
imageDbStore.removeItem(item.id).then(() => {
|
||||
globalConfig.removeImage(item.id)
|
||||
})
|
||||
}
|
||||
globalConfig.removeImage(item.id)
|
||||
}
|
||||
watch(() => imgUploadToast.value, (val) => {
|
||||
if (val !== 0) {
|
||||
setTimeout(() => {
|
||||
imgUploadToast.value = 0
|
||||
}, 2000)
|
||||
}
|
||||
if (val !== 0) {
|
||||
setTimeout(() => {
|
||||
imgUploadToast.value = 0
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -13,84 +13,84 @@ const { t } = useI18n()
|
||||
const toast = useToast()
|
||||
const limitType = ref('audio/*')
|
||||
const visible = defineModel('visible', {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
type: Boolean,
|
||||
required: true,
|
||||
})
|
||||
const globalConfig = useStore().globalConfig
|
||||
const audioDbStore = localforage.createInstance({
|
||||
name: 'audioStore',
|
||||
name: 'audioStore',
|
||||
})
|
||||
const audioData = ref<IFileData | null>(null)
|
||||
|
||||
const fileName = computed({
|
||||
get() {
|
||||
return audioData.value?.fileName || null
|
||||
},
|
||||
set(value) {
|
||||
if (audioData.value && value) {
|
||||
audioData.value.fileName = value
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return audioData.value?.fileName || null
|
||||
},
|
||||
set(value) {
|
||||
if (audioData.value && value) {
|
||||
audioData.value.fileName = value
|
||||
}
|
||||
},
|
||||
})
|
||||
const uploadDialogRef = ref()
|
||||
|
||||
async function uploadFile(fileData: IFileData | null) {
|
||||
if (!fileData) {
|
||||
audioData.value = null
|
||||
return
|
||||
}
|
||||
const isAudio = /audio*/.test(fileData?.type || '')
|
||||
if (!isAudio) {
|
||||
toast.open({
|
||||
message: t('error.notAudioFile'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
audioData.value = fileData
|
||||
if (!fileData) {
|
||||
audioData.value = null
|
||||
return
|
||||
}
|
||||
const isAudio = /audio*/.test(fileData?.type || '')
|
||||
if (!isAudio) {
|
||||
toast.open({
|
||||
message: t('error.notAudioFile'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
audioData.value = fileData
|
||||
}
|
||||
async function getAudioDbStore() {
|
||||
const keys = await audioDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
audioDbStore.iterate((value: { fileName: string, data: Blob }, key: string) => {
|
||||
globalConfig.addMusic({
|
||||
id: key,
|
||||
name: value.fileName,
|
||||
url: 'Storage',
|
||||
})
|
||||
})
|
||||
}
|
||||
const keys = await audioDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
audioDbStore.iterate((value: { fileName: string, data: Blob }, key: string) => {
|
||||
globalConfig.addMusic({
|
||||
id: key,
|
||||
name: value.fileName,
|
||||
url: 'Storage',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
function submitUpload() {
|
||||
if (audioData.value) {
|
||||
const { data, fileName } = audioData.value
|
||||
const uniqueId = uuidv4()
|
||||
audioDbStore.setItem(uniqueId, {
|
||||
data,
|
||||
fileName,
|
||||
})
|
||||
.then(() => {
|
||||
toast.open({
|
||||
message: t('error.uploadSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
if (audioData.value) {
|
||||
const { data, fileName } = audioData.value
|
||||
const uniqueId = uuidv4()
|
||||
audioDbStore.setItem(uniqueId, {
|
||||
data,
|
||||
fileName,
|
||||
})
|
||||
getAudioDbStore()
|
||||
})
|
||||
.catch(() => {
|
||||
toast.open({
|
||||
message: t('error.uploadFail'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
})
|
||||
}
|
||||
.then(() => {
|
||||
toast.open({
|
||||
message: t('error.uploadSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
})
|
||||
getAudioDbStore()
|
||||
})
|
||||
.catch(() => {
|
||||
toast.open({
|
||||
message: t('error.uploadFail'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
watch(visible, (newVal) => {
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
if (newVal) {
|
||||
uploadDialogRef.value.showDialog()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ import { storeToRefs } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import PageHeader from '@/components/PageHeader/index.vue'
|
||||
import { sidebar } from '@/locales/modules'
|
||||
import useStore from '@/store'
|
||||
import UploadDialog from './components/UploadDialog.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const audioDbStore = localforage.createInstance({
|
||||
name: 'audioStore',
|
||||
name: 'audioStore',
|
||||
})
|
||||
const globalConfig = useStore().globalConfig
|
||||
|
||||
@@ -19,23 +18,23 @@ const { getMusicList: localMusicList } = storeToRefs(globalConfig)
|
||||
const localMusicListValue = ref(localMusicList)
|
||||
const uploadVisible = ref(false)
|
||||
async function play(item: IMusic) {
|
||||
globalConfig.setCurrentMusic(item, false)
|
||||
globalConfig.setCurrentMusic(item, false)
|
||||
}
|
||||
|
||||
function deleteMusic(item: IMusic) {
|
||||
globalConfig.removeMusic(item.id)
|
||||
audioDbStore.removeItem(item.name)
|
||||
// setTimeout(()=>{
|
||||
// localMusicListValue.value=localMusicList
|
||||
// },100)
|
||||
globalConfig.removeMusic(item.id)
|
||||
audioDbStore.removeItem(item.name)
|
||||
// setTimeout(()=>{
|
||||
// localMusicListValue.value=localMusicList
|
||||
// },100)
|
||||
}
|
||||
function resetMusic() {
|
||||
globalConfig.resetMusicList()
|
||||
audioDbStore.clear()
|
||||
globalConfig.resetMusicList()
|
||||
audioDbStore.clear()
|
||||
}
|
||||
function deleteAll() {
|
||||
globalConfig.clearMusicList()
|
||||
audioDbStore.clear()
|
||||
globalConfig.clearMusicList()
|
||||
audioDbStore.clear()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
defineProps<{
|
||||
addOnePersonDrawerRef: any
|
||||
addOnePerson: (addOnePersonDrawerRef: any, event: any) => void
|
||||
addOnePersonDrawerRef: any
|
||||
addOnePerson: (addOnePersonDrawerRef: any, event: any) => void
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -11,43 +11,43 @@ let allData: any[] = []
|
||||
|
||||
function headersEqual(template: string[], actual: string[]): boolean {
|
||||
return template.length >= actual.length
|
||||
&& actual.some(item => template.includes(item))
|
||||
&& actual.some(item => template.includes(item))
|
||||
}
|
||||
// 接收主线程消息
|
||||
globalThis.onmessage = async (e: MessageEvent<WorkerMessage>) => {
|
||||
switch (e.data.type) {
|
||||
case 'start':
|
||||
{
|
||||
const fileData = e.data.data
|
||||
const templateData = e.data.templateData
|
||||
{
|
||||
const fileData = e.data.data
|
||||
const templateData = e.data.templateData
|
||||
|
||||
const workBook = XLSX.read(fileData, { type: 'binary', cellDates: true })
|
||||
const workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
||||
const excelData: object[] = XLSX.utils.sheet_to_json(workSheet)
|
||||
const workBook = XLSX.read(fileData, { type: 'binary', cellDates: true })
|
||||
const workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
||||
const excelData: object[] = XLSX.utils.sheet_to_json(workSheet)
|
||||
|
||||
const templateWorkBook = XLSX.read(templateData, { type: 'array', cellDates: true })
|
||||
const templateWorkSheet = templateWorkBook.Sheets[templateWorkBook.SheetNames[0]]
|
||||
const templateExcelData: object[] = XLSX.utils.sheet_to_json(templateWorkSheet)
|
||||
const templateWorkBook = XLSX.read(templateData, { type: 'array', cellDates: true })
|
||||
const templateWorkSheet = templateWorkBook.Sheets[templateWorkBook.SheetNames[0]]
|
||||
const templateExcelData: object[] = XLSX.utils.sheet_to_json(templateWorkSheet)
|
||||
|
||||
const templateHeader = Object.keys(templateExcelData[0])
|
||||
const header = Object.keys(excelData[0])
|
||||
const templateHeader = Object.keys(templateExcelData[0])
|
||||
const header = Object.keys(excelData[0])
|
||||
|
||||
if (!headersEqual(templateHeader, header)) {
|
||||
globalThis.postMessage({
|
||||
type: 'error',
|
||||
data: null,
|
||||
message: 'not right template',
|
||||
})
|
||||
return
|
||||
}
|
||||
allData = addOtherInfo(excelData)
|
||||
if (!headersEqual(templateHeader, header)) {
|
||||
globalThis.postMessage({
|
||||
type: 'done',
|
||||
data: allData,
|
||||
message: '读取完成',
|
||||
type: 'error',
|
||||
data: null,
|
||||
message: 'not right template',
|
||||
})
|
||||
break
|
||||
return
|
||||
}
|
||||
allData = addOtherInfo(excelData)
|
||||
globalThis.postMessage({
|
||||
type: 'done',
|
||||
data: allData,
|
||||
message: '读取完成',
|
||||
})
|
||||
break
|
||||
}
|
||||
default:
|
||||
globalThis.postMessage({
|
||||
type: 'fail',
|
||||
|
||||
@@ -14,16 +14,16 @@ const delAllDataDialogRef = ref()
|
||||
const exportInputFileRef = ref()
|
||||
const addOnePersonDrawerRef = ref()
|
||||
const {
|
||||
resetData,
|
||||
deleteAll,
|
||||
handleFileChange,
|
||||
exportData,
|
||||
addOnePerson,
|
||||
singlePersonData,
|
||||
alreadyPersonList,
|
||||
allPersonList,
|
||||
tableColumnList,
|
||||
downloadTemplate,
|
||||
resetData,
|
||||
deleteAll,
|
||||
handleFileChange,
|
||||
exportData,
|
||||
addOnePerson,
|
||||
singlePersonData,
|
||||
alreadyPersonList,
|
||||
allPersonList,
|
||||
tableColumnList,
|
||||
downloadTemplate,
|
||||
} = useViewModel({ exportInputFileRef })
|
||||
const { t } = useI18n()
|
||||
const limitType = '.xlsx,.xls'
|
||||
|
||||
@@ -17,185 +17,185 @@ import ImportExcelWorker from './importExcel.worker?worker'
|
||||
type IBasePersonConfig = Pick<IPersonConfig, 'uid' | 'name' | 'department' | 'identity' | 'avatar'>
|
||||
|
||||
export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<HTMLInputElement> }) {
|
||||
const { t } = useI18n()
|
||||
const baseUrl = import.meta.env.BASE_URL
|
||||
const toast = useToast()
|
||||
const worker: Worker | null = new ImportExcelWorker()
|
||||
const loading = inject(loadingKey)
|
||||
const personConfig = useStore().personConfig
|
||||
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
||||
const tableColumnList = tableColumns({ handleDeletePerson: delPersonItem })
|
||||
const addPersonModalVisible = ref(false)
|
||||
const singlePersonData = ref<IBasePersonConfig>({
|
||||
uid: '',
|
||||
name: '',
|
||||
department: '',
|
||||
avatar: '',
|
||||
identity: '',
|
||||
})
|
||||
async function getExcelTemplateContent() {
|
||||
const locale = i18n.global.locale.value
|
||||
if (locale === 'zhCn') {
|
||||
const templateData = await readLocalFileAsArraybuffer(`${import.meta.env.BASE_URL}人口登记表-zhCn.xlsx`)
|
||||
return templateData
|
||||
}
|
||||
else {
|
||||
const templateData = await readLocalFileAsArraybuffer(`${import.meta.env.BASE_URL}personListTemplate-en.xlsx`)
|
||||
return templateData
|
||||
}
|
||||
}
|
||||
/// 向worker发送消息
|
||||
function sendWorkerMessage(message: any) {
|
||||
if (worker) {
|
||||
worker.postMessage(message)
|
||||
}
|
||||
}
|
||||
/// 开始导入
|
||||
async function startWorker(data: string) {
|
||||
loading?.show()
|
||||
getExcelTemplateContent()
|
||||
sendWorkerMessage({ type: 'start', data, templateData: await getExcelTemplateContent() })
|
||||
}
|
||||
/**
|
||||
* 获取用户数据
|
||||
*/
|
||||
async function handleFileChange(e: Event) {
|
||||
if (worker) {
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.type === 'done') {
|
||||
personConfig.resetPerson()
|
||||
personConfig.addNotPersonList(e.data.data)
|
||||
// 提示导入成功
|
||||
toast.open({
|
||||
message: t('error.importSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
})
|
||||
// 导入成功后清空file input
|
||||
clearFileInput()
|
||||
const { t } = useI18n()
|
||||
const baseUrl = import.meta.env.BASE_URL.replace('./', '/')
|
||||
const toast = useToast()
|
||||
const worker: Worker | null = new ImportExcelWorker()
|
||||
const loading = inject(loadingKey)
|
||||
const personConfig = useStore().personConfig
|
||||
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
||||
const tableColumnList = tableColumns({ handleDeletePerson: delPersonItem })
|
||||
const addPersonModalVisible = ref(false)
|
||||
const singlePersonData = ref<IBasePersonConfig>({
|
||||
uid: '',
|
||||
name: '',
|
||||
department: '',
|
||||
avatar: '',
|
||||
identity: '',
|
||||
})
|
||||
async function getExcelTemplateContent() {
|
||||
const locale = i18n.global.locale.value
|
||||
if (locale === 'zhCn') {
|
||||
const templateData = await readLocalFileAsArraybuffer(`${baseUrl}人口登记表-zhCn.xlsx`)
|
||||
return templateData
|
||||
}
|
||||
if (e.data.type === 'error') {
|
||||
if (e.data.message === 'not right template') {
|
||||
toast.open({
|
||||
message: t('error.excelFileError'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
toast.open({
|
||||
message: e.data.message || t('error.importFail'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
// toast.warning(e.data.message || '导入错误')
|
||||
else {
|
||||
const templateData = await readLocalFileAsArraybuffer(`${baseUrl}personListTemplate-en.xlsx`)
|
||||
return templateData
|
||||
}
|
||||
loading?.hide()
|
||||
}
|
||||
}
|
||||
const dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
|
||||
startWorker(dataBinary)
|
||||
}
|
||||
// 清空file input
|
||||
function clearFileInput() {
|
||||
if (exportInputFileRef.value) {
|
||||
exportInputFileRef.value.value = ''
|
||||
/// 向worker发送消息
|
||||
function sendWorkerMessage(message: any) {
|
||||
if (worker) {
|
||||
worker.postMessage(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
function downloadTemplate() {
|
||||
/// 开始导入
|
||||
async function startWorker(data: string) {
|
||||
loading?.show()
|
||||
getExcelTemplateContent()
|
||||
sendWorkerMessage({ type: 'start', data, templateData: await getExcelTemplateContent() })
|
||||
}
|
||||
/**
|
||||
* 获取用户数据
|
||||
*/
|
||||
async function handleFileChange(e: Event) {
|
||||
if (worker) {
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.type === 'done') {
|
||||
personConfig.resetPerson()
|
||||
personConfig.addNotPersonList(e.data.data)
|
||||
// 提示导入成功
|
||||
toast.open({
|
||||
message: t('error.importSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
})
|
||||
// 导入成功后清空file input
|
||||
clearFileInput()
|
||||
}
|
||||
if (e.data.type === 'error') {
|
||||
if (e.data.message === 'not right template') {
|
||||
toast.open({
|
||||
message: t('error.excelFileError'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
return
|
||||
}
|
||||
toast.open({
|
||||
message: e.data.message || t('error.importFail'),
|
||||
type: 'error',
|
||||
position: 'top-right',
|
||||
})
|
||||
// toast.warning(e.data.message || '导入错误')
|
||||
}
|
||||
loading?.hide()
|
||||
}
|
||||
}
|
||||
const dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
|
||||
startWorker(dataBinary)
|
||||
}
|
||||
// 清空file input
|
||||
function clearFileInput() {
|
||||
if (exportInputFileRef.value) {
|
||||
exportInputFileRef.value.value = ''
|
||||
}
|
||||
}
|
||||
function downloadTemplate() {
|
||||
// 下载
|
||||
const templateFileName = i18n.global.t('data.xlsxName')
|
||||
const fileUrl = `${baseUrl}${templateFileName}`
|
||||
fetch(fileUrl)
|
||||
.then(res => res.blob())
|
||||
.then((blob) => {
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = templateFileName
|
||||
a.click()
|
||||
toast.open({
|
||||
message: t('error.downloadSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
})
|
||||
})
|
||||
}
|
||||
// 导出数据
|
||||
function exportData() {
|
||||
let data = JSON.parse(JSON.stringify(allPersonList.value))
|
||||
// 排除一些字段
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
delete data[i].x
|
||||
delete data[i].y
|
||||
delete data[i].id
|
||||
delete data[i].createTime
|
||||
delete data[i].updateTime
|
||||
delete data[i].prizeId
|
||||
// 修改字段名称
|
||||
if (data[i].isWin) {
|
||||
data[i].isWin = i18n.global.t('data.yes')
|
||||
}
|
||||
else {
|
||||
data[i].isWin = i18n.global.t('data.no')
|
||||
}
|
||||
// 格式化数组为
|
||||
data[i].prizeTime = data[i].prizeTime.join(',')
|
||||
data[i].prizeName = data[i].prizeName.join(',')
|
||||
const templateFileName = i18n.global.t('data.xlsxName')
|
||||
const fileUrl = `${baseUrl}${templateFileName}`
|
||||
fetch(fileUrl)
|
||||
.then(res => res.blob())
|
||||
.then((blob) => {
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = templateFileName
|
||||
a.click()
|
||||
toast.open({
|
||||
message: t('error.downloadSuccess'),
|
||||
type: 'success',
|
||||
position: 'top-right',
|
||||
})
|
||||
})
|
||||
}
|
||||
let dataString = JSON.stringify(data)
|
||||
dataString = dataString
|
||||
.replaceAll(/uid/g, i18n.global.t('data.number'))
|
||||
.replaceAll(/isWin/g, i18n.global.t('data.isWin'))
|
||||
.replaceAll(/department/g, i18n.global.t('data.department'))
|
||||
.replaceAll(/name/g, i18n.global.t('data.name'))
|
||||
.replaceAll(/identity/g, i18n.global.t('data.identity'))
|
||||
.replaceAll(/prizeName/g, i18n.global.t('data.prizeName'))
|
||||
.replaceAll(/prizeTime/g, i18n.global.t('data.prizeTime'))
|
||||
// 导出数据
|
||||
function exportData() {
|
||||
let data = JSON.parse(JSON.stringify(allPersonList.value))
|
||||
// 排除一些字段
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
delete data[i].x
|
||||
delete data[i].y
|
||||
delete data[i].id
|
||||
delete data[i].createTime
|
||||
delete data[i].updateTime
|
||||
delete data[i].prizeId
|
||||
// 修改字段名称
|
||||
if (data[i].isWin) {
|
||||
data[i].isWin = i18n.global.t('data.yes')
|
||||
}
|
||||
else {
|
||||
data[i].isWin = i18n.global.t('data.no')
|
||||
}
|
||||
// 格式化数组为
|
||||
data[i].prizeTime = data[i].prizeTime.join(',')
|
||||
data[i].prizeName = data[i].prizeName.join(',')
|
||||
}
|
||||
let dataString = JSON.stringify(data)
|
||||
dataString = dataString
|
||||
.replaceAll(/uid/g, i18n.global.t('data.number'))
|
||||
.replaceAll(/isWin/g, i18n.global.t('data.isWin'))
|
||||
.replaceAll(/department/g, i18n.global.t('data.department'))
|
||||
.replaceAll(/name/g, i18n.global.t('data.name'))
|
||||
.replaceAll(/identity/g, i18n.global.t('data.identity'))
|
||||
.replaceAll(/prizeName/g, i18n.global.t('data.prizeName'))
|
||||
.replaceAll(/prizeTime/g, i18n.global.t('data.prizeTime'))
|
||||
|
||||
data = JSON.parse(dataString)
|
||||
data = JSON.parse(dataString)
|
||||
|
||||
if (data.length > 0) {
|
||||
const dataBinary = XLSX.utils.json_to_sheet(data)
|
||||
const dataBinaryBinary = XLSX.utils.book_new()
|
||||
XLSX.utils.book_append_sheet(dataBinaryBinary, dataBinary, 'Sheet1')
|
||||
XLSX.writeFile(dataBinaryBinary, 'data.xlsx')
|
||||
if (data.length > 0) {
|
||||
const dataBinary = XLSX.utils.json_to_sheet(data)
|
||||
const dataBinaryBinary = XLSX.utils.book_new()
|
||||
XLSX.utils.book_append_sheet(dataBinaryBinary, dataBinary, 'Sheet1')
|
||||
XLSX.writeFile(dataBinaryBinary, 'data.xlsx')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetData() {
|
||||
personConfig.resetAlreadyPerson()
|
||||
}
|
||||
function resetData() {
|
||||
personConfig.resetAlreadyPerson()
|
||||
}
|
||||
|
||||
function deleteAll() {
|
||||
personConfig.deleteAllPerson()
|
||||
}
|
||||
function deleteAll() {
|
||||
personConfig.deleteAllPerson()
|
||||
}
|
||||
|
||||
function delPersonItem(row: IPersonConfig) {
|
||||
personConfig.deletePerson(row)
|
||||
}
|
||||
function addOnePerson(addOnePersonDrawerRef: any, event: any) {
|
||||
event.preventDefault()
|
||||
// 表单中的验证信息清除
|
||||
function delPersonItem(row: IPersonConfig) {
|
||||
personConfig.deletePerson(row)
|
||||
}
|
||||
function addOnePerson(addOnePersonDrawerRef: any, event: any) {
|
||||
event.preventDefault()
|
||||
// 表单中的验证信息清除
|
||||
|
||||
const personData = addOtherInfo([toRaw(singlePersonData.value)])
|
||||
personData[0].id = uuidv4()
|
||||
personConfig.addOnePerson(personData)
|
||||
// singlePersonData.value = {} as IBasePersonConfig
|
||||
addOnePersonDrawerRef.closeDrawer()
|
||||
singlePersonData.value = {} as IBasePersonConfig
|
||||
}
|
||||
return {
|
||||
resetData,
|
||||
deleteAll,
|
||||
handleFileChange,
|
||||
exportData,
|
||||
alreadyPersonList,
|
||||
allPersonList,
|
||||
tableColumnList,
|
||||
addOnePerson,
|
||||
addPersonModalVisible,
|
||||
singlePersonData,
|
||||
downloadTemplate,
|
||||
}
|
||||
const personData = addOtherInfo([toRaw(singlePersonData.value)])
|
||||
personData[0].id = uuidv4()
|
||||
personConfig.addOnePerson(personData)
|
||||
// singlePersonData.value = {} as IBasePersonConfig
|
||||
addOnePersonDrawerRef.closeDrawer()
|
||||
singlePersonData.value = {} as IBasePersonConfig
|
||||
}
|
||||
return {
|
||||
resetData,
|
||||
deleteAll,
|
||||
handleFileChange,
|
||||
exportData,
|
||||
alreadyPersonList,
|
||||
allPersonList,
|
||||
tableColumnList,
|
||||
addOnePerson,
|
||||
addPersonModalVisible,
|
||||
singlePersonData,
|
||||
downloadTemplate,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,133 +8,133 @@ import i18n from '@/locales/i18n'
|
||||
import useStore from '@/store'
|
||||
|
||||
export function usePrizeConfig() {
|
||||
const toast = useToast()
|
||||
const imageDbStore = localforage.createInstance({
|
||||
name: 'imgStore',
|
||||
})
|
||||
const prizeConfig = useStore().prizeConfig
|
||||
const globalConfig = useStore().globalConfig
|
||||
const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
||||
const toast = useToast()
|
||||
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 imgList = ref<any[]>([])
|
||||
const { getImageList: localImageList } = storeToRefs(globalConfig)
|
||||
const imgList = ref<any[]>([])
|
||||
|
||||
const prizeList = ref(cloneDeep(localPrizeList.value))
|
||||
const selectedPrize = ref<IPrizeConfig | null>()
|
||||
const prizeList = ref(cloneDeep(localPrizeList.value))
|
||||
const selectedPrize = ref<IPrizeConfig | null>()
|
||||
|
||||
function selectPrize(item: IPrizeConfig) {
|
||||
selectedPrize.value = item
|
||||
selectedPrize.value.isUsedCount = 0
|
||||
selectedPrize.value.isUsed = false
|
||||
function selectPrize(item: IPrizeConfig) {
|
||||
selectedPrize.value = item
|
||||
selectedPrize.value.isUsedCount = 0
|
||||
selectedPrize.value.isUsed = false
|
||||
|
||||
if (selectedPrize.value.separateCount.countList.length > 1) {
|
||||
return
|
||||
if (selectedPrize.value.separateCount.countList.length > 1) {
|
||||
return
|
||||
}
|
||||
selectedPrize.value.separateCount = {
|
||||
enable: true,
|
||||
countList: [
|
||||
{
|
||||
id: '0',
|
||||
count: item.count,
|
||||
isUsedCount: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
selectedPrize.value.separateCount = {
|
||||
enable: true,
|
||||
countList: [
|
||||
{
|
||||
id: '0',
|
||||
count: item.count,
|
||||
isUsedCount: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
function changePrizeStatus(item: IPrizeConfig) {
|
||||
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
|
||||
}
|
||||
function changePrizeStatus(item: IPrizeConfig) {
|
||||
item.isUsed ? item.isUsedCount = 0 : item.isUsedCount = item.count
|
||||
item.separateCount.countList = []
|
||||
item.isUsed = !item.isUsed
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
async function getImageDbStore() {
|
||||
const keys = await imageDbStore.keys()
|
||||
if (keys.length > 0) {
|
||||
imageDbStore.iterate((value, key) => {
|
||||
imgList.value.push({
|
||||
key,
|
||||
value,
|
||||
})
|
||||
})
|
||||
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 delItem(item: IPrizeConfig) {
|
||||
prizeConfig.deletePrizeConfig(item.id)
|
||||
toast.success(i18n.global.t('error.deleteSuccess'))
|
||||
}
|
||||
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,
|
||||
function submitData(value: any) {
|
||||
selectedPrize.value!.separateCount.countList = value
|
||||
selectedPrize.value = null
|
||||
}
|
||||
prizeList.value.push(defaultPrizeCOnfig)
|
||||
toast.success(i18n.global.t('error.success'))
|
||||
}
|
||||
function resetDefault() {
|
||||
prizeConfig.resetDefault()
|
||||
prizeList.value = cloneDeep(localPrizeList.value)
|
||||
toast.success(i18n.global.t('error.success'))
|
||||
}
|
||||
async function delAll() {
|
||||
prizeList.value = []
|
||||
toast.success(i18n.global.t('error.success'))
|
||||
}
|
||||
onMounted(() => {
|
||||
getImageDbStore()
|
||||
})
|
||||
watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
prizeConfig.setPrizeConfig(val)
|
||||
}, { deep: true })
|
||||
|
||||
return {
|
||||
addPrize,
|
||||
resetDefault,
|
||||
delAll,
|
||||
delItem,
|
||||
prizeList,
|
||||
currentPrize,
|
||||
selectedPrize,
|
||||
submitData,
|
||||
changePrizePerson,
|
||||
changePrizeStatus,
|
||||
selectPrize,
|
||||
localImageList,
|
||||
}
|
||||
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)
|
||||
toast.success(i18n.global.t('error.deleteSuccess'))
|
||||
}
|
||||
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(i18n.global.t('error.success'))
|
||||
}
|
||||
function resetDefault() {
|
||||
prizeConfig.resetDefault()
|
||||
prizeList.value = cloneDeep(localPrizeList.value)
|
||||
toast.success(i18n.global.t('error.success'))
|
||||
}
|
||||
async function delAll() {
|
||||
prizeList.value = []
|
||||
toast.success(i18n.global.t('error.success'))
|
||||
}
|
||||
onMounted(() => {
|
||||
getImageDbStore()
|
||||
})
|
||||
watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||
prizeConfig.setPrizeConfig(val)
|
||||
}, { deep: true })
|
||||
|
||||
return {
|
||||
addPrize,
|
||||
resetDefault,
|
||||
delAll,
|
||||
delItem,
|
||||
prizeList,
|
||||
currentPrize,
|
||||
selectedPrize,
|
||||
submitData,
|
||||
changePrizePerson,
|
||||
changePrizeStatus,
|
||||
selectPrize,
|
||||
localImageList,
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user