feat: 团队订单与管理端订单代码重构、合并
This commit is contained in:
parent
f7d40414c0
commit
e1733e3f47
|
|
@ -8,11 +8,3 @@ export function listRecord(query) {
|
|||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询团队(部门)余额变动详细(只读)
|
||||
export function getRecord(id) {
|
||||
return request({
|
||||
url: '/ai/record/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ export function listSubteamChargeOrder(query) {
|
|||
return request({ url: '/subteam/charge-order/list', method: 'get', params: query })
|
||||
}
|
||||
|
||||
/** 导出:POST /subteam/charge-order/export(与列表相同查询参数 + 创建时间区间) */
|
||||
export const subteamChargeOrderExportUrl = 'subteam/charge-order/export'
|
||||
|
||||
export function getSubteamChargeOrder(id) {
|
||||
return request({ url: '/subteam/charge-order/' + id, method: 'get' })
|
||||
}
|
||||
|
|
@ -74,14 +77,17 @@ export function getSubteamUserBalance(id) {
|
|||
return request({ url: '/subteam/user-balance/' + id, method: 'get' })
|
||||
}
|
||||
|
||||
/** 列表:GET /subteam/consume-stat/list(参数与管理端 ai/data 一致:startDate、endDate、pageNum、pageSize) */
|
||||
export function listSubteamConsumeStat(query) {
|
||||
return request({ url: '/subteam/consume-stat/list', method: 'get', params: query })
|
||||
}
|
||||
|
||||
/** 导出:POST /subteam/consume-stat/export */
|
||||
export const subteamConsumeStatExportUrl = 'subteam/consume-stat/export'
|
||||
|
||||
export function listSubteamGroupBalance(query) {
|
||||
return request({ url: '/subteam/group-balance/list', method: 'get', params: query })
|
||||
}
|
||||
|
||||
export function getSubteamGroupBalance(id) {
|
||||
return request({ url: '/subteam/group-balance/' + id, method: 'get' })
|
||||
}
|
||||
/** 导出:POST /subteam/group-balance/export(与列表相同查询参数 + 创建时间区间) */
|
||||
export const subteamGroupBalanceExportUrl = 'subteam/group-balance/export'
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="订单号" prop="relationOrderNo">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
|
||||
<el-form-item label="关联订单号" prop="relationOrderNo">
|
||||
<el-input
|
||||
v-model="queryParams.relationOrderNo"
|
||||
placeholder="请输入关联(充值/退款)订单号"
|
||||
placeholder="支持模糊查询,充值/退款订单号"
|
||||
clearable
|
||||
style="width: 300px"
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
|
@ -178,9 +178,11 @@ export default {
|
|||
this.handleQuery()
|
||||
},
|
||||
handleExport() {
|
||||
this.download('ai/record/export', {
|
||||
...this.queryParams
|
||||
}, `record_${new Date().getTime()}.xlsx`)
|
||||
this.download(
|
||||
'ai/record/export',
|
||||
this.addDateRange({ ...this.queryParams }, this.dateRange, 'CreateTime'),
|
||||
`record_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true" label-width="88px">
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-select v-model="queryParams.orderType" clearable placeholder="全部">
|
||||
<el-option label="充值" :value="0" />
|
||||
<el-option label="退款" :value="1" />
|
||||
</el-select>
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="70px">
|
||||
<el-form-item label="订单号" prop="orderNum">
|
||||
<el-input
|
||||
v-model="queryParams.orderNum"
|
||||
placeholder="支持模糊搜索"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderNum">
|
||||
<el-input v-model="queryParams.orderNum" clearable @keyup.enter.native="handleQuery" />
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-select v-model="queryParams.orderType" placeholder="全部" clearable style="width: 110px">
|
||||
<el-option
|
||||
v-for="item in orderTypeQueryOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
|
|
@ -24,30 +33,61 @@
|
|||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['subteam:charge:export']"
|
||||
>导出</el-button>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="70" />
|
||||
<el-table-column label="团队" prop="deptName" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="类型" width="90">
|
||||
<template slot-scope="s">{{ typeLabel(s.row.orderType) }}</template>
|
||||
|
||||
<el-table v-loading="loading" :data="groupChargeOrderList">
|
||||
<el-table-column label="订单号" align="center" prop="orderNum" width="200" show-overflow-tooltip />
|
||||
<el-table-column label="类型" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ orderTypeLabel(scope.row.orderType) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" prop="money" width="110" align="right">
|
||||
<template slot-scope="s"><span>{{ formatMoney(s.row.money) }}</span></template>
|
||||
<el-table-column label="金额(元)" align="center" prop="money" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ formatTableMoney(scope.row.money) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="积分" prop="amount" width="110" align="right">
|
||||
<template slot-scope="s"><span>{{ formatAmount(s.row.amount) }}</span></template>
|
||||
<el-table-column label="积分" align="center" prop="amount" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ formatTableAmount(scope.row.amount) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ statusLabel(scope.row.status) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="150">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
<el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamChargeOrder } from '@/api/subteam'
|
||||
import { listSubteamChargeOrder, subteamChargeOrderExportUrl } from '@/api/subteam'
|
||||
|
||||
export default {
|
||||
name: 'SubteamChargeOrder',
|
||||
data() {
|
||||
|
|
@ -55,42 +95,87 @@ export default {
|
|||
loading: true,
|
||||
showSearch: true,
|
||||
dateRange: [],
|
||||
list: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, orderType: undefined, orderNum: undefined }
|
||||
groupChargeOrderList: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
orderNum: null,
|
||||
orderType: null
|
||||
},
|
||||
orderTypeQueryOptions: [
|
||||
{ label: '充值', value: 0 },
|
||||
{ label: '退款', value: 1 }
|
||||
],
|
||||
orderTypeOptions: [
|
||||
{ label: '充值', value: 0 },
|
||||
{ label: '退款', value: 1 },
|
||||
{ label: '手动修改', value: 2 }
|
||||
],
|
||||
statusOptions: [
|
||||
{ label: '进行中', value: 0 },
|
||||
{ label: '已完成', value: 1 },
|
||||
{ label: '失败', value: 2 }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
formatMoney(value) {
|
||||
if (value == null || value === '') return '—'
|
||||
formatTableMoney(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '—'
|
||||
}
|
||||
const n = Number(value)
|
||||
if (Number.isNaN(n)) return '—'
|
||||
if (Number.isNaN(n)) {
|
||||
return '—'
|
||||
}
|
||||
return n.toLocaleString('en-US', { maximumFractionDigits: 2, minimumFractionDigits: 0 })
|
||||
},
|
||||
formatAmount(value) {
|
||||
if (value == null || value === '') return '—'
|
||||
formatTableAmount(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '—'
|
||||
}
|
||||
const n = Number(value)
|
||||
if (Number.isNaN(n)) return '—'
|
||||
if (Number.isNaN(n)) {
|
||||
return '—'
|
||||
}
|
||||
return n.toLocaleString('en-US', { maximumFractionDigits: 0 })
|
||||
},
|
||||
typeLabel(t) {
|
||||
const m = { 0: '充值', 1: '退款', 2: '手动修改' }
|
||||
return m[t] != null ? m[t] : '—'
|
||||
orderTypeLabel(orderType) {
|
||||
const n = orderType !== undefined && orderType !== null ? Number(orderType) : null
|
||||
const hit = this.orderTypeOptions.find(o => o.value === n)
|
||||
return hit ? hit.label : '—'
|
||||
},
|
||||
statusLabel(status) {
|
||||
const n = status !== undefined && status !== null ? Number(status) : null
|
||||
const hit = this.statusOptions.find(o => o.value === n)
|
||||
return hit ? hit.label : '—'
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamChargeOrder(this.addDateRange(this.queryParams, this.dateRange, 'CreateTime')).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
listSubteamChargeOrder(this.addDateRange(this.queryParams, this.dateRange, 'CreateTime')).then(response => {
|
||||
this.groupChargeOrderList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.dateRange = []
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
handleExport() {
|
||||
this.download(
|
||||
subteamChargeOrderExportUrl,
|
||||
this.addDateRange({ ...this.queryParams }, this.dateRange, 'CreateTime'),
|
||||
`group_charge_order_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +1,195 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true" label-width="96px">
|
||||
<el-form-item label="统计日期" prop="statDate">
|
||||
<el-date-picker v-model="queryParams.statDate" type="date" value-format="yyyyMMdd" placeholder="请选择日期" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="96px">
|
||||
<el-form-item label="统计日期">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
style="width: 240px"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
unlink-panels
|
||||
value-format="yyyy-MM-dd"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
style="width: 280px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['subteam:consume:export']"
|
||||
>导出</el-button>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<p class="tip">仅展示当前团队数据;请选择日期后查询。</p>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="日期" prop="dateKey" />
|
||||
<el-table-column label="团队" prop="deptName" />
|
||||
<el-table-column label="充值积分" prop="rechargeScore" />
|
||||
<el-table-column label="消耗积分" prop="score" />
|
||||
<el-table-column label="成功订单" prop="orderCount" />
|
||||
<el-table-column label="Tokens" prop="useTokens" />
|
||||
|
||||
<p class="summary-line">
|
||||
<template v-if="summaryState.mode === 'loading'">
|
||||
<span> </span>
|
||||
<span class="summary-prefix">汇总:</span><span class="summary-muted">加载中…</span>
|
||||
</template>
|
||||
<template v-else-if="summaryState.mode === 'empty'">
|
||||
<span> </span>
|
||||
<span class="summary-prefix">汇总:</span><span class="summary-muted">—</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span> </span>
|
||||
<span class="summary-prefix">汇总:</span>
|
||||
<span class="summary-label">总计</span>
|
||||
<span class="summary-num">{{ summaryState.totalStr }}</span>
|
||||
<span class="summary-label">条记录,实际充值积分</span>
|
||||
<span class="summary-num">{{ summaryState.recharge }}</span>
|
||||
<span class="summary-unit">分</span>
|
||||
<span class="summary-label">,消耗积分</span>
|
||||
<span class="summary-num">{{ summaryState.score }}</span>
|
||||
<span class="summary-unit">分</span>
|
||||
<span class="summary-label">,实际订单数量(成功)</span>
|
||||
<span class="summary-num">{{ summaryState.orders }}</span>
|
||||
<span class="summary-unit">单</span>
|
||||
<span class="summary-label">,三方消耗tokens数量</span>
|
||||
<span class="summary-num">{{ summaryState.tokens }}</span>
|
||||
<span class="summary-unit">。</span>
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<el-table v-loading="loading" :data="dataList">
|
||||
<el-table-column label="日期" align="center" prop="dateKey" min-width="110" />
|
||||
<el-table-column
|
||||
label="实际充值积分(充值-退款)"
|
||||
align="center"
|
||||
prop="rechargeScore"
|
||||
min-width="200"
|
||||
:formatter="formatWesternNumber"
|
||||
/>
|
||||
<el-table-column label="消耗积分" align="center" prop="score" width="120" :formatter="formatWesternNumber" />
|
||||
<el-table-column
|
||||
label="实际订单数量(成功)"
|
||||
align="center"
|
||||
prop="orderCount"
|
||||
width="160"
|
||||
:formatter="formatWesternNumber"
|
||||
/>
|
||||
<el-table-column
|
||||
label="三方消耗tokens数量"
|
||||
align="center"
|
||||
prop="useTokens"
|
||||
width="170"
|
||||
:formatter="formatWesternNumber"
|
||||
/>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamConsumeStat } from '@/api/subteam'
|
||||
import { listSubteamConsumeStat, subteamConsumeStatExportUrl } from '@/api/subteam'
|
||||
|
||||
export default {
|
||||
name: 'SubteamConsumeStat',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
dateRange: [],
|
||||
list: [],
|
||||
showSearch: true,
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, statDate: null }
|
||||
dataList: [],
|
||||
aggregate: null,
|
||||
dateRange: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
startDate: null,
|
||||
endDate: null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initDefaultDateRange()
|
||||
this.syncDateRangeToQuery()
|
||||
this.getList()
|
||||
},
|
||||
computed: {
|
||||
summaryState() {
|
||||
if (this.loading) {
|
||||
return { mode: 'loading' }
|
||||
}
|
||||
const a = this.aggregate
|
||||
if (!a) {
|
||||
return { mode: 'empty' }
|
||||
}
|
||||
const fmt = (v) => this.formatWesternNumberValue(v)
|
||||
const n = a.totalRows != null ? Number(a.totalRows) : 0
|
||||
const totalStr = Number.isNaN(n) ? '0' : n.toLocaleString('en-US')
|
||||
return {
|
||||
mode: 'ok',
|
||||
totalStr,
|
||||
recharge: fmt(a.sumRechargeScore),
|
||||
score: fmt(a.sumScore),
|
||||
orders: fmt(a.sumOrderCount),
|
||||
tokens: fmt(a.sumUseTokens)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
if (!this.queryParams.statDate) {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
return
|
||||
formatWesternNumberValue(cellValue) {
|
||||
if (cellValue === null || cellValue === undefined || cellValue === '') {
|
||||
return (0).toLocaleString('en-US')
|
||||
}
|
||||
const n = Number(cellValue)
|
||||
if (Number.isNaN(n)) {
|
||||
return (0).toLocaleString('en-US')
|
||||
}
|
||||
return n.toLocaleString('en-US')
|
||||
},
|
||||
formatWesternNumber(row, column, cellValue) {
|
||||
return this.formatWesternNumberValue(cellValue)
|
||||
},
|
||||
buildLastMonthDateRange() {
|
||||
const end = new Date()
|
||||
const start = new Date(end.getTime())
|
||||
start.setMonth(start.getMonth() - 1)
|
||||
return [this.formatYmd(start), this.formatYmd(end)]
|
||||
},
|
||||
formatYmd(d) {
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${day}`
|
||||
},
|
||||
initDefaultDateRange() {
|
||||
this.dateRange = this.buildLastMonthDateRange()
|
||||
},
|
||||
syncDateRangeToQuery() {
|
||||
if (Array.isArray(this.dateRange) && this.dateRange.length === 2) {
|
||||
this.queryParams.startDate = this.dateRange[0]
|
||||
this.queryParams.endDate = this.dateRange[1]
|
||||
} else {
|
||||
this.queryParams.startDate = null
|
||||
this.queryParams.endDate = null
|
||||
}
|
||||
},
|
||||
getList() {
|
||||
this.syncDateRangeToQuery()
|
||||
this.loading = true
|
||||
listSubteamConsumeStat(this.addDateRange(this.queryParams, this.dateRange, 'CreateTime')).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
listSubteamConsumeStat(this.queryParams)
|
||||
.then(response => {
|
||||
this.dataList = response.rows || []
|
||||
this.total = response.total != null ? response.total : 0
|
||||
this.aggregate =
|
||||
response.param && response.param.aggregate != null ? response.param.aggregate : null
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
|
@ -65,15 +198,61 @@ export default {
|
|||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.dateRange = []
|
||||
this.initDefaultDateRange()
|
||||
this.resetForm('queryForm')
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.queryParams.pageNum = 1
|
||||
this.syncDateRangeToQuery()
|
||||
this.getList()
|
||||
},
|
||||
handleExport() {
|
||||
this.syncDateRangeToQuery()
|
||||
this.download(
|
||||
subteamConsumeStatExportUrl,
|
||||
{
|
||||
startDate: this.queryParams.startDate,
|
||||
endDate: this.queryParams.endDate
|
||||
},
|
||||
`team_consume_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tip { color: #909399; font-size: 13px; margin-bottom: 12px; }
|
||||
.summary-line {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
margin: 0 0 12px 0;
|
||||
padding-left: 8px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.summary-prefix {
|
||||
color: #909399;
|
||||
font-weight: 600;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.summary-muted {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.summary-unit {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.summary-num {
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
margin: 0 2px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
|
||||
<el-form-item label="关联订单号" prop="relationOrderNo">
|
||||
<el-input
|
||||
v-model="queryParams.relationOrderNo"
|
||||
placeholder="支持模糊查询,充值/退款订单号"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="queryParams.type" clearable placeholder="全部类型" style="width: 180px">
|
||||
<el-select v-model="queryParams.type" clearable placeholder="全部类型" style="width: 112px">
|
||||
<el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联单号" prop="relationOrderNo">
|
||||
<el-input v-model="queryParams.relationOrderNo" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
|
|
@ -23,31 +29,61 @@
|
|||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['subteam:groupBalance:export']"
|
||||
>导出</el-button>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="80" />
|
||||
<el-table-column label="关联单号" prop="relationOrderNo" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="类型" width="100">
|
||||
<template slot-scope="s">
|
||||
<span>{{ typeLabel(s.row.type) }}</span>
|
||||
|
||||
<el-table v-loading="loading" :data="recordList">
|
||||
<el-table-column label="ID" align="center" prop="id" width="100" />
|
||||
<el-table-column label="关联订单号" align="center" prop="relationOrderNo" width="200" show-overflow-tooltip />
|
||||
<el-table-column label="操作类型" align="center" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ typeLabel(scope.row.type) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更积分" prop="changeAmount" width="120" align="right">
|
||||
<template slot-scope="s"><span>{{ formatChangeAmount(s.row) }}</span></template>
|
||||
<el-table-column
|
||||
label="变更积分"
|
||||
align="center"
|
||||
prop="changeAmount"
|
||||
width="120"
|
||||
:formatter="formatChangeAmount"
|
||||
/>
|
||||
<el-table-column
|
||||
label="变更后积分"
|
||||
align="center"
|
||||
prop="resultAmount"
|
||||
width="120"
|
||||
:formatter="formatResultAmount"
|
||||
/>
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更后积分" prop="resultAmount" width="120" align="right">
|
||||
<template slot-scope="s"><span>{{ formatResultAmount(s.row) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时间" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamGroupBalance } from '@/api/subteam'
|
||||
import { listSubteamGroupBalance, subteamGroupBalanceExportUrl } from '@/api/subteam'
|
||||
|
||||
export default {
|
||||
name: 'SubteamGroupBalance',
|
||||
data() {
|
||||
|
|
@ -55,8 +91,8 @@ export default {
|
|||
loading: true,
|
||||
showSearch: true,
|
||||
dateRange: [],
|
||||
list: [],
|
||||
total: 0,
|
||||
recordList: [],
|
||||
typeOptions: [
|
||||
{ label: '充值', value: 0 },
|
||||
{ label: '退款', value: 1 },
|
||||
|
|
@ -64,10 +100,17 @@ export default {
|
|||
{ label: '回收', value: 3 },
|
||||
{ label: '手动修改', value: 4 }
|
||||
],
|
||||
queryParams: { pageNum: 1, pageSize: 10, type: undefined, relationOrderNo: undefined }
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
relationOrderNo: null,
|
||||
type: null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
formatPointsWestern(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
|
|
@ -89,8 +132,12 @@ export default {
|
|||
return String(value)
|
||||
}
|
||||
const formatted = Math.abs(n).toLocaleString('en-US', { maximumFractionDigits: 0 })
|
||||
if (n > 0) return `+${formatted}`
|
||||
if (n < 0) return `-${formatted}`
|
||||
if (n > 0) {
|
||||
return `+${formatted}`
|
||||
}
|
||||
if (n < 0) {
|
||||
return `-${formatted}`
|
||||
}
|
||||
return '0'
|
||||
},
|
||||
formatResultAmount(row) {
|
||||
|
|
@ -103,17 +150,27 @@ export default {
|
|||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamGroupBalance(this.addDateRange(this.queryParams, this.dateRange, 'CreateTime')).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
listSubteamGroupBalance(this.addDateRange(this.queryParams, this.dateRange, 'CreateTime')).then(response => {
|
||||
this.recordList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.dateRange = []
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
handleExport() {
|
||||
this.download(
|
||||
subteamGroupBalanceExportUrl,
|
||||
this.addDateRange({ ...this.queryParams }, this.dateRange, 'CreateTime'),
|
||||
`group_balance_record_${new Date().getTime()}.xlsx`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||
|
|
@ -55,14 +53,4 @@ public class AiGroupBalanceChangeRecordController extends BaseController
|
|||
ExcelUtil<AiGroupBalanceChangeRecord> util = new ExcelUtil<AiGroupBalanceChangeRecord>(AiGroupBalanceChangeRecord.class);
|
||||
util.exportExcel(response, list, "团队(部门)余额变动数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取团队(部门)余额变动详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordById(id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
package com.ruoyi.web.controller.subteam;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/subteam/charge-order")
|
||||
public class SubteamChargeOrderController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ISubteamDataQueryService subteamDataQueryService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
|
|
@ -32,10 +33,19 @@ public class SubteamChargeOrderController extends BaseController {
|
|||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiChargeRefundOrder query) {
|
||||
startPage();
|
||||
List<AiChargeRefundOrder> list = subteamDataQueryService.selectChargeRefundOrders(query);
|
||||
List<AiChargeRefundOrder> list = aiChargeRefundOrderService.selectAiChargeRefundOrderListForCurrentSubteam(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:charge:export')")
|
||||
@Log(title = "团队充值记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiChargeRefundOrder query) {
|
||||
List<AiChargeRefundOrder> list = aiChargeRefundOrderService.selectAiChargeRefundOrderListForCurrentSubteam(query);
|
||||
ExcelUtil<AiChargeRefundOrder> util = new ExcelUtil<AiChargeRefundOrder>(AiChargeRefundOrder.class);
|
||||
util.exportExcel(response, list, "团队充值退款订单数据");
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:charge:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
|
|
|
|||
|
|
@ -1,32 +1,78 @@
|
|||
package com.ruoyi.web.controller.subteam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.domain.request.GroupReportDataRequest;
|
||||
import com.ruoyi.ai.domain.vo.SubteamConsumeStatExportRow;
|
||||
import com.ruoyi.ai.domain.vo.TeamDailyConsumeAggregateVO;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
|
||||
/**
|
||||
* 团队后台「消耗统计」:与管理端 /ai/data 同一套 Service / Mapper,仅强制限定为当前登录人所属团队。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/subteam/consume-stat")
|
||||
public class SubteamConsumeStatController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ISubteamDataQueryService subteamDataQueryService;
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:consume:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiVideoReportData query) {
|
||||
if (StringUtils.isEmpty(query.getStatDate())) {
|
||||
return getDataTable(java.util.Collections.emptyList());
|
||||
public TableDataInfo list(@ModelAttribute GroupReportDataRequest query) {
|
||||
GroupReportDataRequest scoped = applyTeamScope(query);
|
||||
TeamDailyConsumeAggregateVO aggregate = aiVideoReportDataService.selectTeamDailyConsumeAggregate(scoped);
|
||||
List<AiVideoReportData> list = aiVideoReportDataService.selectTeamDailyConsumeListPaged(scoped);
|
||||
TableDataInfo rsp = new TableDataInfo();
|
||||
rsp.setCode(HttpStatus.SUCCESS);
|
||||
rsp.setMsg("查询成功");
|
||||
rsp.setRows(list);
|
||||
rsp.setTotal(aggregate.getTotalRows());
|
||||
Map<String, Object> param = new HashMap<>(2);
|
||||
param.put("aggregate", aggregate);
|
||||
rsp.setParam(param);
|
||||
return rsp;
|
||||
}
|
||||
startPage();
|
||||
List<AiVideoReportData> list = subteamDataQueryService.selectTeamDailyConsume(query.getStatDate());
|
||||
return getDataTable(list);
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:consume:export')")
|
||||
@Log(title = "团队消耗统计", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, @ModelAttribute GroupReportDataRequest query) {
|
||||
if (query != null) {
|
||||
query.setPageNum(null);
|
||||
query.setPageSize(null);
|
||||
}
|
||||
GroupReportDataRequest scoped = applyTeamScope(query);
|
||||
List<AiVideoReportData> list = aiVideoReportDataService.selectTeamDailyConsumeList(scoped);
|
||||
List<SubteamConsumeStatExportRow> rows = list.stream().map(SubteamConsumeStatExportRow::from).collect(Collectors.toList());
|
||||
ExcelUtil<SubteamConsumeStatExportRow> util = new ExcelUtil<>(SubteamConsumeStatExportRow.class);
|
||||
util.exportExcel(response, rows, "团队消耗统计");
|
||||
}
|
||||
|
||||
private GroupReportDataRequest applyTeamScope(GroupReportDataRequest query) {
|
||||
GroupReportDataRequest q = query == null ? new GroupReportDataRequest() : query;
|
||||
q.setDeptId(subteamScopeService.currentTeamDeptId());
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,62 @@
|
|||
package com.ruoyi.web.controller.subteam;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
|
||||
/**
|
||||
* 团队后台:本团队总积分变动。列表/导出与 {@link com.ruoyi.ai.controller.AiGroupBalanceChangeRecordController} 同源,
|
||||
* 使用 {@link IAiGroupBalanceChangeRecordService},仅通过 {@link ISubteamScopeService} 限定当前团队 deptId。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/subteam/group-balance")
|
||||
public class SubteamGroupBalanceController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ISubteamDataQueryService subteamDataQueryService;
|
||||
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@Autowired
|
||||
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
||||
/** 固定本团队,并禁止用团队名称条件跨团队过滤 */
|
||||
private void applyTeamScope(AiGroupBalanceChangeRecord query) {
|
||||
query.setDeptId(subteamScopeService.currentTeamDeptId());
|
||||
query.setDeptName(null);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:groupBalance:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiGroupBalanceChangeRecord query) {
|
||||
applyTeamScope(query);
|
||||
startPage();
|
||||
List<AiGroupBalanceChangeRecord> list = subteamDataQueryService.selectGroupBalanceRecords(query);
|
||||
List<AiGroupBalanceChangeRecord> list = aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:groupBalance:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
subteamScopeService.assertGroupBalanceRecordBelongsToTeam(id);
|
||||
return success(aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordById(id));
|
||||
/**
|
||||
* 导出本团队积分变动(与管理端 /ai/record/export 同源逻辑,不含团队名称列)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('subteam:groupBalance:export')")
|
||||
@Log(title = "团队积分变动", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiGroupBalanceChangeRecord query) {
|
||||
applyTeamScope(query);
|
||||
List<AiGroupBalanceChangeRecord> list = aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordList(query);
|
||||
ExcelUtil<AiGroupBalanceChangeRecord> util = new ExcelUtil<AiGroupBalanceChangeRecord>(AiGroupBalanceChangeRecord.class);
|
||||
util.hideColumn("deptName");
|
||||
util.exportExcel(response, list, "团队积分变动");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,17 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
|||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 团队(部门)充值退款订单对象 ai_charge_refund_order
|
||||
*
|
||||
|
|
@ -81,4 +88,22 @@ public class AiChargeRefundOrder implements Serializable {
|
|||
/** 状态:0-进行中 1-已完成 2-失败 */
|
||||
@Excel(name = "状态", readConverterExp = "0=进行中,1=已完成,2=失败")
|
||||
private Integer status;
|
||||
|
||||
/** 请求参数(若依日期范围:params.beginCreateTime / params.endCreateTime) */
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
@TableField(exist = false)
|
||||
@Getter(AccessLevel.NONE)
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Map<String, Object> params;
|
||||
|
||||
public Map<String, Object> getParams() {
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
public void setParams(Map<String, Object> params) {
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package com.ruoyi.ai.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 团队后台消耗统计导出行(不含团队 ID / 名称列)。
|
||||
*/
|
||||
@Data
|
||||
public class SubteamConsumeStatExportRow implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Excel(name = "日期", sort = 1)
|
||||
private String dateKey;
|
||||
|
||||
@Excel(name = "实际充值积分(充值-退款)", sort = 2)
|
||||
private BigDecimal rechargeScore;
|
||||
|
||||
@Excel(name = "消耗积分", sort = 3)
|
||||
private BigDecimal score;
|
||||
|
||||
@Excel(name = "实际订单数量(成功)", sort = 4)
|
||||
private Long orderCount;
|
||||
|
||||
@Excel(name = "三方消耗tokens数量", sort = 5)
|
||||
private Long useTokens;
|
||||
|
||||
public static SubteamConsumeStatExportRow from(AiVideoReportData s) {
|
||||
SubteamConsumeStatExportRow r = new SubteamConsumeStatExportRow();
|
||||
r.setDateKey(s.getDateKey());
|
||||
r.setRechargeScore(s.getRechargeScore());
|
||||
r.setScore(s.getScore());
|
||||
r.setOrderCount(s.getOrderCount());
|
||||
r.setUseTokens(s.getUseTokens());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
@ -39,12 +39,6 @@ public interface AiVideoReportDataMapper extends BaseMapper<AiVideoReportData> {
|
|||
@Param("offset") int offset,
|
||||
@Param("limit") int limit);
|
||||
|
||||
/**
|
||||
* 按团队部门、日期聚合(团队后台消耗统计)
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(@Param("statDate") String statDate,
|
||||
@Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 近 N 日(含)按 date_key 日维度汇总消耗积分与成功订单数
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ public interface IAiChargeRefundOrderService {
|
|||
*/
|
||||
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
/**
|
||||
* 团队后台:仅当前登录部门,其它条件与 {@link #selectAiChargeRefundOrderList} 相同
|
||||
*/
|
||||
List<AiChargeRefundOrder> selectAiChargeRefundOrderListForCurrentSubteam(AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
/**
|
||||
* 新增团队(部门)充值退款订单
|
||||
*
|
||||
|
|
|
|||
|
|
@ -39,11 +39,6 @@ public interface IAiVideoReportDataService {
|
|||
/** 团队每日消耗分页列表(依赖 query 中的 pageNum/pageSize,Service 内写入 offset)。 */
|
||||
List<AiVideoReportData> selectTeamDailyConsumeListPaged(GroupReportDataRequest query);
|
||||
|
||||
/**
|
||||
* 团队每日消耗(按部门 ID,团队后台)
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId);
|
||||
|
||||
void updateReportDataWhenInsertAiOrder(AiOrder order);
|
||||
|
||||
void updateReportDataWhenInsertChargeRefundOrder(AiChargeRefundOrder order);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.ruoyi.common.utils.DateUtils;
|
|||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
|
@ -35,6 +36,9 @@ public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderServi
|
|||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单
|
||||
*
|
||||
|
|
@ -57,6 +61,14 @@ public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderServi
|
|||
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(aiChargeRefundOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiChargeRefundOrder> selectAiChargeRefundOrderListForCurrentSubteam(AiChargeRefundOrder aiChargeRefundOrder) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
aiChargeRefundOrder.setDeptId(deptId);
|
||||
aiChargeRefundOrder.setDeptName(null);
|
||||
return selectAiChargeRefundOrderList(aiChargeRefundOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)充值退款订单
|
||||
*
|
||||
|
|
|
|||
|
|
@ -80,11 +80,6 @@ public class AiVideoReportDataServiceImpl implements IAiVideoReportDataService {
|
|||
query.getStartDate(), query.getEndDate(), query.getDeptId(), offset, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) {
|
||||
return aiVideoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateReportDataWhenInsertAiOrder(AiOrder order) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH");
|
||||
|
|
|
|||
|
|
@ -2,17 +2,8 @@ package com.ruoyi.system.service.subteam;
|
|||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
|
||||
public interface ISubteamDataQueryService {
|
||||
|
||||
List<AiChargeRefundOrder> selectChargeRefundOrders(AiChargeRefundOrder query);
|
||||
|
||||
List<AiBalanceChangeRecord> selectUserBalanceRecords(AiBalanceChangeRecord query);
|
||||
|
||||
List<AiGroupBalanceChangeRecord> selectGroupBalanceRecords(AiGroupBalanceChangeRecord query);
|
||||
|
||||
List<AiVideoReportData> selectTeamDailyConsume(String statDate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,5 @@ public interface ISubteamScopeService {
|
|||
|
||||
void assertChargeRefundBelongsToTeam(Long orderPkId);
|
||||
|
||||
void assertGroupBalanceRecordBelongsToTeam(Long recordId);
|
||||
|
||||
void assertAiBalanceRecordVisible(Long recordId, Long teamDeptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,7 @@ import java.util.List;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.mapper.AiBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
|
||||
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
|
||||
|
|
@ -21,44 +14,12 @@ public class SubteamDataQueryServiceImpl implements ISubteamDataQueryService {
|
|||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@Autowired
|
||||
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
|
||||
|
||||
@Autowired
|
||||
private AiBalanceChangeRecordMapper aiBalanceChangeRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
@Override
|
||||
public List<AiChargeRefundOrder> selectChargeRefundOrders(AiChargeRefundOrder query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
query.setDeptId(deptId);
|
||||
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiBalanceChangeRecord> selectUserBalanceRecords(AiBalanceChangeRecord query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
return aiBalanceChangeRecordMapper.selectAiBalanceChangeRecordListByAiUserDept(query, deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiGroupBalanceChangeRecord> selectGroupBalanceRecords(AiGroupBalanceChangeRecord query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
query.setDeptId(deptId);
|
||||
return aiGroupBalanceChangeRecordMapper.selectAiGroupBalanceChangeRecordList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiVideoReportData> selectTeamDailyConsume(String statDate) {
|
||||
if (StringUtils.isEmpty(statDate)) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
return aiVideoReportDataService.selectTeamDailyConsumeByDeptId(statDate, deptId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ package com.ruoyi.system.service.subteam.impl;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
|
||||
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.mapper.AiOrderMapper;
|
||||
import com.ruoyi.ai.mapper.AiBalanceChangeRecordMapper;
|
||||
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||
|
|
@ -30,9 +28,6 @@ public class SubteamScopeServiceImpl implements ISubteamScopeService {
|
|||
@Autowired
|
||||
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
|
||||
|
||||
@Autowired
|
||||
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private AiBalanceChangeRecordMapper aiBalanceChangeRecordMapper;
|
||||
|
||||
|
|
@ -84,15 +79,6 @@ public class SubteamScopeServiceImpl implements ISubteamScopeService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertGroupBalanceRecordBelongsToTeam(Long recordId) {
|
||||
Long teamDeptId = currentTeamDeptId();
|
||||
AiGroupBalanceChangeRecord r = aiGroupBalanceChangeRecordMapper.selectById(recordId);
|
||||
if (r == null || r.getDeptId() == null || !teamDeptId.equals(r.getDeptId())) {
|
||||
throw new ServiceException("无权查看该记录");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertAiBalanceRecordVisible(Long recordId, Long teamDeptId) {
|
||||
AiBalanceChangeRecord r = aiBalanceChangeRecordMapper.selectById(recordId);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="money != null "> and o.money = #{money}</if>
|
||||
<if test="amount != null "> and o.amount = #{amount}</if>
|
||||
<if test="status != null "> and o.status = #{status}</if>
|
||||
<if test="params != null and params.beginCreateTime != null and params.beginCreateTime != ''">
|
||||
and date_format(o.create_time,'%Y%m%d') >= date_format(#{params.beginCreateTime},'%Y%m%d')
|
||||
</if>
|
||||
<if test="params != null and params.endCreateTime != null and params.endCreateTime != ''">
|
||||
and date_format(o.create_time,'%Y%m%d') <= date_format(#{params.endCreateTime},'%Y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by o.id desc
|
||||
</select>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<select id="selectAiGroupBalanceChangeRecordList" parameterType="AiGroupBalanceChangeRecord" resultMap="AiGroupBalanceChangeRecordResult">
|
||||
<include refid="selectAiGroupBalanceChangeRecordVo"/>
|
||||
<where>
|
||||
<if test="relationOrderNo != null and relationOrderNo != ''"> and r.relation_order_no = #{relationOrderNo}</if>
|
||||
<if test="relationOrderNo != null and relationOrderNo != ''"> and r.relation_order_no like concat('%', #{relationOrderNo}, '%')</if>
|
||||
<if test="deptId != null "> and r.dept_id = #{deptId}</if>
|
||||
<if test="deptName != null and deptName != ''"> and d.dept_name like concat('%', #{deptName}, '%')</if>
|
||||
<if test="type != null "> and r.type = #{type}</if>
|
||||
|
|
|
|||
|
|
@ -105,22 +105,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
LIMIT #{limit} OFFSET #{offset}
|
||||
</select>
|
||||
|
||||
<select id="selectTeamDailyConsumeByDeptId" resultMap="AiVideoReportDataResult">
|
||||
select substr(vrd.date_key, 1, 10) as date_key,
|
||||
vrd.dept_id,
|
||||
d.dept_name,
|
||||
sum(vrd.recharge_score) as recharge_score,
|
||||
sum(vrd.score) as score,
|
||||
sum(vrd.order_count) as order_count,
|
||||
sum(vrd.use_tokens) as use_tokens
|
||||
from ai_video_report_data vrd
|
||||
left join sys_dept d on d.dept_id = vrd.dept_id
|
||||
where vrd.date_key like concat(#{statDate}, '%')
|
||||
and vrd.dept_id = #{deptId}
|
||||
group by substr(vrd.date_key, 1, 10), vrd.dept_id, d.dept_name
|
||||
order by substr(vrd.date_key, 1, 10) desc, vrd.dept_id desc
|
||||
</select>
|
||||
|
||||
<select id="selectDeptVideoMetricsBetween" resultType="com.ruoyi.system.domain.subteam.SubteamVideoMetrics">
|
||||
select ifnull(sum(vrd.score), 0) as consumeScore, ifnull(sum(vrd.order_count), 0) as orderCount
|
||||
from ai_video_report_data vrd where vrd.dept_id = #{deptId}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ values('团队充值记录', @subteamRoot, '4', 'charge-order', 'subteam/chargeO
|
|||
SELECT @m3 := LAST_INSERT_ID();
|
||||
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
values('充值记录查询', @m3, '1', '#', '', 1, 0, 'F', '0', '0', 'subteam:charge:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
values('充值记录导出', @m3, '2', '#', '', 1, 0, 'F', '0', '0', 'subteam:charge:export', '#', 'admin', sysdate(), '', null, '');
|
||||
|
||||
-- 用户余额变动(门户 ai_user)
|
||||
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
|
|
@ -201,3 +203,24 @@ ALTER TABLE `byteai`.`ai_dept_ark_config`
|
|||
|
||||
ALTER TABLE `byteai`.`ai_video_report_data`
|
||||
ADD COLUMN `recharge_score` decimal(14, 2) NULL AFTER `user_id`;
|
||||
|
||||
-- 团队端「团队积分变动」导出权限(组件 ai/groupchargeorder/index,接口 POST /ai/group/chargeorder/record/export)
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
SELECT '团队积分变动导出', m.menu_id, 6, '#', '', 1, 0, 'F', '0', '0', 'ai:groupChargeOrder:record:export', '#', 'admin', sysdate(), '', null, '与 ai:groupChargeOrder:list 同页,单独控制导出'
|
||||
FROM sys_menu m
|
||||
WHERE m.perms = 'ai:groupChargeOrder:list' AND m.menu_type = 'C'
|
||||
LIMIT 1;
|
||||
|
||||
-- 团队后台「团队余额变动」导出(组件 subteam/groupBalance/index,接口 POST /subteam/group-balance/export)
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
SELECT '团队余额变动导出', m.menu_id, 2, '#', '', 1, 0, 'F', '0', '0', 'subteam:groupBalance:export', '#', 'admin', sysdate(), '', null, '与 subteam:groupBalance:list 同页'
|
||||
FROM sys_menu m
|
||||
WHERE m.perms = 'subteam:groupBalance:list' AND m.menu_type = 'C'
|
||||
LIMIT 1;
|
||||
|
||||
-- 团队后台「团队消耗统计」导出(组件 subteam/consumeStat/index,接口 POST /subteam/consume-stat/export)
|
||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
SELECT '消耗统计导出', m.menu_id, 2, '#', '', 1, 0, 'F', '0', '0', 'subteam:consume:export', '#', 'admin', sysdate(), '', null, '与 subteam:consume:list 同页'
|
||||
FROM sys_menu m
|
||||
WHERE m.perms = 'subteam:consume:list' AND m.menu_type = 'C' AND m.path = 'consume-stat'
|
||||
LIMIT 1;
|
||||
Loading…
Reference in New Issue