683 lines
22 KiB
Vue
683 lines
22 KiB
Vue
<!-- Author: fruit.com.cn -->
|
||
|
||
<script setup>
|
||
import { onMounted, reactive, ref } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import PageHeading from '@/views/components/PageHeading.vue'
|
||
import { useRbac } from '@/stores/rbac'
|
||
import { dateCell } from '@/utils/format'
|
||
import {
|
||
adjustCoinsApi,
|
||
compensateOrderApi,
|
||
grantEntitlementApi,
|
||
listOrderEventsApi,
|
||
listWalletLedgerApi,
|
||
pageEntitlementsApi,
|
||
pageOrdersApi,
|
||
pageReconcileApi,
|
||
refundOrderApi,
|
||
revokeEntitlementApi,
|
||
runReconcileApi
|
||
} from '@/api/admin/commerce'
|
||
|
||
const { can } = useRbac()
|
||
const canOrderUpdate = can('order:update')
|
||
const canEntitlementUpdate = can('entitlement:update')
|
||
const canWalletUpdate = can('wallet:update')
|
||
const canReconcile = can('reconcile:run')
|
||
|
||
const ORDER_STATUS = [
|
||
{ value: 'CREATED', label: '待支付', tag: 'info' },
|
||
{ value: 'PAID', label: '已支付', tag: 'warning' },
|
||
{ value: 'DELIVERED', label: '已交付', tag: 'success' },
|
||
{ value: 'REFUNDED', label: '已退款', tag: 'danger' },
|
||
{ value: 'CLOSED', label: '已关闭', tag: 'info' }
|
||
]
|
||
const ENTITLEMENT_STATUS = [
|
||
{ value: 'ACTIVE', label: '有效', tag: 'success' },
|
||
{ value: 'REVOKED', label: '已回收', tag: 'danger' },
|
||
{ value: 'EXPIRED', label: '已过期', tag: 'info' }
|
||
]
|
||
|
||
function meta(list, value) {
|
||
return list.find((item) => item.value === value) || { label: value || '-', tag: 'info' }
|
||
}
|
||
|
||
const activeTab = ref('orders')
|
||
|
||
const orders = reactive({
|
||
rows: [],
|
||
total: 0,
|
||
loading: false,
|
||
page: 1,
|
||
size: 10,
|
||
status: undefined,
|
||
orderNo: '',
|
||
userId: undefined
|
||
})
|
||
async function loadOrders() {
|
||
orders.loading = true
|
||
try {
|
||
const res = await pageOrdersApi({
|
||
pageIndex: orders.page,
|
||
pageSize: orders.size,
|
||
status: orders.status || undefined,
|
||
orderNo: orders.orderNo.trim() || undefined,
|
||
userId: orders.userId || undefined
|
||
})
|
||
orders.rows = res.data?.list || []
|
||
orders.total = res.data?.total || 0
|
||
} finally {
|
||
orders.loading = false
|
||
}
|
||
}
|
||
function queryOrders() {
|
||
orders.page = 1
|
||
loadOrders()
|
||
}
|
||
async function compensate(row) {
|
||
try {
|
||
await ElMessageBox.confirm(
|
||
`对订单 ${row.orderNo} 执行补发?已交付的订单会幂等返回。`,
|
||
'补发订单',
|
||
{
|
||
confirmButtonText: '确认补发',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}
|
||
)
|
||
} catch {
|
||
return
|
||
}
|
||
await compensateOrderApi(row.orderNo)
|
||
ElMessage.success('补发完成')
|
||
await loadOrders()
|
||
}
|
||
async function refund(row) {
|
||
let reason = ''
|
||
try {
|
||
const { value } = await ElMessageBox.prompt(
|
||
'退款会回收权益并扣回金币,请填写原因',
|
||
'订单退款',
|
||
{
|
||
confirmButtonText: '确认退款',
|
||
cancelButtonText: '取消',
|
||
confirmButtonClass: 'el-button--danger',
|
||
inputValidator: (val) => (val && val.trim() ? true : '退款原因不能为空')
|
||
}
|
||
)
|
||
reason = value
|
||
} catch {
|
||
return
|
||
}
|
||
await refundOrderApi(row.orderNo, reason.trim())
|
||
ElMessage.success('已退款并回收权益')
|
||
await loadOrders()
|
||
}
|
||
|
||
const eventsVisible = ref(false)
|
||
const eventsLoading = ref(false)
|
||
const events = ref([])
|
||
const eventsOrderNo = ref('')
|
||
async function openEvents(row) {
|
||
eventsVisible.value = true
|
||
eventsOrderNo.value = row.orderNo
|
||
eventsLoading.value = true
|
||
events.value = []
|
||
try {
|
||
events.value = (await listOrderEventsApi(row.orderNo)).data || []
|
||
} finally {
|
||
eventsLoading.value = false
|
||
}
|
||
}
|
||
|
||
const entitlements = reactive({
|
||
rows: [],
|
||
total: 0,
|
||
loading: false,
|
||
page: 1,
|
||
size: 10,
|
||
userId: undefined,
|
||
status: 'ACTIVE'
|
||
})
|
||
async function loadEntitlements() {
|
||
entitlements.loading = true
|
||
try {
|
||
const res = await pageEntitlementsApi({
|
||
pageIndex: entitlements.page,
|
||
pageSize: entitlements.size,
|
||
userId: entitlements.userId || undefined,
|
||
status: entitlements.status || undefined
|
||
})
|
||
entitlements.rows = res.data?.list || []
|
||
entitlements.total = res.data?.total || 0
|
||
} finally {
|
||
entitlements.loading = false
|
||
}
|
||
}
|
||
function queryEntitlements() {
|
||
entitlements.page = 1
|
||
loadEntitlements()
|
||
}
|
||
async function revokeEntitlement(row) {
|
||
try {
|
||
await ElMessageBox.confirm(
|
||
'回收后该用户立即失去这一集的播放权限(已下载的授权不受影响),确认?',
|
||
'回收权益',
|
||
{
|
||
confirmButtonText: '确认回收',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
confirmButtonClass: 'el-button--danger'
|
||
}
|
||
)
|
||
} catch {
|
||
return
|
||
}
|
||
await revokeEntitlementApi(row.id, '后台回收')
|
||
ElMessage.success('权益已回收')
|
||
await loadEntitlements()
|
||
}
|
||
const grantVisible = ref(false)
|
||
const grantSaving = ref(false)
|
||
const grantForm = reactive({
|
||
userId: undefined,
|
||
dramaId: undefined,
|
||
episodeId: undefined,
|
||
type: 'EPISODE',
|
||
reason: ''
|
||
})
|
||
function openGrant() {
|
||
Object.assign(grantForm, {
|
||
userId: undefined,
|
||
dramaId: undefined,
|
||
episodeId: undefined,
|
||
type: 'EPISODE',
|
||
reason: ''
|
||
})
|
||
grantVisible.value = true
|
||
}
|
||
async function confirmGrant() {
|
||
if (!grantForm.userId || !grantForm.dramaId) return ElMessage.warning('请填写用户 ID 与短剧 ID')
|
||
grantSaving.value = true
|
||
try {
|
||
await grantEntitlementApi({
|
||
userId: grantForm.userId,
|
||
dramaId: grantForm.dramaId,
|
||
episodeId: grantForm.episodeId || 0,
|
||
type: grantForm.type
|
||
})
|
||
ElMessage.success('权益已补发')
|
||
grantVisible.value = false
|
||
await loadEntitlements()
|
||
} finally {
|
||
grantSaving.value = false
|
||
}
|
||
}
|
||
|
||
const ledger = reactive({ rows: [], loading: false, userId: undefined })
|
||
async function loadLedger() {
|
||
if (!ledger.userId) return ElMessage.warning('请先填写用户 ID')
|
||
ledger.loading = true
|
||
try {
|
||
ledger.rows = (await listWalletLedgerApi(ledger.userId, 50)).data || []
|
||
} finally {
|
||
ledger.loading = false
|
||
}
|
||
}
|
||
const coinVisible = ref(false)
|
||
const coinSaving = ref(false)
|
||
const coinForm = reactive({ userId: undefined, amount: 100, remark: '', idempotentKey: '' })
|
||
function openCoin() {
|
||
Object.assign(coinForm, { userId: ledger.userId, amount: 100, remark: '', idempotentKey: '' })
|
||
coinVisible.value = true
|
||
}
|
||
async function confirmCoin() {
|
||
if (!coinForm.userId || !coinForm.amount) return ElMessage.warning('请填写用户 ID 与变动金额')
|
||
coinSaving.value = true
|
||
try {
|
||
await adjustCoinsApi({
|
||
userId: coinForm.userId,
|
||
amount: coinForm.amount,
|
||
remark: coinForm.remark.trim() || '人工调整',
|
||
idempotentKey: coinForm.idempotentKey.trim() || undefined
|
||
})
|
||
ElMessage.success('已入流水,重复提交同一幂等键不会重复加币')
|
||
coinVisible.value = false
|
||
await loadLedger()
|
||
} finally {
|
||
coinSaving.value = false
|
||
}
|
||
}
|
||
|
||
const reconcile = reactive({ rows: [], total: 0, loading: false, page: 1, size: 10 })
|
||
async function loadReconcile() {
|
||
reconcile.loading = true
|
||
try {
|
||
const res = await pageReconcileApi({ pageIndex: reconcile.page, pageSize: reconcile.size })
|
||
reconcile.rows = res.data?.list || []
|
||
reconcile.total = res.data?.total || 0
|
||
} finally {
|
||
reconcile.loading = false
|
||
}
|
||
}
|
||
async function runReconcile() {
|
||
try {
|
||
await ElMessageBox.confirm(
|
||
'默认对账前一天;商店未接入时差异属预期,接入后必须归零。',
|
||
'手动对账',
|
||
{
|
||
confirmButtonText: '开始对账',
|
||
cancelButtonText: '取消'
|
||
}
|
||
)
|
||
} catch {
|
||
return
|
||
}
|
||
const res = await runReconcileApi({})
|
||
const data = res.data
|
||
ElMessage.success(`对账完成:差异 ${data?.diffCount ?? 0} 笔`)
|
||
await loadReconcile()
|
||
}
|
||
|
||
const tabLoaded = {}
|
||
onMounted(() => {
|
||
loadOrders()
|
||
tabLoaded.orders = true
|
||
})
|
||
function onTabChange(name) {
|
||
if (tabLoaded[name]) return
|
||
tabLoaded[name] = true
|
||
if (name === 'entitlements') loadEntitlements()
|
||
if (name === 'reconcile') loadReconcile()
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<PageHeading
|
||
eyebrow="订单与权益"
|
||
title="订单管理"
|
||
description="订单补发与退款、权益回收与补发、金币流水与对账。"
|
||
/>
|
||
|
||
<section class="panel">
|
||
<el-tabs v-model="activeTab" @tab-change="onTabChange">
|
||
<el-tab-pane label="订单" name="orders">
|
||
<div class="console-toolbar">
|
||
<el-select
|
||
v-model="orders.status"
|
||
class="console-select"
|
||
clearable
|
||
placeholder="全部状态"
|
||
@change="queryOrders"
|
||
>
|
||
<el-option
|
||
v-for="item in ORDER_STATUS"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
<el-input
|
||
v-model="orders.orderNo"
|
||
class="console-keyword"
|
||
clearable
|
||
placeholder="订单号"
|
||
@keyup.enter="queryOrders"
|
||
/>
|
||
<el-input
|
||
v-model="orders.userId"
|
||
class="console-user"
|
||
clearable
|
||
placeholder="用户ID"
|
||
@keyup.enter="queryOrders"
|
||
/>
|
||
<el-button type="primary" @click="queryOrders">查询</el-button>
|
||
<span class="console-count">共 {{ orders.total }} 笔订单</span>
|
||
</div>
|
||
<el-table
|
||
v-loading="orders.loading"
|
||
:data="orders.rows"
|
||
row-key="id"
|
||
border
|
||
class="drama-el-table"
|
||
empty-text="没有符合条件的订单"
|
||
>
|
||
<el-table-column prop="orderNo" label="订单号" min-width="200" show-overflow-tooltip />
|
||
<el-table-column prop="userId" label="用户ID" width="90" />
|
||
<el-table-column prop="productName" label="商品" min-width="140" show-overflow-tooltip />
|
||
<el-table-column prop="platform" label="渠道" width="90" />
|
||
<el-table-column prop="amount" label="金额" width="100" />
|
||
<el-table-column prop="coinAmount" label="金币" width="90" />
|
||
<el-table-column label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-tag :type="meta(ORDER_STATUS, row.status).tag" effect="light">{{
|
||
meta(ORDER_STATUS, row.status).label
|
||
}}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="createdAt"
|
||
label="创建时间"
|
||
min-width="165"
|
||
show-overflow-tooltip
|
||
:formatter="dateCell"
|
||
/>
|
||
<el-table-column label="操作" width="230" fixed="right">
|
||
<template #default="{ row }">
|
||
<div class="table-actions">
|
||
<el-button size="small" @click="openEvents(row)">流水</el-button>
|
||
<el-button
|
||
v-if="canOrderUpdate && row.status === 'PAID'"
|
||
type="primary"
|
||
size="small"
|
||
@click="compensate(row)"
|
||
>补发</el-button
|
||
>
|
||
<el-button
|
||
v-if="canOrderUpdate && (row.status === 'PAID' || row.status === 'DELIVERED')"
|
||
type="danger"
|
||
size="small"
|
||
@click="refund(row)"
|
||
>退款</el-button
|
||
>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<div class="pagination">
|
||
<el-pagination
|
||
v-model:current-page="orders.page"
|
||
v-model:page-size="orders.size"
|
||
:page-sizes="[10, 20, 50]"
|
||
:total="orders.total"
|
||
layout="total, prev, pager, next, sizes"
|
||
background
|
||
@current-change="loadOrders"
|
||
@size-change="queryOrders"
|
||
/>
|
||
</div>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="权益" name="entitlements">
|
||
<div class="console-toolbar">
|
||
<el-input
|
||
v-model="entitlements.userId"
|
||
class="console-user"
|
||
clearable
|
||
placeholder="用户ID"
|
||
@keyup.enter="queryEntitlements"
|
||
/>
|
||
<el-select
|
||
v-model="entitlements.status"
|
||
class="console-select"
|
||
clearable
|
||
placeholder="全部状态"
|
||
@change="queryEntitlements"
|
||
>
|
||
<el-option
|
||
v-for="item in ENTITLEMENT_STATUS"
|
||
:key="item.value"
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-select>
|
||
<el-button type="primary" @click="queryEntitlements">查询</el-button>
|
||
<el-button v-if="canEntitlementUpdate" type="primary" @click="openGrant"
|
||
>人工补发权益</el-button
|
||
>
|
||
<span class="console-count">共 {{ entitlements.total }} 条权益</span>
|
||
</div>
|
||
<el-table
|
||
v-loading="entitlements.loading"
|
||
:data="entitlements.rows"
|
||
row-key="id"
|
||
border
|
||
class="drama-el-table"
|
||
empty-text="没有符合条件的权益"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80" />
|
||
<el-table-column prop="userId" label="用户ID" width="90" />
|
||
<el-table-column prop="dramaId" label="短剧ID" width="90" />
|
||
<el-table-column prop="episodeId" label="剧集ID" width="90" />
|
||
<el-table-column prop="type" label="类型" width="100" />
|
||
<el-table-column prop="source" label="来源" width="100" />
|
||
<el-table-column prop="orderNo" label="关联订单" min-width="160" show-overflow-tooltip />
|
||
<el-table-column label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-tag :type="meta(ENTITLEMENT_STATUS, row.status).tag" effect="light">{{
|
||
meta(ENTITLEMENT_STATUS, row.status).label
|
||
}}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
prop="startAt"
|
||
label="生效时间"
|
||
min-width="165"
|
||
show-overflow-tooltip
|
||
:formatter="dateCell"
|
||
/>
|
||
<el-table-column label="操作" width="130" fixed="right">
|
||
<template #default="{ row }">
|
||
<div class="table-actions">
|
||
<el-button
|
||
v-if="canEntitlementUpdate && row.status === 'ACTIVE'"
|
||
type="danger"
|
||
size="small"
|
||
@click="revokeEntitlement(row)"
|
||
>回收</el-button
|
||
>
|
||
<span v-else class="console-muted">—</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<div class="pagination">
|
||
<el-pagination
|
||
v-model:current-page="entitlements.page"
|
||
v-model:page-size="entitlements.size"
|
||
:page-sizes="[10, 20, 50]"
|
||
:total="entitlements.total"
|
||
layout="total, prev, pager, next, sizes"
|
||
background
|
||
@current-change="loadEntitlements"
|
||
@size-change="queryEntitlements"
|
||
/>
|
||
</div>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="金币流水" name="ledger">
|
||
<div class="console-toolbar">
|
||
<el-input
|
||
v-model="ledger.userId"
|
||
class="console-user"
|
||
clearable
|
||
placeholder="用户ID"
|
||
@keyup.enter="loadLedger"
|
||
/>
|
||
<el-button type="primary" @click="loadLedger">查询流水</el-button>
|
||
<el-button v-if="canWalletUpdate" type="primary" @click="openCoin">人工补币</el-button>
|
||
<span class="console-count">{{
|
||
ledger.rows.length ? `最近 ${ledger.rows.length} 条` : '按用户查询'
|
||
}}</span>
|
||
</div>
|
||
<el-table
|
||
v-loading="ledger.loading"
|
||
:data="ledger.rows"
|
||
row-key="id"
|
||
border
|
||
class="drama-el-table"
|
||
empty-text="输入用户 ID 后查询金币流水"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80" />
|
||
<el-table-column label="变动" width="110">
|
||
<template #default="{ row }">
|
||
<span :class="row.changeAmount >= 0 ? 'console-credit' : 'console-debit'">
|
||
{{ row.changeAmount > 0 ? '+' : '' }}{{ row.changeAmount }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="balanceAfter" label="变动后余额" width="120" />
|
||
<el-table-column prop="bizType" label="业务类型" width="120" />
|
||
<el-table-column prop="bizId" label="业务单号" min-width="160" show-overflow-tooltip />
|
||
<el-table-column prop="remark" label="备注" min-width="180" show-overflow-tooltip />
|
||
<el-table-column prop="operatorId" label="操作人" width="90" />
|
||
<el-table-column
|
||
prop="createdAt"
|
||
label="时间"
|
||
min-width="165"
|
||
show-overflow-tooltip
|
||
:formatter="dateCell"
|
||
/>
|
||
</el-table>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="对账" name="reconcile">
|
||
<div class="console-toolbar">
|
||
<el-button v-if="canReconcile" type="primary" @click="runReconcile">手动对账</el-button>
|
||
<el-button @click="loadReconcile">刷新</el-button>
|
||
<span class="console-count">共 {{ reconcile.total }} 次对账</span>
|
||
</div>
|
||
<el-alert
|
||
class="console-hint"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
title="默认核对前一天:本地订单与商店票据逐笔比对,差异必须归零;商店未接入前差异属预期。"
|
||
/>
|
||
<el-table
|
||
v-loading="reconcile.loading"
|
||
:data="reconcile.rows"
|
||
row-key="id"
|
||
border
|
||
class="drama-el-table"
|
||
empty-text="还没有对账记录"
|
||
>
|
||
<el-table-column prop="bizDate" label="对账日期" width="130" />
|
||
<el-table-column prop="platform" label="渠道" width="100" />
|
||
<el-table-column prop="totalCount" label="核对笔数" width="100" />
|
||
<el-table-column prop="matchedCount" label="一致笔数" width="100" />
|
||
<el-table-column label="差异笔数" width="100">
|
||
<template #default="{ row }">
|
||
<span :class="row.diffCount > 0 ? 'console-debit' : 'console-credit'">{{
|
||
row.diffCount
|
||
}}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="amountSum" label="金额合计" width="110" />
|
||
<el-table-column prop="status" label="状态" width="100" />
|
||
<el-table-column prop="detail" label="明细" min-width="240" show-overflow-tooltip />
|
||
<el-table-column
|
||
prop="finishedAt"
|
||
label="完成时间"
|
||
min-width="165"
|
||
show-overflow-tooltip
|
||
:formatter="dateCell"
|
||
/>
|
||
</el-table>
|
||
<div class="pagination">
|
||
<el-pagination
|
||
v-model:current-page="reconcile.page"
|
||
v-model:page-size="reconcile.size"
|
||
:page-sizes="[10, 20, 50]"
|
||
:total="reconcile.total"
|
||
layout="total, prev, pager, next, sizes"
|
||
background
|
||
@current-change="loadReconcile"
|
||
@size-change="loadReconcile"
|
||
/>
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</section>
|
||
|
||
<el-drawer
|
||
v-model="eventsVisible"
|
||
:title="`订单流水 · ${eventsOrderNo}`"
|
||
size="640px"
|
||
class="console-drawer"
|
||
>
|
||
<el-table
|
||
v-loading="eventsLoading"
|
||
:data="events"
|
||
size="small"
|
||
border
|
||
empty-text="该订单暂无状态流转记录"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="70" />
|
||
<el-table-column prop="event" label="事件" width="130" />
|
||
<el-table-column label="状态流转" width="190">
|
||
<template #default="{ row }"
|
||
>{{ row.fromStatus || '-' }} → {{ row.toStatus || '-' }}</template
|
||
>
|
||
</el-table-column>
|
||
<el-table-column prop="source" label="来源" width="100" />
|
||
<el-table-column prop="operatorId" label="操作人" width="90" />
|
||
<el-table-column prop="createdAt" label="时间" width="165" :formatter="dateCell" />
|
||
<el-table-column prop="payload" label="载荷" min-width="220" show-overflow-tooltip />
|
||
</el-table>
|
||
</el-drawer>
|
||
|
||
<el-dialog v-model="coinVisible" title="人工补币" width="480px">
|
||
<el-form label-position="top">
|
||
<el-form-item label="用户 ID" required>
|
||
<el-input v-model="coinForm.userId" placeholder="仅支持已存在的 App 用户" />
|
||
</el-form-item>
|
||
<el-form-item label="变动金额" required>
|
||
<el-input-number v-model="coinForm.amount" :step="10" class="console-number" />
|
||
<span class="console-muted">正数补发、负数扣回,单位为金币</span>
|
||
</el-form-item>
|
||
<el-form-item label="备注">
|
||
<el-input v-model="coinForm.remark" maxlength="60" placeholder="例如:客服补偿" />
|
||
</el-form-item>
|
||
<el-form-item label="幂等键">
|
||
<el-input
|
||
v-model="coinForm.idempotentKey"
|
||
maxlength="64"
|
||
placeholder="可留空;同一工单重复提交请填同一个键"
|
||
/>
|
||
</el-form-item>
|
||
<el-alert
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
title="补币会写入金币流水,请注意重复提交同一幂等键不会重复加币"
|
||
/>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="coinVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="coinSaving" @click="confirmCoin">提交</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="grantVisible" title="人工补发权益" width="480px">
|
||
<el-form label-position="top">
|
||
<el-form-item label="用户 ID" required>
|
||
<el-input v-model="grantForm.userId" />
|
||
</el-form-item>
|
||
<el-form-item label="短剧 ID" required>
|
||
<el-input v-model="grantForm.dramaId" />
|
||
</el-form-item>
|
||
<el-form-item label="剧集 ID">
|
||
<el-input v-model="grantForm.episodeId" placeholder="留空或填 0 表示整剧权益" />
|
||
</el-form-item>
|
||
<el-form-item label="权益类型">
|
||
<el-radio-group v-model="grantForm.type">
|
||
<el-radio label="EPISODE">单集</el-radio>
|
||
<el-radio label="DRAMA">整剧</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-alert
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
title="权益补发即时生效,用户下次取播放票据即可直接观看;补发动作与操作人记入后台操作日志"
|
||
/>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="grantVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="grantSaving" @click="confirmGrant">提交</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|