自媒体来源改推广渠道字典;非白名单隐藏账户消耗/ROI;部门展示完整路径;业绩与消耗按日期+渠道全局去重。 Co-authored-by: Cursor <cursoragent@cursor.com>
255 lines
8.9 KiB
Vue
255 lines
8.9 KiB
Vue
<template>
|
|
<div class="personal-account-cost-page">
|
|
<el-card class="!border-none mb-4" shadow="never">
|
|
<div class="flex flex-wrap">
|
|
<div class="w-1/2 md:w-1/3">
|
|
<div class="leading-10">当前筛选天数</div>
|
|
<div class="text-4xl">{{ pager.extend.days_count ?? 0 }}</div>
|
|
</div>
|
|
<div class="w-1/2 md:w-1/3">
|
|
<div class="leading-10">累计账户消耗 (元)</div>
|
|
<div class="text-4xl">¥{{ pager.extend.total_amount ?? '0.00' }}</div>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
|
|
<el-card class="!border-none" shadow="never">
|
|
<el-form class="mb-[-16px]" :model="queryParams" inline>
|
|
<el-form-item label="日期范围">
|
|
<daterange-picker
|
|
v-model:startTime="queryParams.start_date"
|
|
v-model:endTime="queryParams.end_date"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="部门">
|
|
<el-tree-select
|
|
v-model="queryParams.dept_id"
|
|
:data="deptOptions"
|
|
node-key="id"
|
|
:props="deptTreeProps"
|
|
:default-expand-all="true"
|
|
check-strictly
|
|
placeholder="全部部门"
|
|
clearable
|
|
filterable
|
|
class="w-[220px]"
|
|
@change="resetPage"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="自媒体来源">
|
|
<media-source-select
|
|
v-model="queryParams.media_source"
|
|
:options="mediaSourceOptions"
|
|
:loading="mediaSourceLoading"
|
|
placeholder="全部来源"
|
|
:allow-create="false"
|
|
select-class="w-[220px]"
|
|
@change="resetPage"
|
|
@visible-change="onMediaSourceDropdownVisible"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item class="w-[280px]" label="备注/录入人">
|
|
<el-input
|
|
v-model="queryParams.remark"
|
|
placeholder="备注 / 创建人"
|
|
clearable
|
|
@keyup.enter="resetPage"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" @click="resetPage">查询</el-button>
|
|
<el-button @click="handleReset">重置</el-button>
|
|
<el-button v-if="selfInputPath" class="ml-2" @click="goSelfInput">返回统计</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-card>
|
|
|
|
<el-card class="!border-none mt-4" shadow="never">
|
|
<div>
|
|
<el-button v-perms="['stats.personal_account_cost/add']" type="primary" @click="handleAdd">
|
|
<template #icon>
|
|
<icon name="el-icon-Plus" />
|
|
</template>
|
|
新增
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
|
|
<el-table-column label="日期" prop="cost_date" min-width="120" />
|
|
<el-table-column label="自媒体来源" prop="media_source" min-width="160" show-overflow-tooltip />
|
|
<el-table-column label="账户消耗" min-width="120">
|
|
<template #default="{ row }">¥{{ row.amount }}</template>
|
|
</el-table-column>
|
|
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
|
|
<el-table-column label="录入人" prop="creator_name" min-width="100" />
|
|
<el-table-column label="部门" prop="dept_name" min-width="140">
|
|
<template #default="{ row }">
|
|
<el-tooltip
|
|
v-if="row.dept_path"
|
|
:content="row.dept_path"
|
|
placement="top"
|
|
effect="dark"
|
|
>
|
|
<span class="dept-cell">{{ row.dept_name || '未分配' }}</span>
|
|
</el-tooltip>
|
|
<span v-else-if="row.dept_name">{{ row.dept_name }}</span>
|
|
<span v-else class="text-gray-400">未分配</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="最后修改人" prop="updater_name" min-width="100" />
|
|
<el-table-column label="更新时间" prop="update_time" min-width="180" />
|
|
<el-table-column label="操作" width="160" fixed="right">
|
|
<template #default="{ row }">
|
|
<el-button
|
|
v-perms="['stats.personal_account_cost/edit']"
|
|
type="primary"
|
|
link
|
|
@click="handleEdit(row)"
|
|
>
|
|
编辑
|
|
</el-button>
|
|
<el-button
|
|
v-perms="['stats.personal_account_cost/delete']"
|
|
type="danger"
|
|
link
|
|
@click="handleDelete(row.id)"
|
|
>
|
|
删除
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<div class="flex justify-end mt-4">
|
|
<pagination v-model="pager" @change="getLists" />
|
|
</div>
|
|
</el-card>
|
|
|
|
<cost-edit-popup
|
|
v-if="showEdit"
|
|
ref="editRef"
|
|
:media-source-options="mediaSourceOptions"
|
|
:media-source-loading="mediaSourceLoading"
|
|
@success="handleCostSuccess"
|
|
@close="showEdit = false"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup name="personalAccountCost">
|
|
import { personalAccountCostDelete, personalAccountCostLists } from '@/api/self_input_stats'
|
|
import { deptAll } from '@/api/org/department'
|
|
import { usePaging } from '@/hooks/usePaging'
|
|
import { getRoutePath } from '@/router'
|
|
import feedback from '@/utils/feedback'
|
|
|
|
import CostEditPopup from './cost-edit.vue'
|
|
import MediaSourceSelect from './MediaSourceSelect.vue'
|
|
import { useMediaSourceOptions } from './useMediaSourceOptions'
|
|
|
|
const router = useRouter()
|
|
const editRef = shallowRef<InstanceType<typeof CostEditPopup>>()
|
|
const showEdit = ref(false)
|
|
const deptOptions = ref<any[]>([])
|
|
const {
|
|
mediaSourceOptions,
|
|
mediaSourceLoading,
|
|
loadMediaSourceOptions,
|
|
refreshMediaSourceOptions,
|
|
} = useMediaSourceOptions()
|
|
|
|
const deptTreeProps = {
|
|
value: 'id',
|
|
label: 'name',
|
|
children: 'children',
|
|
}
|
|
|
|
const selfInputPath = computed(() => getRoutePath('stats.self_input/overview') || '')
|
|
|
|
const goSelfInput = () => {
|
|
if (selfInputPath.value) {
|
|
router.push(selfInputPath.value)
|
|
}
|
|
}
|
|
|
|
const queryParams = reactive({
|
|
start_date: '',
|
|
end_date: '',
|
|
media_source: '',
|
|
dept_id: undefined as number | undefined,
|
|
remark: '',
|
|
})
|
|
|
|
const { pager, getLists, resetPage } = usePaging({
|
|
fetchFun: personalAccountCostLists,
|
|
params: queryParams,
|
|
})
|
|
|
|
const handleReset = () => {
|
|
queryParams.start_date = ''
|
|
queryParams.end_date = ''
|
|
queryParams.media_source = ''
|
|
queryParams.dept_id = undefined
|
|
queryParams.remark = ''
|
|
resetPage()
|
|
}
|
|
|
|
const onMediaSourceDropdownVisible = (visible: boolean) => {
|
|
if (visible) {
|
|
refreshMediaSourceOptions()
|
|
}
|
|
}
|
|
|
|
const handleCostSuccess = async () => {
|
|
await refreshMediaSourceOptions()
|
|
getLists()
|
|
}
|
|
|
|
const handleAdd = async () => {
|
|
await refreshMediaSourceOptions()
|
|
showEdit.value = true
|
|
await nextTick()
|
|
editRef.value?.open('add')
|
|
}
|
|
|
|
const handleEdit = async (row: Record<string, any>) => {
|
|
showEdit.value = true
|
|
await nextTick()
|
|
editRef.value?.open('edit')
|
|
editRef.value?.setFormData(row)
|
|
}
|
|
|
|
const handleDelete = async (id: number) => {
|
|
await feedback.confirm('确定删除该账户消耗记录?')
|
|
await personalAccountCostDelete({ id })
|
|
getLists()
|
|
}
|
|
|
|
const loadDeptOptions = async () => {
|
|
try {
|
|
const res = await deptAll({ apply_data_scope: 1 })
|
|
if (Array.isArray(res)) {
|
|
deptOptions.value = res
|
|
}
|
|
} catch (e) {
|
|
deptOptions.value = []
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadDeptOptions()
|
|
loadMediaSourceOptions()
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.personal-account-cost-page {
|
|
padding: 20px;
|
|
}
|
|
|
|
.dept-cell {
|
|
cursor: help;
|
|
border-bottom: 1px dashed #c0c4cc;
|
|
}
|
|
</style>
|