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>
665 lines
18 KiB
Vue
665 lines
18 KiB
Vue
<template>
|
|
<div class="tag-box">
|
|
<!--操作栏-->
|
|
<div class="action-bar">
|
|
<el-select
|
|
placeholder="请选择是否开启"
|
|
clearable
|
|
size="small"
|
|
v-model="params.status"
|
|
>
|
|
<el-option
|
|
:label="item.label"
|
|
:value="item.value"
|
|
v-for="item in statuses"
|
|
:key="item.value"
|
|
></el-option>
|
|
</el-select>
|
|
<el-select
|
|
placeholder="请选择类型"
|
|
clearable
|
|
size="small"
|
|
v-model="params.type"
|
|
>
|
|
<el-option
|
|
:label="item.label"
|
|
:value="item.value"
|
|
v-for="item in types"
|
|
: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"
|
|
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 prop="name" label="名称" align="center" width="240">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.name || "-" }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="cover" label="封面图" align="center" width="120">
|
|
<template slot-scope="scope">
|
|
<span v-if="!scope.row.cover">暂无封面图</span>
|
|
<div
|
|
v-else
|
|
class="picturePreview"
|
|
@click="handlePictureCardPreview({ url: imgUrl + scope.row.cover })"
|
|
>
|
|
<decrypt-img
|
|
style="width: 80px; height: 80px"
|
|
:src="imgUrl + scope.row.cover"
|
|
fit="fill"
|
|
></decrypt-img>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="type" label="类型" align="center" width="120">
|
|
<template slot-scope="scope">
|
|
<el-tag
|
|
style="background-color: #ecf5ff;color: #409eff;border: 1px solid #d9ecff;"
|
|
v-if="scope.row.type == 1"
|
|
>宣传视频</el-tag
|
|
>
|
|
<el-tag type="success" v-else-if="scope.row.type == 2"
|
|
>游戏截图</el-tag
|
|
>
|
|
<el-tag type="info" v-else-if="scope.row.type == 3">盲盒展示</el-tag>
|
|
<el-tag type="danger" v-else-if="scope.row.type == 4"
|
|
>花絮视频</el-tag
|
|
>
|
|
<el-tag type="warning" v-else-if="scope.row.type == 5"
|
|
>下载链接</el-tag
|
|
>
|
|
<span v-else>-</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="url" label="视频审查" align="center" width="120">
|
|
<template slot-scope="scope">
|
|
<i
|
|
class="el-icon-video-play views"
|
|
title="点击预览"
|
|
@click="checkMedia(scope.row.sourceURL, 'video', scope.row)"
|
|
v-if="scope.row.sourceURL"
|
|
>
|
|
</i>
|
|
<span v-else>-</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="url" label="链接" align="center" width="280">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.url || "-" }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="status" label="状态" align="center" width="80">
|
|
<template slot-scope="scope">
|
|
<el-tag type="success" v-if="scope.row.status == 1">开启</el-tag>
|
|
<el-tag v-else>关闭</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="sortCode" label="排序" align="center" width="80">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.sortCode || 0 }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="updatedAct"
|
|
label="操作人"
|
|
align="center"
|
|
min-width="100"
|
|
>
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.updatedAct || "-" }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="updateTime"
|
|
label="修改时间"
|
|
align="center"
|
|
min-width="180"
|
|
>
|
|
<template slot-scope="scope">
|
|
<span>{{ changeTime(scope.row.updateTime) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
prop="createdAt"
|
|
label="创建时间"
|
|
align="center"
|
|
min-width="180"
|
|
>
|
|
<template slot-scope="scope">
|
|
<span>{{ changeTime(scope.row.createdAt) }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label="操作"
|
|
align="center"
|
|
min-width="280"
|
|
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="600px"
|
|
@before-close="handleClose"
|
|
@close="handleClose"
|
|
>
|
|
<el-form :model="form" label-width="100px" :rules="rules" ref="form">
|
|
<el-form-item
|
|
label="名称:"
|
|
size="small"
|
|
prop="name"
|
|
style="width: 480px"
|
|
>
|
|
<el-input v-model="form.name"></el-input>
|
|
</el-form-item>
|
|
<el-form-item
|
|
size="small"
|
|
label="封面图:"
|
|
prop="cover"
|
|
style="width: 480px"
|
|
>
|
|
<base-upload
|
|
:cover="form.cover"
|
|
:action="uploadUrl"
|
|
@successCallback="uploadPortrait"
|
|
:width="'120px'"
|
|
:height="'120px'"
|
|
:hide="true"
|
|
></base-upload>
|
|
</el-form-item>
|
|
<el-form-item
|
|
size="small"
|
|
label="类型:"
|
|
prop="type"
|
|
style="width: 480px"
|
|
>
|
|
<el-select v-model="form.type" placeholder="请选择类型">
|
|
<el-option
|
|
:label="item.label"
|
|
:value="item.value"
|
|
v-for="item in types"
|
|
:key="item.value"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="链接:"
|
|
size="small"
|
|
prop="url"
|
|
style="width: 480px"
|
|
v-if="form.type == 5"
|
|
>
|
|
<el-input v-model="form.url"></el-input>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="上传视频:"
|
|
v-if="(form.type == 1 || form.type == 4) && showUploadVideo"
|
|
>
|
|
<!--视频分片上传-->
|
|
<uploader
|
|
:options="options"
|
|
class="uploader-example"
|
|
ref="uploader"
|
|
@file-added="fileAdd"
|
|
@file-success="onFileSuccess"
|
|
>
|
|
<uploader-unsupport></uploader-unsupport>
|
|
<uploader-drop>
|
|
<uploader-btn :attrs="attrs">上传视频</uploader-btn>
|
|
</uploader-drop>
|
|
<uploader-list></uploader-list>
|
|
</uploader>
|
|
</el-form-item>
|
|
<el-form-item
|
|
size="small"
|
|
label="排序:"
|
|
prop="sortCode"
|
|
style="width: 480px"
|
|
>
|
|
<el-input v-model.number="form.sortCode"></el-input>
|
|
</el-form-item>
|
|
<el-form-item
|
|
size="small"
|
|
label="状态:"
|
|
prop="status"
|
|
style="width: 480px"
|
|
>
|
|
<el-select v-model="form.status" placeholder="请选择状态">
|
|
<el-option
|
|
:label="item.label"
|
|
:value="item.value"
|
|
v-for="item in statuses"
|
|
:key="item.value"
|
|
></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="handleClose" size="small">取 消</el-button>
|
|
<el-button type="primary" size="small" @click="onSubmit()"
|
|
>确 定</el-button
|
|
>
|
|
</div>
|
|
</el-dialog>
|
|
<el-dialog :visible.sync="dialogVisiblePreview">
|
|
<img width="100%" :src="dialogImageUrl" alt="" />
|
|
</el-dialog>
|
|
<!--封面图、视频弹窗组件-->
|
|
<preview-video ref="previewVideo"></preview-video>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import API from "@/api";
|
|
import { uniteDate } from "@/utils/validator.js";
|
|
import baseConfig from "@/utils/serverUrlConfig";
|
|
import local from "@/utils/localStroage";
|
|
import PreviewVideo from "./components/preview-video";
|
|
|
|
export default {
|
|
components: {
|
|
PreviewVideo,
|
|
},
|
|
data() {
|
|
return {
|
|
// 表格数据加载动画
|
|
loading: false,
|
|
// 封面上传地址
|
|
uploadUrl: baseConfig.baseServerUrl + "/vid/uploadStatic",
|
|
header: {
|
|
Authorization: local.get("userInfo").token,
|
|
},
|
|
dialogImageUrl: undefined, // 放大图地址
|
|
dialogVisiblePreview: false, // 放大图
|
|
imgUrl: baseConfig.imgUrl,
|
|
// 列表数据
|
|
tableData: [],
|
|
total: 0,
|
|
params: {
|
|
pageNumber: 1,
|
|
pageSize: 10,
|
|
status: undefined, // 状态
|
|
type: undefined, // 类型
|
|
},
|
|
rules: {},
|
|
types: [
|
|
{
|
|
label: "宣传视频",
|
|
value: 1,
|
|
},
|
|
{
|
|
label: "游戏截图",
|
|
value: 2,
|
|
},
|
|
{
|
|
label: "盲盒展示",
|
|
value: 3,
|
|
},
|
|
{
|
|
label: "花絮视频",
|
|
value: 4,
|
|
},
|
|
{
|
|
label: "下载链接",
|
|
value: 5,
|
|
},
|
|
],
|
|
statuses: [
|
|
{
|
|
label: "开启",
|
|
value: 1,
|
|
},
|
|
{
|
|
label: "关闭",
|
|
value: 2,
|
|
},
|
|
],
|
|
dialogTitle: "",
|
|
dialogVisible: false,
|
|
showUploadVideo: true,
|
|
form: {
|
|
id: undefined,
|
|
cover: undefined, // 封面图
|
|
name: undefined, // 名称
|
|
sortCode: 0, // 排序
|
|
sourceURL: undefined, // 视频链接
|
|
status: 1, // 状态 1:开启;2:关闭
|
|
type: 1, // 类型
|
|
url: undefined, // 链接
|
|
},
|
|
attrs: {
|
|
accept: [
|
|
".mp4",
|
|
".qlv",
|
|
".qsv",
|
|
".ogg",
|
|
".flv",
|
|
".avi",
|
|
".wmv",
|
|
".rmvb",
|
|
], // 接受文件类型
|
|
},
|
|
};
|
|
},
|
|
computed: {
|
|
options() {
|
|
return {
|
|
target: baseConfig.baseServerUrl + "/vid/uploadDotStream", // 上传地址
|
|
testChunks: false, // 是否开启服务器分片校验
|
|
method: "application/json",
|
|
headers: {
|
|
// 额外请求头
|
|
Authorization: local.get("userInfo")
|
|
? local.get("userInfo").token
|
|
: "",
|
|
},
|
|
fileParameterName: "upload", // 文件名参数,默认为file
|
|
query: this.uploadQuery, // 额外参数
|
|
singleFile: true, // 单文件上传
|
|
chunkSize: 2048000, // 分片大小,默认1M
|
|
simultaneousUploads: 6,
|
|
// 把英文时间转成中文
|
|
parseTimeRemaining: function(timeRemaining, parsedTimeRemaining) {
|
|
return parsedTimeRemaining
|
|
.replace(/\syears?/, "年")
|
|
.replace(/\days?/, "天")
|
|
.replace(/\shours?/, "小时")
|
|
.replace(/\sminutes?/, "分钟")
|
|
.replace(/\sseconds?/, "秒");
|
|
},
|
|
};
|
|
},
|
|
},
|
|
created() {
|
|
this.getList();
|
|
},
|
|
methods: {
|
|
// 头像上传成功
|
|
uploadPortrait(res) {
|
|
this.form.cover = res.data.coverImg;
|
|
},
|
|
handlePictureCardPreview(file) {
|
|
this.dialogImageUrl = file.url;
|
|
this.dialogVisiblePreview = true;
|
|
},
|
|
getList(type) {
|
|
if (type === "status") {
|
|
this.params.pageNumber = 1;
|
|
}
|
|
API.getAdvanceConfigList(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;
|
|
});
|
|
},
|
|
// 视频上传成功时回调函数
|
|
// eslint-disable-next-line no-unused-vars
|
|
onFileSuccess(rootFile, file, response, chunk) {
|
|
const res = JSON.parse(response);
|
|
this.form.sourceURL = res.data.sourceURL;
|
|
//通知文件服务器, 上传完成
|
|
API.uploadSuccess({ id: res.data.sourceID })
|
|
.then((res) => {
|
|
if (res.code !== 200) {
|
|
this.$message.error("通知失败!");
|
|
}
|
|
})
|
|
.catch(() => {
|
|
this.$message.error("通知异常!");
|
|
});
|
|
},
|
|
// 视频上传选中时
|
|
fileAdd() {
|
|
this.generateTaskId();
|
|
},
|
|
// 定义视频上传唯一标识符id
|
|
generateTaskId() {
|
|
const time = new Date().getTime();
|
|
this.trackId = time;
|
|
},
|
|
// 视频上传额外参数
|
|
uploadQuery(file, chunk) {
|
|
return {
|
|
pos: chunk.offset,
|
|
id: String(this.trackId),
|
|
};
|
|
},
|
|
// 视频查看
|
|
checkMedia(url, type, data) {
|
|
this.$refs.previewVideo.open(url, type, data);
|
|
},
|
|
// 新增
|
|
addAndEdit(param) {
|
|
this.showUploadVideo = true;
|
|
if (param === "add") {
|
|
this.dialogTitle = "新增";
|
|
} else {
|
|
this.dialogTitle = "编辑";
|
|
// 把数据回显给表单
|
|
this.form.id = param.id;
|
|
this.form.name = param.name;
|
|
this.form.cover = param.cover;
|
|
this.form.sourceURL = param.sourceURL;
|
|
this.form.type = param.type;
|
|
this.form.sortCode = param.sortCode;
|
|
this.form.status = param.status;
|
|
this.form.url = param.url;
|
|
}
|
|
this.dialogVisible = true; // 打开新增、编辑对话框
|
|
},
|
|
// 新增、修改提交
|
|
onSubmit() {
|
|
if (this.dialogTitle === "新增") {
|
|
this.add();
|
|
} else {
|
|
this.edit();
|
|
}
|
|
},
|
|
// 新增方法
|
|
add() {
|
|
this.$refs["form"].validate((valid) => {
|
|
if (valid) {
|
|
API.addAdvanceConfig(this.form).then((res) => {
|
|
if (res.code === 200) {
|
|
this.$message({
|
|
type: "success",
|
|
message: "新增成功",
|
|
});
|
|
this.handleClose();
|
|
this.getList();
|
|
} else {
|
|
this.$message({
|
|
type: "error",
|
|
message: "新增失败",
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
// 修改方法
|
|
edit() {
|
|
this.$refs["form"].validate((valid) => {
|
|
if (valid) {
|
|
API.updateAdvanceConfig(this.form).then((res) => {
|
|
if (res.code === 200) {
|
|
this.$message({
|
|
type: "success",
|
|
message: "编辑成功",
|
|
});
|
|
this.handleClose();
|
|
this.getList();
|
|
} else {
|
|
this.$message({
|
|
type: "error",
|
|
message: "编辑失败",
|
|
});
|
|
}
|
|
});
|
|
} 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.delAdvanceConfig(delData).then((res) => {
|
|
if (res.code === 200) {
|
|
this.$message({
|
|
type: "success",
|
|
message: "删除成功!",
|
|
});
|
|
} else {
|
|
this.$message({
|
|
type: "error",
|
|
message: "删除失败!",
|
|
});
|
|
}
|
|
this.getList();
|
|
});
|
|
})
|
|
.catch(() => {
|
|
this.$message({
|
|
type: "info",
|
|
message: "已取消删除",
|
|
});
|
|
});
|
|
},
|
|
// 关闭窗口清除数据
|
|
handleClose() {
|
|
this.form.id = undefined;
|
|
this.form.name = undefined;
|
|
this.form.cover = undefined;
|
|
this.form.type = 1;
|
|
this.form.sourceURL = undefined;
|
|
this.form.url = undefined;
|
|
this.form.sortCode = 0;
|
|
this.form.status = 1;
|
|
this.showUploadVideo = false;
|
|
this.dialogVisible = false;
|
|
},
|
|
// 分页条数改变回调
|
|
changeSize(size) {
|
|
this.params.pageSize = size;
|
|
this.getList();
|
|
},
|
|
// 分页页码改变回调
|
|
changeCurrent(pageNumber) {
|
|
this.params.pageNumber = pageNumber;
|
|
this.getList();
|
|
},
|
|
// 更换时间格式
|
|
changeTime(time) {
|
|
return uniteDate(time);
|
|
},
|
|
},
|
|
};
|
|
</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%;
|
|
}
|
|
::v-deep .el-date-editor.el-input,
|
|
.el-date-editor.el-input__inner {
|
|
width: 100%;
|
|
}
|
|
::v-deep .el-upload-list--picture-card .el-upload-list__item {
|
|
width: 120px;
|
|
height: 120px;
|
|
}
|
|
::v-deep .el-upload--picture-card {
|
|
width: 120px;
|
|
height: 120px;
|
|
line-height: 130px;
|
|
}
|
|
</style>
|