Files
tkNewAdmin/src/views/server/employeebigbrother/index.vue

541 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true">
<el-form-item label="大哥的用户id" prop="displayId">
<el-input v-model="queryParams.displayId" placeholder="请输入大哥的用户id" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<!-- <el-form-item label="大哥的uid" prop="userIdStr">
<el-input v-model="queryParams.userIdStr" placeholder="请输入大哥的uid" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="大哥的用户昵称" prop="nickname">
<el-input v-model="queryParams.nickname" placeholder="请输入大哥的用户昵称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item> -->
<el-form-item label="大哥的等级" prop="level">
<el-input v-model="queryParams.levelMin" :placeholder="t('newHosts.min')" clearable @keyup.enter="handleQuery"
class="!w-115px" />
<span>
&nbsp;-&nbsp;
</span>
<el-input v-model="queryParams.levelMax" :placeholder="t('newHosts.max')" clearable @keyup.enter="handleQuery"
class="!w-115px" />
</el-form-item>
<el-form-item label="粉丝团等级" prop="level">
<el-input v-model="queryParams.fansLevelMin" :placeholder="t('newHosts.min')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
<span>
&nbsp;-&nbsp;
</span>
<el-input v-model="queryParams.fansLevelMax" :placeholder="t('newHosts.max')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
</el-form-item>
<!-- <el-form-item label="大哥打赏的金币" prop="hostcoins">
<el-input v-model="queryParams.hostcoins" placeholder="请输入大哥打赏的金币" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="大哥的粉丝数" prop="followerCount">
<el-input v-model="queryParams.followerCount" placeholder="请输入大哥的粉丝数" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="大哥的关注数" prop="followingCount">
<el-input v-model="queryParams.followingCount" placeholder="请输入大哥的关注数" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item> -->
<el-form-item label="大哥所在的地区" prop="region">
<el-input v-model="queryParams.region" placeholder="请输入大哥所在的地区" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="大哥打赏的历史最高金币" prop="historicHighCoins">
<el-input v-model="queryParams.historicHighCoinsMin" :placeholder="t('newHosts.min')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
<span>
&nbsp;-&nbsp;
</span>
<el-input v-model="queryParams.historicHighCoinsMax" :placeholder="t('newHosts.max')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
</el-form-item>
<el-form-item label="大哥历史打赏金币总和" prop="totalGiftCoins">
<el-input v-model="queryParams.totalGiftCoinsMin" :placeholder="t('newHosts.min')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
<span>
&nbsp;-&nbsp;
</span>
<el-input v-model="queryParams.totalGiftCoinsMax" :placeholder="t('newHosts.max')" clearable
@keyup.enter="handleQuery" class="!w-115px" />
</el-form-item>
<el-form-item label="大哥所在的直播间的主播id" prop="hostDisplayId">
<el-input v-model="queryParams.hostDisplayId" placeholder="请输入大哥所在的直播间的主播id" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<!-- <el-form-item label="该数据所属的账号id" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入该数据所属的账号id" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item> -->
<el-form-item label="创建时间" prop="createTime">
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-220px" />
</el-form-item>
<el-form-item label="是否洽谈" prop="operationStatus">
<el-select v-model="queryParams.operationStatus" placeholder="请选择是否洽谈" clearable class="!w-240px">
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.BIGBIOTHER_NEGOTIATION)" :key="dict.value"
:label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('newHosts.allocationUser')" prop="allocationUser">
<el-select v-model="queryParams.userId" :placeholder="t('newHosts.placeAllocationUser')" clearable
class="!w-240px">
<el-option v-for="(user, index) in allocationUserList" :key="index" :label="user.label" :value="user.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
<!-- <el-button type="primary" plain @click="openForm('create')" v-hasPermi="['server:employee-big-brother:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button> -->
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['server:employee-big-brother:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button @click="exportAi(1)">
<Icon icon="ep:copy-document" class="mr-5px" /> 批量复制大哥id
</el-button>
<el-button @click="exportAi(2)">
<Icon icon="ep:copy-document" class="mr-5px" /> 批量复制主播id
</el-button>
<el-button v-if="!isMobile" :disabled="checkedIds.length === 0" type="danger" @click="handleDeleteList">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button v-else type="danger" @click="handleDeletePageList">
<Icon icon="ep:delete" class="mr-5px" /> 删除本页
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-switch v-model="isMobile" size="large" active-text="卡片" inactive-text="列表" />
<el-table v-if="!isMobile" v-loading="loading" :data="list" :stripe="true"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="大哥的用户id" align="center" prop="displayId">
<template #default="scope">
<div style="color: green; text-decoration: underline;" @click="openHtml(scope.row, scope.row.displayId)">
{{ scope.row.displayId }}</div>
</template>
</el-table-column>
<el-table-column label="大哥的uid" align="center" prop="userIdStr" />
<el-table-column label="大哥的用户昵称" align="center" prop="nickname" />
<el-table-column label="大哥的等级" align="center" prop="level" />
<el-table-column label="粉丝团等级" align="center" prop="fansLevel" />
<el-table-column label="大哥打赏的金币" align="center" prop="hostcoins" />
<el-table-column label="大哥的粉丝数" align="center" prop="followerCount" />
<el-table-column label="大哥的关注数" align="center" prop="followingCount" />
<el-table-column label="大哥所在的地区" align="center" prop="region" />
<el-table-column label="大哥打赏的历史最高金币" align="center" prop="historicHighCoins" />
<el-table-column label="大哥历史打赏金币总和" align="center" prop="totalGiftCoins" />
<el-table-column label="大哥所在的直播间的主播id" align="center" prop="hostDisplayId">
<template #default="scope">
<div style="color: green; text-decoration: underline;" @click="openHtmlbig(scope.row.hostDisplayId)">
{{ scope.row.hostDisplayId }}</div>
</template>
</el-table-column>
<!-- <el-table-column label="大哥所在的直播间的主播id" align="center" prop="hostDisplayId" />
-->
<!-- <el-table-column label="该数据所属的账号id" align="center" prop="userId" /> -->
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="是否洽谈" align="center" prop="operationStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.BIGBIOTHER_NEGOTIATION" :value="scope.row.operationStatus" />
</template>
</el-table-column>
<!-- <el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['server:employee-big-brother:update']">
编辑
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)"
v-hasPermi="['server:employee-big-brother:delete']">
删除
</el-button>
</template>
</el-table-column> -->
</el-table>
<!-- ···························································································································· -->
<div v-else>
<div v-for="(item, index) in list" :key="index" class="mobile-card">
<div class="card-row" style="color:green;">
<b>大哥的用户id</b><span @click="openHtml(item, item.displayId)"
style=" text-decoration: underline;margin-right: 50px;">{{ item.displayId }}</span>
</div>
<div class="card-row"><b>大哥的uid</b>{{ item.userIdStr }}</div>
<div class="card-row"><b>大哥的用户昵称</b>{{ item.nickname }}</div>
<div class="card-row"><b>大哥的等级</b>{{ item.level }}</div>
<div class="card-row"><b>粉丝团等级:</b>{{ item.fansLevel }}</div>
<div class="card-row"><b>大哥打赏的金币</b>{{ item.hostcoins }}</div>
<div class="card-row"><b>大哥的粉丝数</b>{{ item.followerCount }}</div>
<div class="card-row"><b>大哥的关注数</b>{{ item.followingCount }}</div>
<div class="card-row"><b>大哥所在的地区:</b>{{ item.region }}</div>
<div class="card-row"><b>大哥打赏的历史最高金币:</b>{{ item.historicHighCoins }}</div>
<div class="card-row"><b>大哥历史打赏金币总和:</b>{{ item.totalGiftCoins }}</div>
<div class="card-row" style="color:green;">
<b>大哥所在的直播间的主播id</b><span @click="openHtmlbig(item.hostDisplayId)"
style=" text-decoration: underline;margin-right: 50px;">{{ item.hostDisplayId }}</span>
</div>
<div class="card-row"><b>创建时间</b>{{ formatTimestamp(item.createTime) }}</div>
<div class="card-row"><b>是否洽谈</b>
<el-tag size="small" :type="item.operationStatus == 1 ? 'success' : 'info'">
{{ dictLabelI18n(DICT_TYPE.BIGBIOTHER_NEGOTIATION, item.operationStatus) || '-' }}
</el-tag>
</div>
</div>
</div>
<MobilePagination v-if="isMobile" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
:total="total" :page-sizes="[10, 20, 30, 50]" @size-change="getList()" @load="getList()" @load-pre="getList()" />
<!-- 分页 -->
<Pagination v-if="!isMobile" :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<EmployeeBigBrotherForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE, getStrDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { EmployeeBigBrotherApi, EmployeeBigBrotherVO } from '@/api/server/employeebigbrother'
import EmployeeBigBrotherForm from './EmployeeBigBrotherForm.vue'
import { getAllocation, getSimpleUserList } from '@/api/system/user'
import { useCache } from '@/hooks/web/useCache'
const { wsCache } = useCache()
/** 大哥数据员工业务 列表 */
defineOptions({ name: 'EmployeeBigBrother' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref<EmployeeBigBrotherVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
displayId: undefined,
userIdStr: undefined,
nickname: undefined,
levelMin: undefined,
levelMax: undefined,
fansLevelMin: undefined,
fansLevelMax: undefined,
hostcoins: undefined,
followerCount: undefined,
followingCount: undefined,
region: undefined,
historicHighCoinsMin: undefined,
historicHighCoinsMax: undefined,
totalGiftCoinsMin: undefined,
totalGiftCoinsMax: undefined,
hostDisplayId: undefined,
userId: undefined,
createTime: [],
createTimeStart: '',
createTimeEnd: '',
operationStatus: undefined
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
let selectBigList = ref([])
let allocationUser = ref('') //选中的分配用户
let allocationUserList = ref([
{
label: '分配用户1',
value: 1
}
]) //选中的分配用户
/** 批量删除按钮操作 */
const checkedIds = ref<number[]>([])
//本页数据
const checkedPageIds = ref<number[]>([])
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
queryParams.createTimeStart = queryParams.createTime?.[0]
queryParams.createTimeEnd = queryParams.createTime?.[1]
const data = await EmployeeBigBrotherApi.getEmployeeBigBrotherPage(queryParams)
list.value = data.list
total.value = data.total
checkedPageIds.value = data.list.map((row) => row.id)
console.log(checkedPageIds.value)
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 删除按钮操作 */
const handleDeleteList = async () => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await EmployeeBigBrotherApi.deleteEmployeeBigBrotherList(checkedIds.value)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch { }
}
/** 删除本页按钮操作 */
const handleDeletePageList = async () => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await EmployeeBigBrotherApi.deleteEmployeeBigBrotherList(checkedPageIds.value)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch { }
}
// 格式化时间戳
function formatTimestamp(milliseconds) {
const date = new Date(milliseconds); // 直接使用毫秒级时间戳
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
import { useDictStore } from '@/store/modules/dict' // 如果你项目里有字典 store
const dictStore = useDictStore?.() // 有就用;没有的话把 dictStore 相关行删掉
// 统一用字符串比较,自动识别并翻译 i18n key
function dictLabelI18n(type: string, val: any) {
const v = val == null ? '' : String(val)
// 优先从 store 取若没有就从你现有的工具取getIntDictOptions / getStrDictOptions
const opts =
(dictStore?.getDictOptions?.(type) as any[]) ||
getIntDictOptions(type) ||
getStrDictOptions(type) ||
[]
const hit = opts.find(o => String(o.value) === v)
const label = hit?.label ?? ''
// 形如 a.b 或包含点号的,大概率是 i18n key则用 t() 翻
return label && label.includes('.') ? t(label) : label
}
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.levelMin = undefined
queryParams.levelMax = undefined
queryParams.totalGiftCoinsMin = undefined
queryParams.totalGiftCoinsMax = undefined
queryParams.historicHighCoinsMin = undefined
queryParams.historicHighCoinsMax = undefined
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await EmployeeBigBrotherApi.deleteEmployeeBigBrother(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch { }
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await EmployeeBigBrotherApi.exportEmployeeBigBrother(queryParams)
download.excel(data, '大哥数据员工业务.xls')
} catch {
} finally {
exportLoading.value = false
}
}
//分配按钮操作
const handleSelectionChange = (val) => {
checkedIds.value = val.map((row) => row.id)
selectBigList.value = val
console.log(selectBigList.value)
}
/** 查询员工 */
const getAllocationList = async () => {
loading.value = true
allocationUserList.value = []
try {
const data = await getSimpleUserList()
console.log('data', data)
data.forEach((item) => {
if (wsCache.get('user').user.id == item.id) {
} else {
allocationUserList.value.push({
label: item.nickname,
value: item.id
})
}
})
console.log(allocationUserList.value)
} finally {
loading.value = false
}
}
function openHtml(item, id) {
let data = item
data.operationStatus = 1
EmployeeBigBrotherApi.updateEmployeeBigBrother({ id: data.id, userId: data.userId, displayId: data.displayId, operationStatus: 1 }).then(res => {
getList()
})
window.open(`https://www.tiktok.com/@${id}`)
}
function openHtmlbig(id) {
window.open(`https://www.tiktok.com/@${id}`)
}
function exportAi(type) {
if (selectBigList.value.length === 0) {
ElMessage.error('请选择主播')
return
}
let data = ''
if (type == 1) {
data = selectBigList.value.map(item => item.displayId).join('\n')
} else {
data = selectBigList.value.map(item => item.hostDisplayId).join('\n')
}
const copyToClipboard = async (text) => {
// 优先使用 Clipboard API
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(text)
ElMessage.success('✅ 复制成功 ' + selectBigList.value.length + ' 条数据')
} catch (err) {
ElMessage.error('❌ 复制失败')
console.error(err)
}
} else {
// fallback 兼容方案
const textarea = document.createElement('textarea')
textarea.value = text
textarea.style.position = 'fixed' // 避免跳动
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
try {
const result = document.execCommand('copy')
if (result) {
ElMessage.success('✅(兼容模式)复制成功 ' + selectBigList.value.length + ' 条数据')
} else {
ElMessage.error('❌(兼容模式)复制失败')
}
} catch (err) {
ElMessage.error('❌(兼容模式)复制异常')
console.error(err)
} finally {
document.body.removeChild(textarea)
}
}
}
copyToClipboard(data)
}
const isMobile = ref(window.innerWidth <= 768)
/** 初始化 **/
onMounted(() => {
getList()
getAllocationList();
//实时监听实际还是电脑
window.addEventListener('resize', () => {
if ((window.innerWidth <= 768) != isMobile.value) {
getList()
}
isMobile.value = window.innerWidth <= 768
})
})
</script>
<style scoped>
@media screen and (max-width: 768px) {
.mobile-card {
background: #fff;
margin: 12px;
padding: 12px;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
font-size: 14px;
}
.card-row {
margin-bottom: 6px;
word-break: break-word;
}
.card-row b {
color: #555;
font-weight: 500;
margin-right: 4px;
}
.action-row {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 6px;
}
}
</style>