Files
91fans_admin/src/views/videoManagement/emojiList/index.vue
T
rootandClaude Opus 5 e282bd23e8 Switch to dart-sass and make deploy script fail-safe
node-sass 4.x cannot build on arm64/Node 16. Use sass with ::v-deep
instead of /deep/, and only replace the server dist after the upload
is unpacked and verified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 19:18:37 +08:00

781 lines
22 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>
<div class="tag-box">
<!--操作栏-->
<div class="action-bar">
<!-- <el-select
placeholder="请选择状态"
clearable
size="small"
v-model="params.status"
@change="getList('status')"
>
<el-option
:label="item.label"
:value="item.value"
v-for="item in enables"
:key="item.value"
></el-option>
</el-select> -->
<el-button
type="primary"
size="small"
icon="el-icon-search"
@click="getList('status')"
style="margin-right: 20px"
>搜索</el-button
>
<el-button
type="primary"
size="small"
@click="addAndEdit('add')"
style="margin-right: 20px"
>新增</el-button
>
</div>
<!--数据表格-->
<el-table
:data="tableData"
style="width: 100%"
border
v-loading="loading"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
ref="multipleTable"
height="600"
>
<el-table-column prop="id" label="ID" align="center" min-width="210">
<template slot-scope="scope">
<span>{{ scope.row.id || "-" }}</span>
</template>
</el-table-column>
<el-table-column
label="封面图"
align="center"
min-width="120"
prop="cover"
>
<template slot-scope="scope">
<img-load
:width="'80px'"
:height="'60px'"
:src="imgUrl + scope.row.cover"
>
</img-load>
</template>
</el-table-column>
<el-table-column prop="name" label="名称" align="center" min-width="150">
<template slot-scope="scope">
<span>{{ scope.row.name || "-" }}</span>
</template>
</el-table-column>
<el-table-column
prop="author"
label="作者"
align="center"
min-width="150"
>
<template slot-scope="scope">
<span>{{ scope.row.author || "-" }}</span>
</template>
</el-table-column>
<el-table-column
prop="code"
label="表情包代码"
align="center"
width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.code }}</span>
</template>
</el-table-column>
<el-table-column
prop="vipLevel"
label="VIP等级限制"
align="center"
width="80"
>
<template slot-scope="scope">
<span>{{ scope.row.vipLevel }}</span>
</template>
</el-table-column>
<el-table-column
prop="boughtCount"
label="购买次数"
align="center"
width="100"
>
<template slot-scope="scope">
<span>{{ scope.row.boughtCount }}</span>
</template>
</el-table-column>
<el-table-column prop="coin" label="售价金币" align="center" width="100">
<template slot-scope="scope">
<span>{{ scope.row.coin }}</span>
</template>
</el-table-column>
<el-table-column prop="icons" label="表情包" align="center" width="120">
<template slot-scope="scope">
<el-button
v-if="scope.row.icons && scope.row.icons.length > 0"
size="small"
@click="viewResourceConfig(scope.row.icons)"
>点击查看</el-button
><el-button v-else size="small" disabled>点击查看</el-button>
</template>
</el-table-column>
<el-table-column prop="sortOrder" label="排序" align="center" width="100">
<template slot-scope="scope">
<span>{{ scope.row.sortOrder }}</span>
</template>
</el-table-column>
<el-table-column
prop="status"
label="状态"
align="center"
min-width="120"
>
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.status === 1">上架</el-tag>
<el-tag type="danger" v-if="scope.row.status === 0">下架</el-tag>
</template>
</el-table-column>
<el-table-column prop="summary" label="简介" align="center" width="280">
<template slot-scope="scope">
<span>{{ scope.row.summary || "-" }}</span>
</template>
</el-table-column>
<el-table-column
prop="updatedAt"
label="更新时间"
align="center"
min-width="180"
>
<template slot-scope="scope">
<span>{{ changeTimes(scope.row.updatedAt) }}</span>
</template>
</el-table-column>
<el-table-column
prop="createdAt"
label="创建时间"
align="center"
min-width="180"
>
<template slot-scope="scope">
<span>{{ changeTimes(scope.row.createdAt) }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
min-width="180"
fixed="right"
>
<template slot-scope="scope">
<el-button
size="mini"
type="success"
icon="el-icon-edit"
@click="addAndEdit(scope.row)"
>编辑</el-button
>
<!-- <el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="del(scope.row)"
>删除</el-button
> -->
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<el-pagination
:page-sizes="[10, 15, 20, 30]"
:current-page="params.pageNumber"
:page-size="params.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
@size-change="changeSize"
@current-change="changeCurrent"
></el-pagination>
<!-- 新增、修改 -->
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="580px"
@close="handleClose"
>
<el-form :model="form" label-width="100px" :rules="rules" ref="form">
<el-form-item style="width: 480px" label="封面图:" prop="cover">
<base-upload
class="upload"
:cover="form.cover"
:action="action"
wSize="47"
hSize="47"
:width="'138.5px'"
:height="'138.5px'"
@successCallback="handleCoverSuccess"
></base-upload>
</el-form-item>
<el-form-item style="width: 480px" label="名称" prop="name">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item style="width: 480px" label="作者" prop="author">
<el-input v-model="form.author"></el-input>
</el-form-item>
<el-form-item
style="width: 480px"
label="表情包代码(仅限英文数字)"
prop="code"
>
<el-input v-model="form.code"></el-input>
</el-form-item>
<el-form-item style="width: 480px" label="售价金币" prop="coin">
<el-input v-model.number="form.coin"></el-input>
</el-form-item>
<el-form-item style="width: 480px" label="VIP等级限制" prop="vipLevel">
<el-input v-model.number="form.vipLevel"></el-input>
</el-form-item>
<el-form-item style="width: 480px" label="排序" prop="sortOrder">
<el-input v-model.number="form.sortOrder"></el-input>
</el-form-item>
<el-form-item label="表情包配置">
<el-button type="primary" size="small" @click="openEmojiConfig"
>表情包配置</el-button
>
</el-form-item>
<el-form-item label="状态" style="width: 480px">
<el-select v-model="form.status" placeholder="请选择状态">
<el-option
v-for="item in enables"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="简介" prop="summary" style="width: 480px">
<el-input type="textarea" :rows="5" v-model="form.summary"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="onSubmit()">确 定</el-button>
</div>
</el-dialog>
<el-dialog
title="表情包配置"
:visible.sync="emojiDialogVisible"
width="900px"
@before-close="emojiHandleClose"
>
<div
v-for="(item, index) in tempIcons"
:key="index"
style="position:relative"
>
<div v-if="tempIcons.length !== 0">
<span style="margin:10px 2px 10px 10px"
>表情代码(仅限英文数字):</span
>
<el-input
type="text"
size="small"
clearable
v-model="tempIcons[index].code"
style="width:180px;"
@input="onInput"
></el-input>
<span style="margin:10px 2px 10px 10px">图片:</span>
<div @click="uploadImgIndex(index)" style="display: inline-block;">
<el-upload
style="height: 40px;width: 40px;"
:headers="header"
:action="uploadUrl"
name="upload"
accept="image/jpeg,image/png,image/jpg, image/gif, image/webp"
:show-file-list="false"
:on-success="uploadImg"
:before-upload="beforeImg"
>
<img
v-if="tempIcons[index].img"
:src="imgUrl + tempIcons[index].img"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<span style="margin:10px 2px 10px 10px">描述信息:</span>
<el-input
type="text"
size="small"
clearable
v-model="tempIcons[index].text"
style="width:250px;"
@input="onInput"
></el-input>
<i
class="el-icon-circle-plus"
v-if="index === tempIcons.length - 1"
style="color:#67c23a;font-size:24px;cursor:pointer;position:absolute;right:20px;top:15px"
@click="addBtn"
></i>
<i
class="el-icon-remove"
v-if="tempIcons.length > 1"
style="color:#f56c6c;font-size:24px;cursor:pointer;position:absolute;right:-5px;top:15px"
@click="removeBtn(item)"
></i>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="emojiHandleClose"
>确 定</el-button
>
</div>
</el-dialog>
<!-- 查看表情包配置 -->
<el-dialog
title="表情包配置"
:visible.sync="emojiConfigDialog"
width="900px"
@before-close="emojiHandleClose"
>
<div class="tip">(此处仅支持查看,如要修改请点击编辑按钮)</div>
<div
v-for="(item, index) in viewEmoji"
:key="index"
style="position:relative"
>
<div v-if="viewEmoji.length !== 0">
<span style="margin:10px 2px 10px 10px"
>表情代码(仅限英文数字):</span
>
<el-input
type="text"
size="small"
clearable
v-model="viewEmoji[index].code"
style="width:180px;"
></el-input>
<span style="margin:10px 2px 10px 10px">图片</span>
<div @click="uploadImgIndex(index)" style="display: inline-block;">
<el-upload
style="height: 40px;width: 40px;"
:headers="header"
:action="uploadUrl"
name="upload"
accept="image/jpeg,image/png,image/jpg, image/gif, image/webp"
:show-file-list="false"
:on-success="uploadImg"
:before-upload="beforeImg"
>
<img
v-if="viewEmoji[index].img"
:src="imgUrl + viewEmoji[index].img"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<span style="margin:10px 2px 10px 10px">描述信息:</span>
<el-input
type="text"
size="small"
clearable
v-model="viewEmoji[index].text"
style="width:250px;"
@input="onInput"
></el-input>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button size="small" type="primary" @click="emojiHandleClose"
>关 闭</el-button
>
</div>
</el-dialog>
<!--封面图、视频弹窗组件-->
<media-popup ref="mediaPopup"></media-popup>
</div>
</template>
<script>
import API from "@/api";
import { uniteDate } from "@/utils/validator.js";
import baseConfig from "@/utils/serverUrlConfig";
import local from "@/utils/localStroage";
import { changeTime } from "@/utils/global";
import MediaPopup from "@/components/media-popup";
import { internalLinks } from "@/utils/common.js";
export default {
components: {
MediaPopup,
},
data() {
return {
// 表格数据加载动画
loading: false,
// 封面上传地址
uploadUrl: baseConfig.baseServerUrl + "/vid/uploadStatic",
header: {
Authorization: local.get("userInfo").token,
},
// 列表数据
tableData: [],
total: 0,
params: {
pageNumber: 1,
pageSize: 10,
},
imgUrl: baseConfig.imgUrl,
// 图片上传地址
action: baseConfig.baseServerUrl + "/agent/upload/static",
types: [{ label: "金刚区下活动特惠", value: 0 }],
enables: [
{ label: "上架", value: 1 },
{ label: "下架", value: 0 },
],
linkTypeList: [
{ label: "内部浏览器跳转", value: 1 },
{ label: "外部浏览器跳转", value: 2 },
],
linkList: internalLinks,
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
linkUrl: [
{ required: true, message: "请输入链接地址", trigger: "blur" },
],
},
dialogTitle: "",
dialogVisible: false,
time: "",
form: {
id: undefined,
author: undefined, // 作者
code: undefined, // 包代码(仅限英文数字)
coin: 0, // 售价金币
cover: undefined, // 封面图
icons: undefined, // 表情图标
name: undefined, // 表情包名称
sortOrder: 0, // 排序
status: 1, // 状态 0 下架 1 上架
summary: undefined, // 简介
vipLevel: 0, // VIP等级限制
},
emojiDialogVisible: false,
tempIcons: [
{
code: undefined, // 表情代码(仅限英文数字)
img: undefined, // 图片
text: undefined, // 描述信息
},
],
currentIndex: 0, // 当前上传的图片索引
emojiConfigDialog: false,
viewEmoji: [],
rescourceTypes: [
{
label: "图片",
value: 0,
},
{
label: "视频",
value: 1,
},
],
};
},
created() {
this.getList();
},
methods: {
getList(type) {
if (type === "status") {
this.params.pageNumber = 1;
}
API.getEmojiList(this.params)
.then((res) => {
if (res.code === 200 && res.data) {
this.tableData = res.data.list;
this.total = res.data.total;
} else {
this.tableData = [];
}
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
// 标签封面上传成功回掉
handleCoverSuccess(res) {
this.form.cover = res.data.coverImg;
},
uploadImgIndex(index) {
this.currentIndex = index;
},
beforeImg(file) {
if (!file) return;
const isLt3M = file.size / 1024 / 1024 < 0.2;
if (!isLt3M) {
this.$message.error("表情包图片上传大小不能超过200kb");
return false;
}
},
// 图片上传成功
uploadImg(res) {
this.tempIcons[this.currentIndex].img = res.data.coverImg;
},
// 查看媒体
checkMedia(url, type) {
this.$refs.mediaPopup.open(url, type);
},
// 新增标签配置
addAndEdit(param) {
this.dialogVisible = true; // 打开新增、编辑对话框
if (param === "add") {
this.dialogTitle = "新增";
} else {
this.dialogTitle = "编辑";
// 把数据回显给表单
this.form.id = param.id;
this.form.author = param.author;
this.form.code = param.code;
this.form.coin = param.coin;
this.form.name = param.name;
this.form.cover = param.cover;
this.form.sortOrder = param.sortOrder;
this.form.status = param.status;
this.form.summary = param.summary;
this.form.vipLevel = param.vipLevel;
if (!param.icons || (param.icons && !param.icons.length)) {
param.icons = [{
code: '', // 表情代码(仅限英文数字)
img: '', // 图片
text: '', // 描述信息
}];
}
this.tempIcons = param.icons;
}
},
// 新增、修改提交
onSubmit() {
if (this.dialogTitle === "新增") {
this.add();
} else {
this.edit();
}
},
// 新增方法
add() {
this.$refs["form"].validate((valid) => {
if (valid) {
this.form.icons = this.tempIcons;
API.addEmoji(this.form).then((res) => {
if (res.code === 200) {
this.$message({
type: "success",
message: "新增成功",
});
this.getList();
this.handleClose();
} else {
this.$message({
type: "error",
message: res.data || res.msg || "新增失败",
});
}
});
} else {
return false;
}
});
},
// 修改方法
edit() {
this.$refs["form"].validate((valid) => {
if (valid) {
this.form.icons = this.tempIcons;
API.updateEmoji(this.form).then((res) => {
if (res.code === 200) {
this.$message({
type: "success",
message: "编辑成功",
});
this.getList();
this.handleClose();
} else {
this.$message({
type: "error",
message: res.data || res.msg || "编辑失败",
});
}
});
} else {
return false;
}
});
},
del(param) {
this.$confirm(
`确认是否删除<span style='color:blue'>${param.name}</span>, 是否继续?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
dangerouslyUseHTMLString: true,
}
)
.then(() => {
let delData = {
id: param.id,
};
API.deleteEmoji(delData).then((res) => {
if (res.code === 200) {
this.$message({
type: "success",
message: "删除成功!",
});
} else {
this.$message({
type: "error",
message: res.data || res.msg || "删除失败",
});
}
this.getList();
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
// 关闭窗口清除数据
handleClose() {
this.form.id = undefined;
this.form.author = undefined;
this.form.code = undefined;
this.form.coin = 0;
this.form.cover = undefined;
this.form.icons = undefined;
this.form.name = undefined;
this.form.sortOrder = 0;
this.form.status = 1;
this.form.summary = undefined;
this.form.vipLevel = 0;
this.tempIcons = [
{
code: undefined, // 表情代码(仅限英文数字)
img: undefined, // 图片
text: undefined, // 描述信息
},
];
this.dialogVisible = false;
},
// 分页条数改变回调
changeSize(size) {
this.params.pageSize = size;
this.getList();
},
// 分页页码改变回调
changeCurrent(pageNumber) {
this.params.pageNumber = pageNumber;
this.getList();
},
// 更换时间格式
changeTimes(time) {
return uniteDate(time);
},
// 时间触发回调
changeDate(time) {
if (time) {
this.form.startTime = changeTime(time[0]) || "";
this.form.endTime = changeTime(time[1]) || "";
}
},
// ----------------------------资源相关--------------------------
onInput() {
this.$forceUpdate();
},
openEmojiConfig() {
this.emojiDialogVisible = true;
},
emojiHandleClose() {
this.emojiDialogVisible = false;
this.emojiConfigDialog = false;
this.viewEmoji = [];
},
// 增加数量
addBtn() {
this.tempIcons.push({
code: undefined,
img: undefined,
text: undefined,
});
},
// 减少数量
removeBtn(value) {
this.tempIcons = this.tempIcons.filter((item) => {
if (item.code !== value.code) {
return item;
}
});
},
viewResourceConfig(emojiConfig) {
this.viewEmoji = JSON.parse(JSON.stringify(emojiConfig));
console.log(this.viewEmoji);
this.emojiConfigDialog = true;
},
},
};
</script>
<style lang="scss" scoped>
.dialog-footer {
position: relative;
left: 50%;
-webkit-transform: translate(-50%);
transform: translate(-50%);
}
::v-deep .el-form-item__content {
display: flex;
}
::v-deep .el-select {
width: 100%;
}
.avatar-uploader .el-upload {
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader-icon {
font-size: 20px;
color: #8c939d;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px dashed #d9d9d9;
border-radius: 6px;
}
.avatar {
width: 40px;
height: 40px;
display: block;
border-radius: 6px;
overflow: hidden;
}
.views {
cursor: pointer;
}
</style>