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