mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
feat: 更新组件和API模型,优化用户体验
- 在api-models.ts中将goodsId字段更改为goods,以更好地表示商品信息 - 在多个组件中添加NEllipsis组件以优化文本显示 - 在AddressDisplay.vue中调整模板格式,提升可读性 - 在PointOrderCard.vue中更新订单信息的显示逻辑 - 在PointOrderManage.vue中添加批量更新订单状态的功能
This commit is contained in:
@@ -17,3 +17,12 @@
|
|||||||
- `open_live/`: 直播相关视图,包括点歌系统
|
- `open_live/`: 直播相关视图,包括点歌系统
|
||||||
- `obs/`: OBS相关视图组件
|
- `obs/`: OBS相关视图组件
|
||||||
- `public/`: 公共静态资源
|
- `public/`: 公共静态资源
|
||||||
|
|
||||||
|
## 项目使用的库
|
||||||
|
|
||||||
|
- @vueuse/core: 提供了一系列的 Vue 3 的实用函数
|
||||||
|
- @vicons/fluent: 图标
|
||||||
|
- naive-ui: 组件库
|
||||||
|
- pinia: 状态管理
|
||||||
|
- vue-router: 路由
|
||||||
|
- vue-echarts: 图表
|
||||||
|
|||||||
@@ -772,7 +772,7 @@ export interface ResponsePointOrder2OwnerModel {
|
|||||||
type: GoodsTypes
|
type: GoodsTypes
|
||||||
customer: BiliAuthModel
|
customer: BiliAuthModel
|
||||||
address?: AddressInfo
|
address?: AddressInfo
|
||||||
goodsId: number
|
goods: ResponsePointGoodModel
|
||||||
count: number
|
count: number
|
||||||
createAt: number
|
createAt: number
|
||||||
updateAt: number
|
updateAt: number
|
||||||
|
|||||||
2
src/components.d.ts
vendored
2
src/components.d.ts
vendored
@@ -22,6 +22,7 @@ declare module 'vue' {
|
|||||||
NAvatar: typeof import('naive-ui')['NAvatar']
|
NAvatar: typeof import('naive-ui')['NAvatar']
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
NCard: typeof import('naive-ui')['NCard']
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
|
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
NFlex: typeof import('naive-ui')['NFlex']
|
NFlex: typeof import('naive-ui')['NFlex']
|
||||||
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
NFormItemGi: typeof import('naive-ui')['NFormItemGi']
|
||||||
@@ -29,6 +30,7 @@ declare module 'vue' {
|
|||||||
NIcon: typeof import('naive-ui')['NIcon']
|
NIcon: typeof import('naive-ui')['NIcon']
|
||||||
NImage: typeof import('naive-ui')['NImage']
|
NImage: typeof import('naive-ui')['NImage']
|
||||||
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
|
NInputGroupLabel: typeof import('naive-ui')['NInputGroupLabel']
|
||||||
|
NModal: typeof import('naive-ui')['NModal']
|
||||||
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
|
|||||||
@@ -15,33 +15,72 @@ const { height } = useElementSize(elementRef.value)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NText v-if="!address" depth="3" italic> 未知 </NText>
|
<NText
|
||||||
<NFlex v-else ref="elementRef">
|
v-if="!address"
|
||||||
<NFlex vertical :size="5">
|
depth="3"
|
||||||
|
italic
|
||||||
|
>
|
||||||
|
未知
|
||||||
|
</NText>
|
||||||
|
<NFlex
|
||||||
|
v-else
|
||||||
|
ref="elementRef"
|
||||||
|
>
|
||||||
|
<NFlex
|
||||||
|
vertical
|
||||||
|
:size="5"
|
||||||
|
>
|
||||||
<NText v-if="size != 'small'">
|
<NText v-if="size != 'small'">
|
||||||
{{ address.province }}
|
{{ address.province }}
|
||||||
<NText depth="3"> 省 </NText>
|
<NText depth="3">
|
||||||
|
省
|
||||||
|
</NText>
|
||||||
{{ address.city }}
|
{{ address.city }}
|
||||||
<NText depth="3"> 市 </NText>
|
<NText depth="3">
|
||||||
|
市
|
||||||
|
</NText>
|
||||||
{{ address.district }}
|
{{ address.district }}
|
||||||
<NText depth="3"> 区 </NText>
|
<NText depth="3">
|
||||||
|
区
|
||||||
|
</NText>
|
||||||
{{ address.street }}
|
{{ address.street }}
|
||||||
</NText>
|
</NText>
|
||||||
<NText depth="3">
|
<NText depth="3">
|
||||||
<NFlex align="center">
|
<NFlex align="center">
|
||||||
<NTag size="tiny" type="info" :bordered="false"> 详细地址 </NTag>
|
<NTag
|
||||||
|
size="tiny"
|
||||||
|
type="info"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
详细地址
|
||||||
|
</NTag>
|
||||||
|
<NEllipsis :style="{ maxWidth: size == 'small' ? '120px' : '1000px' }">
|
||||||
{{ address.address }}
|
{{ address.address }}
|
||||||
|
</NEllipsis>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NText>
|
</NText>
|
||||||
<NText v-if="size != 'small'" depth="3">
|
<NText
|
||||||
|
v-if="size != 'small'"
|
||||||
|
depth="3"
|
||||||
|
>
|
||||||
<NFlex align="center">
|
<NFlex align="center">
|
||||||
<NTag size="tiny" type="info" :bordered="false"> 收货人 </NTag>
|
<NTag
|
||||||
|
size="tiny"
|
||||||
|
type="info"
|
||||||
|
:bordered="false"
|
||||||
|
>
|
||||||
|
收货人
|
||||||
|
</NTag>
|
||||||
<span> {{ address.phone }} {{ address.name }} </span>
|
<span> {{ address.phone }} {{ address.name }} </span>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NText>
|
</NText>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
<NFlex style="flex: 1" justify="end" align="center">
|
<NFlex
|
||||||
<slot name="actions"></slot>
|
style="flex: 1"
|
||||||
|
justify="end"
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<slot name="actions" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { NCard, NEllipsis, NEmpty, NFlex, NIcon, NImage, NTag, NText } from 'nai
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
goods: ResponsePointGoodModel | undefined;
|
goods: ResponsePointGoodModel | undefined;
|
||||||
contentStyle?: string | undefined;
|
contentStyle?: string | undefined;
|
||||||
|
size?: 'small' | 'default';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 默认封面图片
|
// 默认封面图片
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
import {
|
import {
|
||||||
GoodsTypes,
|
GoodsTypes,
|
||||||
PointOrderStatus,
|
PointOrderStatus,
|
||||||
ResponsePointGoodModel,
|
|
||||||
ResponsePointOrder2OwnerModel,
|
ResponsePointOrder2OwnerModel,
|
||||||
ResponsePointOrder2UserModel,
|
ResponsePointOrder2UserModel
|
||||||
} from '@/api/api-models'
|
} from '@/api/api-models'
|
||||||
import { QueryPostAPI } from '@/api/query'
|
import { QueryPostAPI } from '@/api/query'
|
||||||
import { POINT_API_URL } from '@/data/constants'
|
import { POINT_API_URL } from '@/data/constants'
|
||||||
@@ -12,10 +11,13 @@ import { Info24Filled } from '@vicons/fluent'
|
|||||||
import {
|
import {
|
||||||
DataTableColumns,
|
DataTableColumns,
|
||||||
DataTableRowKey,
|
DataTableRowKey,
|
||||||
|
NAlert,
|
||||||
NAutoComplete,
|
NAutoComplete,
|
||||||
NButton,
|
NButton,
|
||||||
|
NCard,
|
||||||
NDataTable,
|
NDataTable,
|
||||||
NDivider,
|
NDivider,
|
||||||
|
NEllipsis,
|
||||||
NEmpty,
|
NEmpty,
|
||||||
NFlex,
|
NFlex,
|
||||||
NIcon,
|
NIcon,
|
||||||
@@ -24,6 +26,7 @@ import {
|
|||||||
NInputGroupLabel,
|
NInputGroupLabel,
|
||||||
NModal,
|
NModal,
|
||||||
NScrollbar,
|
NScrollbar,
|
||||||
|
NSpace,
|
||||||
NStep,
|
NStep,
|
||||||
NSteps,
|
NSteps,
|
||||||
NTag,
|
NTag,
|
||||||
@@ -32,9 +35,6 @@ import {
|
|||||||
NTooltip,
|
NTooltip,
|
||||||
useDialog,
|
useDialog,
|
||||||
useMessage,
|
useMessage,
|
||||||
NCard,
|
|
||||||
NSpace,
|
|
||||||
NAlert,
|
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { computed, h, onMounted, ref, watch } from 'vue'
|
import { computed, h, onMounted, ref, watch } from 'vue'
|
||||||
import AddressDisplay from './AddressDisplay.vue'
|
import AddressDisplay from './AddressDisplay.vue'
|
||||||
@@ -45,10 +45,10 @@ type OrderType = ResponsePointOrder2UserModel | ResponsePointOrder2OwnerModel
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
order: ResponsePointOrder2UserModel[] | ResponsePointOrder2OwnerModel[]
|
order: ResponsePointOrder2UserModel[] | ResponsePointOrder2OwnerModel[]
|
||||||
type: 'user' | 'owner'
|
type: 'user' | 'owner'
|
||||||
goods?: ResponsePointGoodModel[]
|
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const emit = defineEmits(['selectedItem'])
|
const emit = defineEmits(['selectedItem'])
|
||||||
@@ -71,11 +71,7 @@ const orderAsOwner = computed(() => props.order as ResponsePointOrder2OwnerModel
|
|||||||
const currentGoods = computed(() => {
|
const currentGoods = computed(() => {
|
||||||
if (!orderDetail.value) return null
|
if (!orderDetail.value) return null
|
||||||
|
|
||||||
if (props.type === 'user') {
|
return orderDetail.value.goods
|
||||||
return (orderDetail.value as ResponsePointOrder2UserModel).goods
|
|
||||||
} else {
|
|
||||||
return props.goods?.find((g) => g.id === (orderDetail.value as ResponsePointOrder2OwnerModel).goodsId)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const expressOptions = computed(() => {
|
const expressOptions = computed(() => {
|
||||||
@@ -143,6 +139,7 @@ const orderColumn: DataTableColumns<OrderType> = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '订单号',
|
title: '订单号',
|
||||||
|
minWidth: 70,
|
||||||
key: 'id',
|
key: 'id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -173,11 +170,9 @@ const orderColumn: DataTableColumns<OrderType> = [
|
|||||||
{
|
{
|
||||||
title: '礼物名',
|
title: '礼物名',
|
||||||
key: 'giftName',
|
key: 'giftName',
|
||||||
|
minWidth: 150,
|
||||||
render: (row: OrderType) => {
|
render: (row: OrderType) => {
|
||||||
if (row.instanceOf === 'user') {
|
return row.goods?.name
|
||||||
return (row as ResponsePointOrder2UserModel).goods.name
|
|
||||||
}
|
|
||||||
return props.goods?.find((g) => g.id === row.goodsId)?.name || '未知礼物'
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -249,9 +244,7 @@ const orderColumn: DataTableColumns<OrderType> = [
|
|||||||
key: 'address',
|
key: 'address',
|
||||||
minWidth: 250,
|
minWidth: 250,
|
||||||
render: (row: OrderType) => {
|
render: (row: OrderType) => {
|
||||||
const goodsCollectUrl = row.instanceOf === 'user'
|
const goodsCollectUrl = row.goods.collectUrl
|
||||||
? (row as ResponsePointOrder2UserModel).goods.collectUrl
|
|
||||||
: props.goods?.find((g) => g.id === row.goodsId)?.collectUrl
|
|
||||||
|
|
||||||
if (row.type === GoodsTypes.Physical) {
|
if (row.type === GoodsTypes.Physical) {
|
||||||
return goodsCollectUrl
|
return goodsCollectUrl
|
||||||
@@ -262,7 +255,7 @@ const orderColumn: DataTableColumns<OrderType> = [
|
|||||||
text: true,
|
text: true,
|
||||||
type: 'info'
|
type: 'info'
|
||||||
}, () => h(NText, { italic: true }, () => '通过站外链接收集'))
|
}, () => h(NText, { italic: true }, () => '通过站外链接收集'))
|
||||||
: h(AddressDisplay, { address: row.address })
|
: h(AddressDisplay, { address: row.address, size: 'small' })
|
||||||
} else {
|
} else {
|
||||||
return h(NText, { depth: 3, italic: true }, () => '无需发货')
|
return h(NText, { depth: 3, italic: true }, () => '无需发货')
|
||||||
}
|
}
|
||||||
@@ -277,7 +270,7 @@ const orderColumn: DataTableColumns<OrderType> = [
|
|||||||
if (row.trackingNumber) {
|
if (row.trackingNumber) {
|
||||||
return h(NFlex, { align: 'center', gap: 8 }, () => [
|
return h(NFlex, { align: 'center', gap: 8 }, () => [
|
||||||
h(NTag, { size: 'tiny', bordered: false }, () => row.expressCompany),
|
h(NTag, { size: 'tiny', bordered: false }, () => row.expressCompany),
|
||||||
h(NText, { depth: 3 }, () => row.trackingNumber),
|
h(NEllipsis, { style: { maxWidth: '100px' } }, () => h(NText, { depth: 3 }, () => row.trackingNumber)),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
return h(NText, { depth: 3, italic: true }, () => '尚未发货')
|
return h(NText, { depth: 3, italic: true }, () => '尚未发货')
|
||||||
@@ -728,7 +721,10 @@ onMounted(() => {
|
|||||||
size="small"
|
size="small"
|
||||||
class="address-info-card"
|
class="address-info-card"
|
||||||
>
|
>
|
||||||
<AddressDisplay :address="orderDetail.address" />
|
<AddressDisplay
|
||||||
|
:address="orderDetail.address"
|
||||||
|
size="default"
|
||||||
|
/>
|
||||||
</NCard>
|
</NCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { QueryGetAPI } from '@/api/query'
|
import { QueryGetAPI } from '@/api/query'
|
||||||
import { BILI_AUTH_API_URL, CURRENT_HOST } from '@/data/constants'
|
import { BILI_AUTH_API_URL, CURRENT_HOST } from '@/data/constants'
|
||||||
import { useBiliAuth } from '@/store/useBiliAuth'
|
import { useBiliAuth } from '@/store/useBiliAuth'
|
||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage, useBreakpoints as useVueUseBreakpoints, breakpointsTailwind } from '@vueuse/core'
|
||||||
import {
|
import {
|
||||||
NAlert,
|
NAlert,
|
||||||
NButton,
|
NButton,
|
||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
NStep,
|
NStep,
|
||||||
NSteps,
|
NSteps,
|
||||||
NText,
|
NText,
|
||||||
useMessage
|
useMessage,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
@@ -30,6 +30,8 @@ type AuthStartModel = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const breakpoints = useVueUseBreakpoints(breakpointsTailwind)
|
||||||
|
const isSmallScreen = breakpoints.smaller('sm')
|
||||||
|
|
||||||
const guidKey = useStorage('Bili.Auth.Key', uuidv4())
|
const guidKey = useStorage('Bili.Auth.Key', uuidv4())
|
||||||
const currentToken = useStorage<string>('Bili.Auth.Selected', null)
|
const currentToken = useStorage<string>('Bili.Auth.Selected', null)
|
||||||
@@ -97,11 +99,15 @@ function checkTimeLeft() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function copyCode() {
|
function copyCode() {
|
||||||
if (navigator.clipboard) {
|
const textToCopy = currentStep.value === 2
|
||||||
navigator.clipboard.writeText(startModel.value?.code ?? '')
|
? `${CURRENT_HOST}bili-user?auth=${currentToken.value}`
|
||||||
message.success('已复制认证码到剪切板')
|
: startModel.value?.code ?? ''
|
||||||
|
|
||||||
|
if (navigator.clipboard && textToCopy) {
|
||||||
|
navigator.clipboard.writeText(textToCopy)
|
||||||
|
message.success(currentStep.value === 2 ? '已复制登陆链接到剪切板' : '已复制认证码到剪切板')
|
||||||
} else {
|
} else {
|
||||||
message.warning('当前环境不支持自动复制, 请手动选择并复制')
|
message.warning('无法复制内容, 请手动选择并复制')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,20 +125,25 @@ onMounted(async () => {
|
|||||||
<NFlex
|
<NFlex
|
||||||
justify="center"
|
justify="center"
|
||||||
align="center"
|
align="center"
|
||||||
style="height: 100vh"
|
style="min-height: 100vh; padding: 20px; box-sizing: border-box"
|
||||||
>
|
>
|
||||||
<NCard
|
<NCard
|
||||||
embedded
|
embedded
|
||||||
style="margin: 20px; max-width: 1100px"
|
style="width: 100%; max-width: 1000px"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
|
<NText style="font-size: 1.2em; font-weight: bold">
|
||||||
Bilibili 身份验证
|
Bilibili 身份验证
|
||||||
|
</NText>
|
||||||
</template>
|
</template>
|
||||||
<NFlex :wrap="false">
|
<NFlex
|
||||||
|
:wrap="false"
|
||||||
|
:vertical="isSmallScreen"
|
||||||
|
>
|
||||||
<NSteps
|
<NSteps
|
||||||
:current="currentStep + 1"
|
:current="currentStep + 1"
|
||||||
vertical
|
vertical
|
||||||
style="max-width: 300px"
|
style="min-width: 200px; max-width: 300px; margin-bottom: 20px"
|
||||||
>
|
>
|
||||||
<NStep
|
<NStep
|
||||||
title="准备认证"
|
title="准备认证"
|
||||||
@@ -147,30 +158,45 @@ onMounted(async () => {
|
|||||||
description="现在就已经通过了认证!"
|
description="现在就已经通过了认证!"
|
||||||
/>
|
/>
|
||||||
</NSteps>
|
</NSteps>
|
||||||
|
<div style="flex-grow: 1; padding-left: 20px; border-left: 1px solid var(--n-border-color); min-width: 0;">
|
||||||
<template v-if="currentStep == 1">
|
<template v-if="currentStep == 1">
|
||||||
<NSpace
|
<NFlex
|
||||||
vertical
|
vertical
|
||||||
justify="center"
|
justify="center"
|
||||||
align="center"
|
align="center"
|
||||||
style="width: 100%"
|
style="width: 100%; height: 100%; padding-top: 20px; min-height: 250px;"
|
||||||
>
|
>
|
||||||
<template v-if="!timeOut">
|
<template v-if="!timeOut">
|
||||||
<NSpin />
|
<NSpin size="large" />
|
||||||
<span> 剩余 <NCountdown :duration="timeLeft" /> </span>
|
<NText style="margin-top: 15px; font-size: 1.1em;">
|
||||||
<NInputGroup>
|
剩余时间:<NCountdown :duration="timeLeft" />
|
||||||
|
</NText>
|
||||||
|
<NText
|
||||||
|
depth="3"
|
||||||
|
style="margin-top: 20px;"
|
||||||
|
>
|
||||||
|
请复制下方的认证码,并前往指定直播间发送:
|
||||||
|
</NText>
|
||||||
|
<NInputGroup style="margin-top: 10px; max-width: 300px;">
|
||||||
<NInput
|
<NInput
|
||||||
:value="startModel?.code"
|
:value="startModel?.code"
|
||||||
:allow-input="() => false"
|
readonly
|
||||||
|
placeholder="认证码"
|
||||||
|
style="text-align: center; font-size: 1.2em; letter-spacing: 2px;"
|
||||||
/>
|
/>
|
||||||
<NButton @click="copyCode">
|
<NButton
|
||||||
复制认证码
|
type="primary"
|
||||||
|
@click="copyCode"
|
||||||
|
>
|
||||||
|
复制
|
||||||
</NButton>
|
</NButton>
|
||||||
</NInputGroup>
|
</NInputGroup>
|
||||||
<NButton
|
<NButton
|
||||||
type="primary"
|
type="info"
|
||||||
tag="a"
|
tag="a"
|
||||||
:href="'https://live.bilibili.com/' + startModel?.targetRoomId"
|
:href="'https://live.bilibili.com/' + startModel?.targetRoomId"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
style="margin-top: 20px"
|
||||||
>
|
>
|
||||||
前往直播间
|
前往直播间
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -178,10 +204,13 @@ onMounted(async () => {
|
|||||||
<NAlert
|
<NAlert
|
||||||
v-else
|
v-else
|
||||||
type="error"
|
type="error"
|
||||||
|
title="认证超时"
|
||||||
|
style="width: 100%; max-width: 400px;"
|
||||||
>
|
>
|
||||||
认证超时
|
<NFlex justify="center">
|
||||||
<NButton
|
<NButton
|
||||||
type="error"
|
type="error"
|
||||||
|
style="margin-top: 10px"
|
||||||
@click="
|
@click="
|
||||||
() => {
|
() => {
|
||||||
currentStep = 0
|
currentStep = 0
|
||||||
@@ -189,17 +218,17 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
重新开始
|
重新开始认证
|
||||||
</NButton>
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
</NAlert>
|
</NAlert>
|
||||||
</NSpace>
|
</NFlex>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="currentStep == 0">
|
<template v-else-if="currentStep == 0">
|
||||||
<NSpace
|
<NSpace
|
||||||
vertical
|
vertical
|
||||||
justify="center"
|
align="stretch"
|
||||||
align="center"
|
style="width: 100%; padding-top: 10px"
|
||||||
style="width: 100%"
|
|
||||||
>
|
>
|
||||||
<NAlert type="info">
|
<NAlert type="info">
|
||||||
<NText>
|
<NText>
|
||||||
@@ -220,12 +249,10 @@ onMounted(async () => {
|
|||||||
在指定的直播间直播间内发送给出的验证码
|
在指定的直播间直播间内发送给出的验证码
|
||||||
</NText>
|
</NText>
|
||||||
</NAlert>
|
</NAlert>
|
||||||
<NText
|
<NFlex
|
||||||
depth="3"
|
justify="center"
|
||||||
style="font-size: 15px"
|
style="margin-top: 20px"
|
||||||
>
|
>
|
||||||
准备好了吗?
|
|
||||||
</NText>
|
|
||||||
<NButton
|
<NButton
|
||||||
size="large"
|
size="large"
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -233,36 +260,49 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
开始认证
|
开始认证
|
||||||
</NButton>
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="currentStep == 2">
|
<template v-else-if="currentStep == 2">
|
||||||
<NFlex
|
<NSpace
|
||||||
justify="center"
|
|
||||||
align="center"
|
|
||||||
vertical
|
vertical
|
||||||
style="width: 100%"
|
align="stretch"
|
||||||
|
style="width: 100%; padding-top: 10px"
|
||||||
|
>
|
||||||
|
<NAlert
|
||||||
|
type="success"
|
||||||
|
title="验证成功!"
|
||||||
|
style="margin-bottom: 15px"
|
||||||
>
|
>
|
||||||
<NAlert type="success">
|
|
||||||
你已完成验证! 请妥善保存你的登陆链接, 请勿让其他人获取. 丢失后可以再次通过认证流程获得.
|
你已完成验证! 请妥善保存你的登陆链接, 请勿让其他人获取. 丢失后可以再次通过认证流程获得.
|
||||||
<br>
|
<br>
|
||||||
要在其他地方登陆, 或者需要重新登陆的话把这个链接复制到浏览器地址栏打开即可
|
要在其他地方登陆, 或者需要重新登陆的话把这个链接复制到浏览器地址栏打开即可
|
||||||
</NAlert>
|
</NAlert>
|
||||||
<NText> 你的登陆链接为: </NText>
|
<NText strong>
|
||||||
<NInputGroup>
|
你的登陆链接为:
|
||||||
|
</NText>
|
||||||
<NInput
|
<NInput
|
||||||
:value="`${CURRENT_HOST}bili-user?auth=${currentToken}`"
|
:value="`${CURRENT_HOST}bili-user?auth=${currentToken}`"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:allow-input="() => false"
|
readonly
|
||||||
|
style="margin-top: 5px"
|
||||||
/>
|
/>
|
||||||
|
<NFlex
|
||||||
|
justify="end"
|
||||||
|
style="margin-top: 10px"
|
||||||
|
>
|
||||||
<NButton
|
<NButton
|
||||||
type="info"
|
type="primary"
|
||||||
style="height: 100%"
|
|
||||||
@click="copyCode"
|
@click="copyCode"
|
||||||
>
|
>
|
||||||
复制登陆链接
|
复制登陆链接
|
||||||
</NButton>
|
</NButton>
|
||||||
</NInputGroup>
|
</NFlex>
|
||||||
<NFlex>
|
<NFlex
|
||||||
|
justify="center"
|
||||||
|
style="margin-top: 20px"
|
||||||
|
:wrap="true"
|
||||||
|
>
|
||||||
<NButton
|
<NButton
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="$router.push({ name: 'bili-user' })"
|
@click="$router.push({ name: 'bili-user' })"
|
||||||
@@ -271,6 +311,7 @@ onMounted(async () => {
|
|||||||
</NButton>
|
</NButton>
|
||||||
<NPopconfirm
|
<NPopconfirm
|
||||||
positive-text="继续"
|
positive-text="继续"
|
||||||
|
negative-text="取消"
|
||||||
@positive-click="
|
@positive-click="
|
||||||
() => {
|
() => {
|
||||||
currentStep = 0
|
currentStep = 0
|
||||||
@@ -288,8 +329,9 @@ onMounted(async () => {
|
|||||||
这将会登出当前已认证的账号, 请先在认证其他账号前保存你的登陆链接
|
这将会登出当前已认证的账号, 请先在认证其他账号前保存你的登陆链接
|
||||||
</NPopconfirm>
|
</NPopconfirm>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NFlex>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
</div>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NCard>
|
</NCard>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAccount } from '@/api/account'
|
import { useAccount } from '@/api/account'
|
||||||
import { GoodsTypes, PointOrderStatus, ResponsePointGoodModel, ResponsePointOrder2OwnerModel } from '@/api/api-models'
|
import { GoodsTypes, PointOrderStatus, ResponsePointGoodModel, ResponsePointOrder2OwnerModel, ResponsePointUserModel } from '@/api/api-models'
|
||||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||||
import PointOrderCard from '@/components/manage/PointOrderCard.vue'
|
import PointOrderCard from '@/components/manage/PointOrderCard.vue'
|
||||||
import { POINT_API_URL } from '@/data/constants'
|
import { POINT_API_URL } from '@/data/constants'
|
||||||
@@ -17,12 +17,16 @@ import {
|
|||||||
NDivider,
|
NDivider,
|
||||||
NEmpty,
|
NEmpty,
|
||||||
NFlex,
|
NFlex,
|
||||||
|
NModal,
|
||||||
NPopconfirm,
|
NPopconfirm,
|
||||||
NSelect,
|
NSelect,
|
||||||
|
NSpace,
|
||||||
NSpin,
|
NSpin,
|
||||||
|
NText,
|
||||||
useMessage,
|
useMessage,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import PointUserDetailCard from './PointUserDetailCard.vue'
|
||||||
|
|
||||||
// 订单筛选设置类型定义
|
// 订单筛选设置类型定义
|
||||||
type OrderFilterSettings = {
|
type OrderFilterSettings = {
|
||||||
@@ -62,6 +66,8 @@ const filteredOrders = computed(() => {
|
|||||||
|
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const selectedItem = ref<DataTableRowKey[]>()
|
const selectedItem = ref<DataTableRowKey[]>()
|
||||||
|
const targetStatus = ref<PointOrderStatus>()
|
||||||
|
const showStatusModal = ref(false)
|
||||||
|
|
||||||
// 获取所有订单
|
// 获取所有订单
|
||||||
async function getOrders() {
|
async function getOrders() {
|
||||||
@@ -104,6 +110,54 @@ async function deleteOrder() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开状态更新模态框
|
||||||
|
function openStatusUpdateModal() {
|
||||||
|
if (!selectedItem.value?.length) {
|
||||||
|
message.warning('请选择要更新的订单')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showStatusModal.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新订单状态
|
||||||
|
async function batchUpdateOrderStatus() {
|
||||||
|
if (!selectedItem.value?.length) {
|
||||||
|
message.warning('请选择要更新的订单')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetStatus.value === undefined) {
|
||||||
|
message.warning('请选择目标状态')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requestData = {
|
||||||
|
orderIds: selectedItem.value,
|
||||||
|
status: targetStatus.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await QueryPostAPI<number[]>(POINT_API_URL + 'batch-update-order-status', requestData)
|
||||||
|
if (data.code == 200) {
|
||||||
|
message.success('更新成功')
|
||||||
|
// 更新本地订单状态
|
||||||
|
orders.value.forEach(order => {
|
||||||
|
if (data.data.includes(order.id)) {
|
||||||
|
order.status = targetStatus.value as PointOrderStatus
|
||||||
|
order.updateAt = Date.now()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
targetStatus.value = undefined
|
||||||
|
showStatusModal.value = false
|
||||||
|
} else {
|
||||||
|
message.error('更新失败: ' + data.message)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
message.error('更新失败: ' + err)
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 订单状态文本映射
|
// 订单状态文本映射
|
||||||
const statusText = {
|
const statusText = {
|
||||||
[PointOrderStatus.Completed]: '已完成',
|
[PointOrderStatus.Completed]: '已完成',
|
||||||
@@ -116,7 +170,7 @@ function exportData() {
|
|||||||
try {
|
try {
|
||||||
const text = objectsToCSV(
|
const text = objectsToCSV(
|
||||||
filteredOrders.value.map((s) => {
|
filteredOrders.value.map((s) => {
|
||||||
const gift = props.goods.find((g) => g.id == s.goodsId)
|
const gift = s.goods
|
||||||
return {
|
return {
|
||||||
订单号: s.id,
|
订单号: s.id,
|
||||||
订单类型: s.type == GoodsTypes.Physical ? '实体' : '虚拟',
|
订单类型: s.type == GoodsTypes.Physical ? '实体' : '虚拟',
|
||||||
@@ -237,8 +291,7 @@ onMounted(async () => {
|
|||||||
/>
|
/>
|
||||||
<NSelect
|
<NSelect
|
||||||
v-model:value="filterSettings.customer"
|
v-model:value="filterSettings.customer"
|
||||||
:options="
|
:options="new List(orders)
|
||||||
new List(orders)
|
|
||||||
.DistinctBy((s) => s.customer.userId)
|
.DistinctBy((s) => s.customer.userId)
|
||||||
.Select((s) => ({ label: s.customer.name, value: s.customer.userId }))
|
.Select((s) => ({ label: s.customer.name, value: s.customer.userId }))
|
||||||
.ToArray()
|
.ToArray()
|
||||||
@@ -247,15 +300,17 @@ onMounted(async () => {
|
|||||||
clearable
|
clearable
|
||||||
style="min-width: 120px; max-width: 150px"
|
style="min-width: 120px; max-width: 150px"
|
||||||
/>
|
/>
|
||||||
<NCheckbox
|
<NCheckbox v-model:checked="filterSettings.onlyRequireShippingInfo">
|
||||||
v-model:checked="filterSettings.onlyRequireShippingInfo"
|
|
||||||
>
|
|
||||||
仅包含未填写快递单号的订单
|
仅包含未填写快递单号的订单
|
||||||
</NCheckbox>
|
</NCheckbox>
|
||||||
</NFlex>
|
</NFlex>
|
||||||
</NCard>
|
</NCard>
|
||||||
|
|
||||||
<NDivider title-placement="left">
|
<NDivider title-placement="left">
|
||||||
|
<NFlex
|
||||||
|
:gap="8"
|
||||||
|
:wrap="false"
|
||||||
|
>
|
||||||
<NPopconfirm @positive-click="deleteOrder">
|
<NPopconfirm @positive-click="deleteOrder">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton
|
<NButton
|
||||||
@@ -268,15 +323,65 @@ onMounted(async () => {
|
|||||||
</template>
|
</template>
|
||||||
确定删除吗?
|
确定删除吗?
|
||||||
</NPopconfirm>
|
</NPopconfirm>
|
||||||
|
|
||||||
|
<NPopconfirm @positive-click="openStatusUpdateModal">
|
||||||
|
<template #trigger>
|
||||||
|
<NButton
|
||||||
|
size="tiny"
|
||||||
|
type="info"
|
||||||
|
:disabled="!selectedItem?.length"
|
||||||
|
>
|
||||||
|
批量更新状态
|
||||||
|
</NButton>
|
||||||
|
</template>
|
||||||
|
确定要更新选中订单的状态吗?
|
||||||
|
</NPopconfirm>
|
||||||
|
</NFlex>
|
||||||
</NDivider>
|
</NDivider>
|
||||||
|
|
||||||
<!-- 订单列表 -->
|
<!-- 订单列表 -->
|
||||||
<PointOrderCard
|
<PointOrderCard
|
||||||
:order="filteredOrders"
|
:order="filteredOrders"
|
||||||
:goods="goods"
|
|
||||||
type="owner"
|
type="owner"
|
||||||
@selected-item="(items) => (selectedItem = items)"
|
@selected-item="(items) => (selectedItem = items)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 状态选择模态框 -->
|
||||||
|
<NModal
|
||||||
|
v-model:show="showStatusModal"
|
||||||
|
title="选择目标状态"
|
||||||
|
preset="card"
|
||||||
|
style="max-width: 400px"
|
||||||
|
>
|
||||||
|
<NSpace vertical>
|
||||||
|
<NText>请选择您想要将订单更新为的状态</NText>
|
||||||
|
<NSelect
|
||||||
|
v-model:value="targetStatus"
|
||||||
|
:options="[
|
||||||
|
{ label: '已完成', value: PointOrderStatus.Completed },
|
||||||
|
{ label: '等待发货', value: PointOrderStatus.Pending },
|
||||||
|
{ label: '已发货', value: PointOrderStatus.Shipped },
|
||||||
|
]"
|
||||||
|
placeholder="选择状态"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
<NFlex
|
||||||
|
justify="end"
|
||||||
|
:gap="12"
|
||||||
|
>
|
||||||
|
<NButton @click="showStatusModal = false">
|
||||||
|
取消
|
||||||
|
</NButton>
|
||||||
|
<NButton
|
||||||
|
type="primary"
|
||||||
|
:disabled="targetStatus === undefined"
|
||||||
|
@click="batchUpdateOrderStatus"
|
||||||
|
>
|
||||||
|
确认更新
|
||||||
|
</NButton>
|
||||||
|
</NFlex>
|
||||||
|
</NSpace>
|
||||||
|
</NModal>
|
||||||
</template>
|
</template>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user