327 lines
13 KiB
Vue
327 lines
13 KiB
Vue
<template>
|
||
<div class="asset-resource-container">
|
||
<!-- 搜索区域 -->
|
||
<el-card class="!border-none" shadow="never">
|
||
<el-form class="ls-form" :model="searchData" inline>
|
||
<el-form-item class="w-[280px]" label="标题">
|
||
<el-input
|
||
placeholder="请输入标题关键词"
|
||
v-model="searchData.title"
|
||
clearable
|
||
@keyup.enter="handleSearch"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="上传时间">
|
||
<el-date-picker
|
||
v-model="searchData.dateRange"
|
||
type="daterange"
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
value-format="YYYY-MM-DD"
|
||
clearable
|
||
style="width: 280px;"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
<el-button @click="handleReset">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 列表区域 -->
|
||
<el-card class="!border-none mt-4" shadow="never">
|
||
<div class="mb-4 flex items-center gap-2">
|
||
<el-button type="primary" @click="handleAdd">上传资源</el-button>
|
||
<el-button type="danger" :disabled="selectedIds.length === 0" @click="handleBatchDelete">
|
||
批量删除
|
||
</el-button>
|
||
<span v-if="selectedIds.length > 0" class="text-sm text-gray-500">已选 {{ selectedIds.length }} 条</span>
|
||
</div>
|
||
|
||
<el-tabs v-model="queryParams.type" @tab-change="handleTabChange">
|
||
<el-tab-pane label="图片" name="1"></el-tab-pane>
|
||
<el-tab-pane label="视频" name="2"></el-tab-pane>
|
||
<el-tab-pane label="语音" name="3"></el-tab-pane>
|
||
</el-tabs>
|
||
|
||
<el-table :data="tableData" v-loading="loading" @selection-change="handleSelectionChange">
|
||
<el-table-column type="selection" width="55" />
|
||
<!-- <el-table-column prop="id" label="ID" width="80" /> -->
|
||
<el-table-column prop="title" label="标题" min-width="80" />
|
||
<el-table-column label="预览" width="100">
|
||
<template #default="{ row }">
|
||
<el-image v-if="row.type == 1" :src="row.file_url" style="width: 50px; height: 50px;" :preview-src-list="[row.file_url]" preview-teleported />
|
||
<el-link v-else :href="row.file_url" target="_blank" type="primary">点击预览</el-link>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="关联账号" min-width="150" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<el-tag v-if="!row.users?.length" type="info" size="small">公开资源</el-tag>
|
||
<span v-else>{{ row.users?.map((u: any) => u.phone).join(', ') }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="create_time" label="上传时间" width="180" />
|
||
<el-table-column label="操作" width="150" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
|
||
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="mt-4 flex justify-end">
|
||
<el-pagination
|
||
v-model:current-page="queryParams.page_no"
|
||
v-model:page-size="queryParams.page_size"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="getList"
|
||
@current-change="getList"
|
||
/>
|
||
</div>
|
||
</el-card>
|
||
|
||
<!-- 新增/编辑资源弹窗 -->
|
||
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑资源' : '新增分发资源'" width="600px" destroy-on-close>
|
||
<el-form ref="formRef" :model="formData" :rules="computedRules" label-width="100px">
|
||
<el-form-item label="资源类型" prop="type" v-if="!isEdit">
|
||
<el-radio-group v-model="formData.type">
|
||
<el-radio :label="1">图片</el-radio>
|
||
<el-radio :label="2">视频</el-radio>
|
||
<el-radio :label="3">语音</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="标题" prop="title">
|
||
<el-input v-model="formData.title" placeholder="请输入资源标题" />
|
||
</el-form-item>
|
||
<el-form-item label="资源文件" prop="file_url" v-if="!isEdit">
|
||
<div v-if="formData.type === 1" class="w-full">
|
||
<material-picker v-model="formData.file_url" :limit="9" type="image" />
|
||
<div style="font-size: 12px; color: #909399; margin-top: 4px;">支持批量上传多张图片,一次最多 9 张,每张图片将生成一条独立资源(多张时标题自动追加序号)</div>
|
||
</div>
|
||
<upload v-else-if="formData.type === 2" type="video" direct :multiple="false" :limit="1" :show-progress="true" @success="handleUploadSuccess">
|
||
<el-button type="primary">上传视频 (OSS直传)</el-button>
|
||
</upload>
|
||
<upload v-else-if="formData.type === 3" type="voice" direct :multiple="false" :limit="1" :show-progress="true" @success="handleUploadSuccess">
|
||
<el-button type="primary">上传语音 (OSS直传)</el-button>
|
||
</upload>
|
||
<div v-if="formData.file_url && formData.type !== 1" class="ml-4 text-primary truncate max-w-xs" :title="formData.file_url">
|
||
已上传: {{ formData.file_url }}
|
||
</div>
|
||
</el-form-item>
|
||
<el-form-item label="关联账号" prop="user_ids">
|
||
<el-select v-model="formData.user_ids" multiple filterable placeholder="不选择则为公开资源" clearable style="width: 100%;">
|
||
<el-option v-for="item in userOptions" :key="item.id" :label="item.phone" :value="item.id" />
|
||
</el-select>
|
||
<div style="font-size: 12px; color: #909399; margin-top: 4px;">不选择账号则资源为公开资源,所有人可见</div>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitForm" :loading="submitLoading">{{ isEdit ? '保存修改' : '确定发布' }}</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive, computed, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import { apiAssetResourceList, apiAssetResourceAdd, apiAssetResourceEdit, apiAssetResourceDelete, apiAssetUserList } from '@/api/asset'
|
||
import MaterialPicker from '@/components/material/picker.vue'
|
||
import Upload from '@/components/upload/index.vue'
|
||
|
||
const loading = ref(false)
|
||
const tableData = ref<any[]>([])
|
||
const total = ref(0)
|
||
const selectedIds = ref<number[]>([])
|
||
|
||
const searchData = reactive<any>({
|
||
title: '',
|
||
dateRange: []
|
||
})
|
||
|
||
const queryParams = reactive<any>({
|
||
type: '1',
|
||
page_no: 1,
|
||
page_size: 15
|
||
})
|
||
|
||
const dialogVisible = ref(false)
|
||
const submitLoading = ref(false)
|
||
const formRef = ref()
|
||
const isEdit = ref(false)
|
||
const editId = ref(0)
|
||
|
||
const userOptions = ref<any[]>([])
|
||
|
||
const formData = reactive<any>({
|
||
type: 1,
|
||
title: '',
|
||
file_url: '',
|
||
cover_url: '',
|
||
user_ids: []
|
||
})
|
||
|
||
const validateFileUrl = (_rule: any, value: any, callback: any) => {
|
||
if (Array.isArray(value)) {
|
||
if (!value.length) return callback(new Error('请上传资源文件'))
|
||
} else if (!value) {
|
||
return callback(new Error('请输入或上传文件获取链接'))
|
||
}
|
||
callback()
|
||
}
|
||
|
||
const computedRules = computed(() => {
|
||
if (isEdit.value) {
|
||
return {
|
||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }]
|
||
}
|
||
}
|
||
return {
|
||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||
file_url: [{ required: true, validator: validateFileUrl, trigger: 'change' }]
|
||
}
|
||
})
|
||
|
||
const buildQueryParams = () => {
|
||
const params: any = { ...queryParams }
|
||
if (searchData.title) {
|
||
params.title = searchData.title
|
||
}
|
||
if (searchData.dateRange && searchData.dateRange.length === 2) {
|
||
params.start_time = searchData.dateRange[0]
|
||
params.end_time = searchData.dateRange[1]
|
||
}
|
||
return params
|
||
}
|
||
|
||
const getList = async () => {
|
||
loading.value = true
|
||
try {
|
||
const res = await apiAssetResourceList(buildQueryParams())
|
||
tableData.value = res.lists
|
||
total.value = res.count
|
||
selectedIds.value = []
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const fetchUserOptions = async () => {
|
||
try {
|
||
const res = await apiAssetUserList({ page_no: 1, page_size: 9999 })
|
||
userOptions.value = res.lists
|
||
} catch (e) {
|
||
console.error(e)
|
||
}
|
||
}
|
||
|
||
const handleSearch = () => {
|
||
queryParams.page_no = 1
|
||
getList()
|
||
}
|
||
|
||
const handleReset = () => {
|
||
searchData.title = ''
|
||
searchData.dateRange = []
|
||
queryParams.page_no = 1
|
||
getList()
|
||
}
|
||
|
||
const handleTabChange = () => {
|
||
queryParams.page_no = 1
|
||
getList()
|
||
}
|
||
|
||
const handleAdd = () => {
|
||
isEdit.value = false
|
||
editId.value = 0
|
||
Object.assign(formData, { type: parseInt(queryParams.type), title: '', file_url: '', cover_url: '', user_ids: [] })
|
||
fetchUserOptions()
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
const handleEdit = (row: any) => {
|
||
isEdit.value = true
|
||
editId.value = row.id
|
||
Object.assign(formData, {
|
||
type: row.type,
|
||
title: row.title,
|
||
file_url: row.file_url,
|
||
cover_url: row.cover_url || '',
|
||
user_ids: row.users?.map((u: any) => u.id) || []
|
||
})
|
||
fetchUserOptions()
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
const handleUploadSuccess = (response: any) => {
|
||
formData.file_url = response?.data?.uri || response?.data?.url || ''
|
||
ElMessage.success('上传成功')
|
||
}
|
||
|
||
const handleDelete = async (row: any) => {
|
||
try {
|
||
await ElMessageBox.confirm('确定要删除该资源吗?用户将无法再看到。', '提示', { type: 'warning' })
|
||
await apiAssetResourceDelete({ id: row.id })
|
||
ElMessage.success('删除成功')
|
||
getList()
|
||
} catch (e) {
|
||
// canceled
|
||
}
|
||
}
|
||
|
||
const handleSelectionChange = (rows: any[]) => {
|
||
selectedIds.value = rows.map((row) => Number(row.id)).filter((id) => id > 0)
|
||
}
|
||
|
||
const handleBatchDelete = async () => {
|
||
if (!selectedIds.value.length) return
|
||
try {
|
||
await ElMessageBox.confirm(`确定要删除选中的 ${selectedIds.value.length} 个资源吗?用户将无法再看到。`, '提示', { type: 'warning' })
|
||
await apiAssetResourceDelete({ id: selectedIds.value })
|
||
ElMessage.success('删除成功')
|
||
getList()
|
||
} catch (e) {
|
||
// canceled
|
||
}
|
||
}
|
||
|
||
const submitForm = async () => {
|
||
if (!formRef.value) return
|
||
await formRef.value.validate(async (valid: boolean) => {
|
||
if (valid) {
|
||
submitLoading.value = true
|
||
try {
|
||
if (isEdit.value) {
|
||
await apiAssetResourceEdit({
|
||
id: editId.value,
|
||
title: formData.title,
|
||
user_ids: formData.user_ids
|
||
})
|
||
ElMessage.success('编辑成功')
|
||
} else {
|
||
await apiAssetResourceAdd(formData)
|
||
ElMessage.success('上传分发成功')
|
||
}
|
||
dialogVisible.value = false
|
||
getList()
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
submitLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
getList()
|
||
})
|
||
</script>
|