From 2e5e0afd30ba65c16dc4cc4615ec13b3d625d867 Mon Sep 17 00:00:00 2001 From: Megghy Date: Thu, 17 Apr 2025 02:15:22 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E8=A7=86=E5=9B=BE=E7=BB=84=E4=BB=B6=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交对多个视图组件进行了重构和功能增强: PointGoodsView.vue: - 清理了未使用的导入(`useAccount`)和变量(`accountInfo`, `biliInfo` prop)。 - 通过重组计算属性和方法提高了代码可读性。 - 增强了商品列表的筛选和排序逻辑。 - 为购买商品功能添加了错误处理和加载状态。 PointUserHistoryView.vue: - 为获取积分历史记录实现了加载状态。 - 改进了 PointHistoryCard 组件的渲染。 QuestionBoxView.vue: - 优化了可读性和性能(整合状态变量,改进命名)。 - 增强了文件上传处理和验证逻辑。 - 改进了标签选择逻辑和数据获取方法。 - 添加了代码注释以提高可理解性。 UserIndexView.vue: - 简化了确定要显示的模板组件的逻辑。 - 确保无论用户信息是否存在,都一致返回默认模板。 --- src/client/ClientDanmakuWindow.vue | 2 +- src/components.d.ts | 2 + src/components/manage/PointGoodsItem.vue | 35 +- src/components/manage/PointHistoryCard.vue | 40 +- src/components/manage/PointOrderCard.vue | 108 +- src/store/useWebFetcher.ts | 2 +- src/views/ManageLayout.vue | 541 ++- src/views/manage/EventView.vue | 95 +- src/views/manage/HistoryView.vue | 632 ++-- src/views/manage/SettingsManageView.vue | 459 +-- src/views/manage/SongListManageView.vue | 454 ++- src/views/manage/point/PointManage.vue | 458 ++- src/views/manage/point/PointOrderManage.vue | 145 +- src/views/manage/point/PointSettings.vue | 237 +- src/views/manage/point/PointSubItemManage.vue | 28 +- .../manage/point/PointUserDetailCard.vue | 159 +- src/views/manage/point/PointUserManage.vue | 234 +- src/views/obs/DanmujiOBS.vue | 268 +- src/views/open_live/OpenQueue.vue | 2958 +++++++++-------- src/views/pointViews/PointGoodsView.vue | 843 +++-- src/views/pointViews/PointUserHistoryView.vue | 5 +- src/views/view/QuestionBoxView.vue | 105 +- src/views/view/UserIndexView.vue | 17 +- 23 files changed, 4747 insertions(+), 3080 deletions(-) diff --git a/src/client/ClientDanmakuWindow.vue b/src/client/ClientDanmakuWindow.vue index 8928517..8948114 100644 --- a/src/client/ClientDanmakuWindow.vue +++ b/src/client/ClientDanmakuWindow.vue @@ -89,7 +89,7 @@ } }, setting.value.animationDuration || 300); - console.log('[DanmakuWindow] 添加弹幕:', dataWithId); + //console.log('[DanmakuWindow] 添加弹幕:', dataWithId); } // 检查和移除过期弹幕 diff --git a/src/components.d.ts b/src/components.d.ts index 3c6e88d..e2e7cf3 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -20,9 +20,11 @@ declare module 'vue' { MonacoEditorComponent: typeof import('./components/MonacoEditorComponent.vue')['default'] NAlert: typeof import('naive-ui')['NAlert'] NAvatar: typeof import('naive-ui')['NAvatar'] + NBadge: typeof import('naive-ui')['NBadge'] NButton: typeof import('naive-ui')['NButton'] NCard: typeof import('naive-ui')['NCard'] NCheckbox: typeof import('naive-ui')['NCheckbox'] + NEmpty: typeof import('naive-ui')['NEmpty'] NFlex: typeof import('naive-ui')['NFlex'] NFormItemG: typeof import('naive-ui')['NFormItemG'] NFormItemGi: typeof import('naive-ui')['NFormItemGi'] diff --git a/src/components/manage/PointGoodsItem.vue b/src/components/manage/PointGoodsItem.vue index a4fb171..b4bcb64 100644 --- a/src/components/manage/PointGoodsItem.vue +++ b/src/components/manage/PointGoodsItem.vue @@ -8,6 +8,8 @@ goods: ResponsePointGoodModel | undefined; contentStyle?: string | undefined; }>(); + + // 默认封面图片 const emptyCover = IMGUR_URL + 'None.png'; @@ -20,7 +22,9 @@ v-else embedded :style="props.contentStyle" + class="goods-card" > + + + + + + + - + + + + 仅限舰长 + + + + + + diff --git a/src/components/manage/PointHistoryCard.vue b/src/components/manage/PointHistoryCard.vue index 7e91d19..d9769f4 100644 --- a/src/components/manage/PointHistoryCard.vue +++ b/src/components/manage/PointHistoryCard.vue @@ -12,6 +12,7 @@ import { NText, NTime, NTooltip, + NEmpty } from 'naive-ui' import { h, ref } from 'vue' import PointGoodsItem from './PointGoodsItem.vue' @@ -20,9 +21,11 @@ const props = defineProps<{ histories: ResponsePointHisrotyModel[] }>() +// 礼物详情模态框 const showGoodsModal = ref(false) const currentGoods = ref() +// 数据表格列定义 const historyColumn: DataTableColumns = [ { title: '时间', @@ -102,7 +105,6 @@ const historyColumn: DataTableColumns = [ { title: '详情', key: 'action', - render: (row: ResponsePointHisrotyModel) => { switch (row.from) { case PointFrom.Danmaku: @@ -128,6 +130,7 @@ const historyColumn: DataTableColumns = [ row.extra?.danmaku.price, ]) } + break case PointFrom.Manual: return h(NFlex, { align: 'center' }, () => [ h(NTag, { type: 'info', size: 'small', style: { margin: '0' } }, () => '来自'), @@ -162,23 +165,48 @@ const historyColumn: DataTableColumns = [ ), ]) } + return null }, }, ] diff --git a/src/components/manage/PointOrderCard.vue b/src/components/manage/PointOrderCard.vue index 9570666..b30143f 100644 --- a/src/components/manage/PointOrderCard.vue +++ b/src/components/manage/PointOrderCard.vue @@ -177,16 +177,28 @@ const orderColumn: DataTableColumns { - switch (row.status) { - case PointOrderStatus.Pending: - return h(NTag, { size: 'small' }, () => '等待发货') - case PointOrderStatus.Shipped: - return h(NTag, { size: 'small', type: row.expressCompany ? 'info' : 'warning', bordered: false }, () => - row.expressCompany ? '已发货 | 已填写单号' : '已发货 | 未填写单号', - ) - case PointOrderStatus.Completed: - return h(NTag, { size: 'small', type: 'success' }, () => '已完成') + const statusMap = { + [PointOrderStatus.Pending]: { + text: '等待发货', + type: 'default' + }, + [PointOrderStatus.Shipped]: { + text: row.expressCompany ? '已发货 | 已填写单号' : '已发货 | 未填写单号', + type: row.expressCompany ? 'info' : 'warning' + }, + [PointOrderStatus.Completed]: { + text: '已完成', + type: 'success' + } } + + const status = statusMap[row.status] || { text: '未知状态', type: 'error' } + + return h(NTag, { + size: 'small', + type: status.type as any, + bordered: false + }, () => status.text) }, }, { @@ -294,6 +306,7 @@ function onChangeStatus(id: number, status: PointOrderStatus) { } async function updateStatus(id: number[], status: PointOrderStatus) { try { + isLoading.value = true const data = await QueryPostAPI(POINT_API_URL + 'update-orders-status', { ids: id, status, @@ -311,6 +324,8 @@ async function updateStatus(id: number[], status: PointOrderStatus) { } catch (err) { message.error('操作失败: ' + err) console.log(err) + } finally { + isLoading.value = false } } async function updateExpress(item: ResponsePointOrder2OwnerModel) { @@ -358,7 +373,6 @@ onMounted(() => { - > { - + - + + { + + { }) 仅当 - 舰长和SC + + 舰长和SC + 中存在对应记录时才能生效 - 不限 - 总督 - 提督 - 舰长 + + 不限 + + + 总督 + + + 提督 + + + 舰长 + - + - 虚拟礼物 - 实体礼物 + + 虚拟礼物 + + + 实体礼物 + - - 允许重复兑换 + + + 允许重复兑换 + - + {{ currentGoodsModel.goods.id ? '修改' : '创建' }} diff --git a/src/views/manage/point/PointOrderManage.vue b/src/views/manage/point/PointOrderManage.vue index e46f68a..968625b 100644 --- a/src/views/manage/point/PointOrderManage.vue +++ b/src/views/manage/point/PointOrderManage.vue @@ -24,25 +24,32 @@ import { } from 'naive-ui' import { computed, onMounted, ref } from 'vue' +// 订单筛选设置类型定义 type OrderFilterSettings = { - type?: GoodsTypes - status?: PointOrderStatus - customer?: number - onlyRequireShippingInfo: boolean + type?: GoodsTypes // 订单类型(实体/虚拟) + status?: PointOrderStatus // 订单状态 + customer?: number // 用户ID + onlyRequireShippingInfo: boolean // 是否只显示需要物流信息的订单 } const props = defineProps<{ goods: ResponsePointGoodModel[] }>() + +// 默认筛选设置 const defaultSettings = { onlyRequireShippingInfo: false, } as OrderFilterSettings + +// 使用持久化存储保存筛选设置 const filterSettings = useStorage('Setting.Point.OrderFilter', defaultSettings) const message = useMessage() const accountInfo = useAccount() +// 订单数据 const orders = ref([]) +// 根据筛选条件过滤后的订单 const filteredOrders = computed(() => { return orders.value.filter((o) => { if (filterSettings.value.type != undefined && o.type !== filterSettings.value.type) return false @@ -52,9 +59,11 @@ const filteredOrders = computed(() => { return true }) }) + const isLoading = ref(false) const selectedItem = ref() +// 获取所有订单 async function getOrders() { try { isLoading.value = true @@ -72,7 +81,14 @@ async function getOrders() { } return [] } + +// 删除选中的订单 async function deleteOrder() { + if (!selectedItem.value?.length) { + message.warning('请选择要删除的订单') + return + } + try { const data = await QueryPostAPI(POINT_API_URL + 'delete-orders', selectedItem.value) if (data.code == 200) { @@ -87,45 +103,61 @@ async function deleteOrder() { console.log(err) } } + +// 订单状态文本映射 const statusText = { [PointOrderStatus.Completed]: '已完成', [PointOrderStatus.Pending]: '等待发货', [PointOrderStatus.Shipped]: '已发货', } + +// 导出订单数据为CSV function exportData() { - const text = objectsToCSV( - filteredOrders.value.map((s) => { - const gift = props.goods.find((g) => g.id == s.goodsId) - return { - 订单号: s.id, - 订单类型: s.type == GoodsTypes.Physical ? '实体' : '虚拟', - 订单状态: statusText[s.status], - 用户名: s.customer.name ?? '未知', - 用户UID: s.customer.userId, - 联系人: s.address?.name, - 联系电话: s.address?.phone, - 地址: s.address - ? `${s.address?.province}省${s.address?.city}市${s.address?.district}区${s.address?.street}街道${s.address?.address}` - : '无', - 礼物名: gift?.name ?? '已删除', - 礼物数量: s.count, - 礼物单价: gift?.price, - 礼物总价: s.point, - 快递公司: s.expressCompany, - 快递单号: s.trackingNumber, - 创建时间: format(s.createAt, 'yyyy-MM-dd HH:mm:ss'), - 更新时间: s.updateAt ? format(s.updateAt, 'yyyy-MM-dd HH:mm:ss') : '未更新', - } - }), - ) - const BOM = new Uint8Array([0xef, 0xbb, 0xbf]) - const utf8encoder = new TextEncoder() - const utf8array = utf8encoder.encode(text) - saveAs( - new Blob([BOM, utf8array], { type: 'text/csv;charset=utf-8;' }), - `积分订单_${format(Date.now(), 'yyyy-MM-dd HH:mm:ss')}_${accountInfo.value?.name}_.csv`, - ) + try { + const text = objectsToCSV( + filteredOrders.value.map((s) => { + const gift = props.goods.find((g) => g.id == s.goodsId) + return { + 订单号: s.id, + 订单类型: s.type == GoodsTypes.Physical ? '实体' : '虚拟', + 订单状态: statusText[s.status], + 用户名: s.customer.name ?? '未知', + 用户UID: s.customer.userId, + 联系人: s.address?.name, + 联系电话: s.address?.phone, + 地址: s.address + ? `${s.address?.province}省${s.address?.city}市${s.address?.district}区${s.address?.street}街道${s.address?.address}` + : '无', + 礼物名: gift?.name ?? '已删除', + 礼物数量: s.count, + 礼物单价: gift?.price, + 礼物总价: s.point, + 快递公司: s.expressCompany, + 快递单号: s.trackingNumber, + 创建时间: format(s.createAt, 'yyyy-MM-dd HH:mm:ss'), + 更新时间: s.updateAt ? format(s.updateAt, 'yyyy-MM-dd HH:mm:ss') : '未更新', + } + }), + ) + + // 添加BOM标记,确保Excel正确识别UTF-8编码 + const BOM = new Uint8Array([0xef, 0xbb, 0xbf]) + const utf8encoder = new TextEncoder() + const utf8array = utf8encoder.encode(text) + + saveAs( + new Blob([BOM, utf8array], { type: 'text/csv;charset=utf-8;' }), + `积分订单_${format(Date.now(), 'yyyy-MM-dd HH:mm:ss')}_${accountInfo.value?.name}_.csv`, + ) + + message.success('导出成功') + } catch (error) { + message.error('导出失败: ' + error) + console.error('导出失败:', error) + } } + +// 刷新订单数据 async function refresh() { orders.value = await getOrders() } @@ -142,8 +174,13 @@ onMounted(async () => { description="暂无订单" /> - + { ]" placeholder="订单状态" clearable - style="width: 150px" + style="min-width: 120px; max-width: 150px" /> - + > + 仅包含未填写快递单号的订单 + + + + diff --git a/src/views/manage/point/PointSettings.vue b/src/views/manage/point/PointSettings.vue index d042bfa..eed057b 100644 --- a/src/views/manage/point/PointSettings.vue +++ b/src/views/manage/point/PointSettings.vue @@ -32,20 +32,24 @@ import { computed, ref } from 'vue' const accountInfo = useAccount() const message = useMessage() + +// 默认积分设置 const defaultSettingPoint: Setting_Point = { - allowType: [EventDataTypes.Guard], - jianzhangPoint: 10, - tiduPoint: 100, - zongduPoint: 1000, - giftPercentMap: {}, // Empty object for an empty map - scPointPercent: 0.1, - giftPointPercent: 0.1, - giftAllowType: SettingPointGiftAllowType.All, + allowType: [EventDataTypes.Guard], // 默认只允许舰长积分 + jianzhangPoint: 10, // 舰长积分 + tiduPoint: 100, // 提督积分 + zongduPoint: 1000, // 总督积分 + giftPercentMap: {}, // 礼物积分映射表 + scPointPercent: 0.1, // SC积分比例 (10%) + giftPointPercent: 0.1, // 礼物积分比例 (10%) + giftAllowType: SettingPointGiftAllowType.All, // 默认允许所有礼物 } + +// 响应式设置对象 const setting = computed({ get: () => { if (accountInfo.value) { - return accountInfo.value.settings.point + return accountInfo.value.settings.point || defaultSettingPoint } return defaultSettingPoint }, @@ -55,65 +59,93 @@ const setting = computed({ } }, }) + +// 添加礼物表单模型 const addGiftModel = ref<{ name: string; point: number }>({ name: '', point: 1 }) +// 是否可以编辑设置 const canEdit = computed(() => { return accountInfo.value && accountInfo.value.settings }) + const isLoading = ref(false) const showAddGiftModal = ref(false) +// 更新积分设置 async function updateSettings() { - if (accountInfo.value) { - isLoading.value = true - setting.value.giftPercentMap ??= {} - try { - const msg = await SaveSetting('Point', setting.value) - if (msg) { - message.success('已保存') - return true - } else { - message.error('保存失败: ' + msg) - } - } catch (err) { - message.error('保存失败: ' + err) - console.error(err) - } finally { - isLoading.value = false - } - } else { + if (!accountInfo.value) { message.success('完成') + return false } + + isLoading.value = true + setting.value.giftPercentMap ??= {} + + try { + const msg = await SaveSetting('Point', setting.value) + if (msg) { + message.success('已保存') + return true + } else { + message.error('保存失败: ' + msg) + } + } catch (err) { + message.error('保存失败: ' + err) + console.error(err) + } finally { + isLoading.value = false + } + return false } + +// 添加礼物积分规则 async function addGift() { + // 表单验证 if (!addGiftModel.value.name) { message.error('请输入礼物名称') return } + if (addGiftModel.value.point > 2147483647) { - //不能超过int message.error('积分不能超过2147483647') + return } + + // 添加礼物积分规则 setting.value.giftPercentMap[addGiftModel.value.name] = addGiftModel.value.point - updateGift() + const success = await updateGift() + + // 添加成功后清空表单 + if (success) { + addGiftModel.value = { name: '', point: 1 } + showAddGiftModal.value = false + } } + +// 删除礼物积分规则 async function deleteGift(name: string) { const oldValue = setting.value.giftPercentMap[name] delete setting.value.giftPercentMap[name] + if (!(await updateGift())) { + // 如果更新失败,恢复原值 setting.value.giftPercentMap[name] = oldValue } } + +// 更新礼物积分规则 async function updateGift() { return await updateSettings() } + + \ No newline at end of file diff --git a/src/views/manage/point/PointUserDetailCard.vue b/src/views/manage/point/PointUserDetailCard.vue index 6978cac..aa2338e 100644 --- a/src/views/manage/point/PointUserDetailCard.vue +++ b/src/views/manage/point/PointUserDetailCard.vue @@ -31,6 +31,7 @@ import { } from 'naive-ui' import { onMounted, ref } from 'vue' +// 组件属性定义 const props = defineProps<{ user: ResponsePointUserModel goods: ResponsePointGoodModel[] @@ -38,20 +39,30 @@ const props = defineProps<{ const message = useMessage() +// 加载状态 const isLoading = ref(false) +// 用户订单列表 const orders = ref([]) +// 用户积分历史 const pointHistory = ref([]) +// 积分调整弹窗状态 const showAddPointModal = ref(false) const addPointCount = ref(0) -const addPointReason = ref() +const addPointReason = ref('') +// 获取用户订单 async function getOrders() { + if (!props.user.info?.id) { + return [] + } + try { isLoading.value = true const data = await QueryGetAPI(POINT_API_URL + 'get-user-orders', { authId: props.user.info?.id, }) + if (data.code == 200) { return data.data } else { @@ -64,21 +75,25 @@ async function getOrders() { } finally { isLoading.value = false } + return [] } + +// 获取用户积分历史 async function getPointHistory() { try { isLoading.value = true + + // 根据用户认证状态使用不同的请求参数 + const params = props.user.info.id > 0 + ? { authId: props.user.info.id } + : { id: props.user.info.userId ?? props.user.info.openId } + const data = await QueryGetAPI( POINT_API_URL + 'get-user-histories', - props.user.info.id > 0 - ? { - authId: props.user.info.id, - } - : { - id: props.user.info.userId ?? props.user.info.openId, - }, + params ) + if (data.code == 200) { return data.data } else { @@ -91,42 +106,58 @@ async function getPointHistory() { } finally { isLoading.value = false } + return [] } + +// 给用户增加/减少积分 async function givePoint() { + // 验证积分数量 if (addPointCount.value == 0) { message.error('积分数量不能为 0') return } + isLoading.value = true try { - const data = await QueryGetAPI( - POINT_API_URL + 'give-point', - props.user.info?.id >= 0 - ? { - authId: props.user.info?.id, - count: addPointCount.value, - reason: addPointReason.value ?? '', - } - : props.user.info?.userId - ? { - uId: props.user.info?.userId, - count: addPointCount.value, - reason: addPointReason.value ?? '', - } - : { - oId: props.user.info?.openId, - count: addPointCount.value, - reason: addPointReason.value ?? '', - }, - ) + // 根据用户认证状态构建不同的请求参数 + let params = {} + + if (props.user.info?.id >= 0) { + params = { + authId: props.user.info?.id, + count: addPointCount.value, + reason: addPointReason.value ?? '', + } + } else if (props.user.info?.userId) { + params = { + uId: props.user.info?.userId, + count: addPointCount.value, + reason: addPointReason.value ?? '', + } + } else { + params = { + oId: props.user.info?.openId, + count: addPointCount.value, + reason: addPointReason.value ?? '', + } + } + + const data = await QueryGetAPI(POINT_API_URL + 'give-point', params) + if (data.code == 200) { message.success('添加成功') showAddPointModal.value = false props.user.point += addPointCount.value + + // 重新加载积分历史 setTimeout(async () => { pointHistory.value = await getPointHistory() }, 1500) + + // 重置表单 + addPointCount.value = 0 + addPointReason.value = '' } else { message.error('添加积分失败: ' + data.message) console.error(data) @@ -139,8 +170,10 @@ async function givePoint() { } } +// 组件挂载时加载数据 onMounted(async () => { pointHistory.value = await getPointHistory() + if (props.user.info?.id) { orders.value = await getOrders() } @@ -151,10 +184,15 @@ onMounted(async () => { + + { :column="2" > - {{ user.info.name }} + {{ user.info.name || '未知' }} + {{ user.info.userId }} + {{ user.info.openId }} + {{ user.point }} + { + + + 订单 - + { :goods="goods" /> + + 积分历史 - + + + + { - + + { - 负数为扣除 + 负数为扣除积分 + { show-count clearable /> + { + + diff --git a/src/views/manage/point/PointUserManage.vue b/src/views/manage/point/PointUserManage.vue index 4ad37d7..6306291 100644 --- a/src/views/manage/point/PointUserManage.vue +++ b/src/views/manage/point/PointUserManage.vue @@ -1,8 +1,13 @@ diff --git a/src/views/open_live/OpenQueue.vue b/src/views/open_live/OpenQueue.vue index ccdcdc5..423dc73 100644 --- a/src/views/open_live/OpenQueue.vue +++ b/src/views/open_live/OpenQueue.vue @@ -1,634 +1,770 @@ + + {{ item.question.message }}
@@ -323,6 +370,8 @@ onUnmounted(() => { lazy />
+ +