feat: 团队订单与管理端订单代码重构、合并

This commit is contained in:
yys 2026-04-23 16:40:02 +08:00
parent f7d40414c0
commit e1733e3f47
25 changed files with 655 additions and 257 deletions

View File

@ -8,11 +8,3 @@ export function listRecord(query) {
params: query
})
}
// 查询团队(部门)余额变动详细(只读)
export function getRecord(id) {
return request({
url: '/ai/record/' + id,
method: 'get'
})
}

View File

@ -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'

View File

@ -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`
)
}
}
}

View File

@ -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`
)
}
}
}

View File

@ -1,79 +1,258 @@
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="summary-prefix">汇总</span><span class="summary-muted">加载中</span>
</template>
<template v-else-if="summaryState.mode === 'empty'">
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span class="summary-prefix">汇总</span><span class="summary-muted"></span>
</template>
<template v-else>
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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
this.loading = false
})
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
})
},
handleQuery() {
this.queryParams.pageNum = 1
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>

View File

@ -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`
)
}
}
}

View File

@ -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));
}
}

View File

@ -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) {

View File

@ -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;
}
@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);
}
startPage();
List<AiVideoReportData> list = subteamDataQueryService.selectTeamDailyConsume(query.getStatDate());
return getDataTable(list);
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;
}
}

View File

@ -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, "团队积分变动");
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 日维度汇总消耗积分与成功订单数
*/

View File

@ -29,6 +29,11 @@ public interface IAiChargeRefundOrderService {
*/
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 团队后台仅当前登录部门其它条件与 {@link #selectAiChargeRefundOrderList} 相同
*/
List<AiChargeRefundOrder> selectAiChargeRefundOrderListForCurrentSubteam(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 新增团队部门充值退款订单
*

View File

@ -39,11 +39,6 @@ public interface IAiVideoReportDataService {
/** 团队每日消耗分页列表(依赖 query 中的 pageNum/pageSizeService 内写入 offset。 */
List<AiVideoReportData> selectTeamDailyConsumeListPaged(GroupReportDataRequest query);
/**
* 团队每日消耗按部门 ID团队后台
*/
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId);
void updateReportDataWhenInsertAiOrder(AiOrder order);
void updateReportDataWhenInsertChargeRefundOrder(AiChargeRefundOrder order);

View File

@ -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);
}
/**
* 新增团队部门充值退款订单
*

View File

@ -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");

View File

@ -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);
}

View File

@ -18,7 +18,5 @@ public interface ISubteamScopeService {
void assertChargeRefundBelongsToTeam(Long orderPkId);
void assertGroupBalanceRecordBelongsToTeam(Long recordId);
void assertAiBalanceRecordVisible(Long recordId, Long teamDeptId);
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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') &gt;= 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') &lt;= date_format(#{params.endCreateTime},'%Y%m%d')
</if>
</where>
order by o.id desc
</select>

View File

@ -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>

View File

@ -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}

View File

@ -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)
@ -200,4 +202,25 @@ ALTER TABLE `byteai`.`ai_dept_ark_config`
ADD COLUMN `remark` varchar(255) NULL AFTER `update_time`;
ALTER TABLE `byteai`.`ai_video_report_data`
ADD COLUMN `recharge_score` decimal(14, 2) NULL AFTER `user_id`;
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;