Merge branch 'projects/mesxc-test' into projects/mesxc-zhp
@@ -1,290 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号接入" url="https://doc.iocoder.cn/mp/account/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入名称" clearable
|
||||
@keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['mp:account:create']">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="名称" align="center" prop="name"/>
|
||||
<el-table-column label="微信号" align="center" prop="account" width="180"/>
|
||||
<el-table-column label="appId" align="center" prop="appId" width="180"/>
|
||||
<!-- <el-table-column label="appSecret" align="center" prop="appSecret" width="180"/>-->
|
||||
<!-- <el-table-column label="token" align="center" prop="token"/>-->
|
||||
<!-- <el-table-column label="消息加解密密钥" align="center" prop="aesKey"/>-->
|
||||
<el-table-column label="服务器地址(URL)" align="center" prop="appId" width="360">
|
||||
<template v-slot="scope">
|
||||
{{ 'http://服务端地址/mp/open/' + scope.row.appId }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="二维码" align="center" prop="qrCodeUrl">
|
||||
<template v-slot="scope">
|
||||
<img v-if="scope.row.qrCodeUrl" :src="scope.row.qrCodeUrl" alt="二维码" style="height: 100px;" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark"/>
|
||||
<!-- <el-table-column label="创建时间" align="center" prop="createTime" width="180">-->
|
||||
<!-- <template v-slot="scope">-->
|
||||
<!-- <span>{{ parseTime(scope.row.createTime) }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['mp:account:update']">修改
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mp:account:delete']">删除
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleGenerateQrCode(scope.row)"
|
||||
v-hasPermi="['mp:account:qr-code']">生成二维码
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-share" @click="handleCleanQuota(scope.row)"
|
||||
v-hasPermi="['mp:account:clear-quota']">清空 API 配额
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入名称"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="微信号" prop="account">
|
||||
<span slot="label">
|
||||
<el-tooltip content="在微信公众平台(mp.weixin.qq.com)的菜单 [设置与开发 - 公众号设置 - 账号详情] 中能找到「微信号」" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
微信号
|
||||
</span>
|
||||
<el-input v-model="form.account" placeholder="请输入微信号"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="appId" prop="appId">
|
||||
<span slot="label">
|
||||
<el-tooltip content="在微信公众平台(mp.weixin.qq.com)的菜单 [设置与开发 - 公众号设置 - 基本设置] 中能找到「开发者ID(AppID)」" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
appId
|
||||
</span>
|
||||
<el-input v-model="form.appId" placeholder="请输入公众号 appId"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="appSecret" prop="appSecret">
|
||||
<span slot="label">
|
||||
<el-tooltip content="在微信公众平台(mp.weixin.qq.com)的菜单 [设置与开发 - 公众号设置 - 基本设置] 中能找到「开发者密码(AppSecret)」" placement="top">
|
||||
<i class="el-icon-question" />
|
||||
</el-tooltip>
|
||||
appSecret
|
||||
</span>
|
||||
<el-input v-model="form.appSecret" placeholder="请输入公众号 appSecret"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="token" prop="token">
|
||||
<el-input v-model="form.token" placeholder="请输入公众号token"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="消息加解密密钥" prop="aesKey">
|
||||
<el-input v-model="form.aesKey" placeholder="请输入消息加解密密钥"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
clearAccountQuota,
|
||||
createAccount,
|
||||
deleteAccount,
|
||||
generateAccountQrCode,
|
||||
getAccount,
|
||||
getAccountPage,
|
||||
updateAccount
|
||||
} from '@/api/mp/account'
|
||||
|
||||
export default {
|
||||
name: 'MpAccount',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 公众号账号列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: '',
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
account: null,
|
||||
appId: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [{required: true, message: '名称不能为空', trigger: 'blur'}],
|
||||
account: [{required: true, message: '公众号账号不能为空', trigger: 'blur'}],
|
||||
appId: [{required: true, message: '公众号 appId 不能为空', trigger: 'blur'}],
|
||||
appSecret: [{required: true, message: '公众号密钥不能为空', trigger: 'blur'}],
|
||||
token: [{required: true, message: '公众号 token 不能为空', trigger: 'blur'}],
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams}
|
||||
// 执行查询
|
||||
getAccountPage(params).then(response => {
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
account: undefined,
|
||||
appId: undefined,
|
||||
appSecret: undefined,
|
||||
token: undefined,
|
||||
aesKey: undefined,
|
||||
remark: undefined,
|
||||
}
|
||||
this.resetForm('form')
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRangeCreateTime = []
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = '添加公众号账号'
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id
|
||||
getAccount(id).then(response => {
|
||||
this.form = response.data
|
||||
this.open = true
|
||||
this.title = '修改公众号账号'
|
||||
})
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateAccount(this.form).then(response => {
|
||||
this.$modal.msgSuccess('修改成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
return
|
||||
}
|
||||
// 添加的提交
|
||||
createAccount(this.form).then(response => {
|
||||
this.$modal.msgSuccess('新增成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id
|
||||
this.$modal.confirm('是否确认删除公众号账号编号为"' + row.name + '"的数据项?').then(function () {
|
||||
return deleteAccount(id)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
/** 生成二维码的按钮操作 */
|
||||
handleGenerateQrCode(row) {
|
||||
const id = row.id
|
||||
this.$modal.confirm('是否确认生成公众号账号编号为"' + row.name + '"的二维码?').then(function () {
|
||||
return generateAccountQrCode(id)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess('生成二维码成功')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
/** 清空二维码 API 配额的按钮操作 */
|
||||
handleCleanQuota(row) {
|
||||
const id = row.id
|
||||
this.$modal.confirm('是否确认清空生成公众号账号编号为"' + row.name + '"的 API 配额?').then(function () {
|
||||
return clearAccountQuota(id)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('清空 API 配额成功')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,384 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.joolun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
芋道源码:
|
||||
① 移除 avue 框架,使用 element-ui 重写
|
||||
② 重写代码,保持和现有项目保持一致
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="自动回复" url="https://doc.iocoder.cn/mp/auto-reply/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- tab 切换 -->
|
||||
<el-tabs v-model="type" @tab-click="handleClick">
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['mp:auto-reply:create']" v-if="type !== '1' || list.length <= 0">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
<!-- tab 项 -->
|
||||
<el-tab-pane name="1">
|
||||
<span slot="label"><i class="el-icon-star-off"></i> 关注时回复</span>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2">
|
||||
<span slot="label"><i class="el-icon-chat-line-round"></i> 消息回复</span>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3">
|
||||
<span slot="label"><i class="el-icon-news"></i> 关键词回复</span>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="请求消息类型" align="center" prop="requestMessageType" v-if="type === '2'" />
|
||||
<el-table-column label="关键词" align="center" prop="requestKeyword" v-if="type === '3'" />
|
||||
<el-table-column label="匹配类型" align="center" prop="requestMatch" v-if="type === '3'">
|
||||
<template v-slot="scope">
|
||||
<dict-tag :type="DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH" :value="scope.row.requestMatch"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复消息类型" align="center">
|
||||
<template v-slot="scope">
|
||||
<dict-tag :type="DICT_TYPE.MP_MESSAGE_TYPE" :value="scope.row.responseMessageType"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复内容" align="center">
|
||||
<template v-slot="scope">
|
||||
<div v-if="scope.row.responseMessageType === 'text'">{{ scope.row.responseContent }}</div>
|
||||
<div v-else-if="scope.row.responseMessageType === 'voice'">
|
||||
<wx-voice-player :url="scope.row.responseMediaUrl" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.responseMessageType === 'image'">
|
||||
<a target="_blank" :href="scope.row.responseMediaUrl">
|
||||
<img :src="scope.row.responseMediaUrl" style="width: 100px">
|
||||
</a>
|
||||
</div>
|
||||
<div v-else-if="scope.row.responseMessageType === 'video' || scope.row.responseMessageType === 'shortvideo'">
|
||||
<wx-video-player :url="scope.row.responseMediaUrl" style="margin-top: 10px" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.responseMessageType === 'news'">
|
||||
<wx-news :articles="scope.row.responseArticles" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.responseMessageType === 'music'">
|
||||
<wx-music :title="scope.row.responseTitle" :description="scope.row.responseDescription"
|
||||
:thumb-media-url="scope.row.responseThumbMediaUrl"
|
||||
:music-url="scope.row.responseMusicUrl" :hq-music-url="scope.row.responseHqMusicUrl" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['mp:auto-reply:update']">修改
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mp:auto-reply:delete']">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改自动回复的对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="消息类型" prop="requestMessageType" v-if="type === '2'">
|
||||
<el-select v-model="form.requestMessageType" placeholder="请选择">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_MESSAGE_TYPE)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"
|
||||
v-if="requestMessageTypes.includes(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="匹配类型" prop="requestMatch" v-if="type === '3'">
|
||||
<el-select v-model="form.requestMatch" placeholder="请选择匹配类型" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
|
||||
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键词" prop="requestKeyword" v-if="type === '3'">
|
||||
<el-input v-model="form.requestKeyword" placeholder="请输入内容" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="回复消息">
|
||||
<wx-reply-select :objData="objData" v-if="hackResetWxReplySelect" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxMsg from '@/views/mp/components/wx-msg/main.vue';
|
||||
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
||||
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
import { createAutoReply, deleteAutoReply, getAutoReply, getAutoReplyPage, updateAutoReply } from "@/api/mp/autoReply";
|
||||
|
||||
export default {
|
||||
name: 'MpAutoReply',
|
||||
components: {
|
||||
WxVideoPlayer,
|
||||
WxVoicePlayer,
|
||||
WxMsg,
|
||||
WxLocation,
|
||||
WxMusic,
|
||||
WxNews,
|
||||
WxReplySelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// tab 类型(1、关注时回复;2、消息回复;3、关键词回复)
|
||||
type: '3',
|
||||
// 允许选择的请求消息类型
|
||||
requestMessageTypes: ['text', 'image', 'voice', 'video', 'shortvideo', 'location', 'link'],
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 自动回复列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: undefined,
|
||||
},
|
||||
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 回复消息
|
||||
objData: {
|
||||
type : 'text'
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
requestKeyword: [{ required: true, message: "请求的关键字不能为空", trigger: "blur" }],
|
||||
requestMatch: [{ required: true, message: "请求的关键字的匹配不能为空", trigger: "blur" }],
|
||||
},
|
||||
hackResetWxReplySelect: false, // 重置 WxReplySelect 组件,解决无法清除的问题
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询自动回复')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
// 处理查询参数
|
||||
let params = {
|
||||
...this.queryParams,
|
||||
type: this.type
|
||||
}
|
||||
// 执行查询
|
||||
getAutoReplyPage(params).then(response => {
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
handleClick(tab, event) {
|
||||
this.type = tab.name
|
||||
this.handleQuery()
|
||||
},
|
||||
|
||||
/** 新增按钮操作 */
|
||||
handleAdd(){
|
||||
this.reset();
|
||||
this.resetEditor();
|
||||
// 打开表单,并设置初始化
|
||||
this.open = true
|
||||
this.title = '新增自动回复';
|
||||
this.objData = {
|
||||
type : 'text',
|
||||
accountId: this.queryParams.accountId,
|
||||
}
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
this.resetEditor();
|
||||
const id = row.id;
|
||||
getAutoReply(id).then(response => {
|
||||
// 设置属性
|
||||
this.form = {...response.data}
|
||||
this.$delete(this.form, 'responseMessageType');
|
||||
this.$delete(this.form, 'responseContent');
|
||||
this.$delete(this.form, 'responseMediaId');
|
||||
this.$delete(this.form, 'responseMediaUrl');
|
||||
this.$delete(this.form, 'responseDescription');
|
||||
this.$delete(this.form, 'responseArticles');
|
||||
this.objData = {
|
||||
type: response.data.responseMessageType,
|
||||
accountId: this.queryParams.accountId,
|
||||
content: response.data.responseContent,
|
||||
mediaId: response.data.responseMediaId,
|
||||
url: response.data.responseMediaUrl,
|
||||
title: response.data.responseTitle,
|
||||
description: response.data.responseDescription,
|
||||
thumbMediaId: response.data.responseThumbMediaId,
|
||||
thumbMediaUrl: response.data.responseThumbMediaUrl,
|
||||
articles: response.data.responseArticles,
|
||||
musicUrl: response.data.responseMusicUrl,
|
||||
hqMusicUrl: response.data.responseHqMusicUrl,
|
||||
}
|
||||
|
||||
// 打开表单
|
||||
this.open = true
|
||||
this.title = '修改自动回复';
|
||||
})
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 处理回复消息
|
||||
const form = {...this.form};
|
||||
form.responseMessageType = this.objData.type;
|
||||
form.responseContent = this.objData.content;
|
||||
form.responseMediaId = this.objData.mediaId;
|
||||
form.responseMediaUrl = this.objData.url;
|
||||
form.responseTitle = this.objData.title;
|
||||
form.responseDescription = this.objData.description;
|
||||
form.responseThumbMediaId = this.objData.thumbMediaId;
|
||||
form.responseThumbMediaUrl = this.objData.thumbMediaUrl;
|
||||
form.responseArticles = this.objData.articles;
|
||||
form.responseMusicUrl = this.objData.musicUrl;
|
||||
form.responseHqMusicUrl = this.objData.hqMusicUrl;
|
||||
|
||||
if (this.form.id !== undefined) {
|
||||
updateAutoReply(form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
createAutoReply(form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
accountId: this.queryParams.accountId,
|
||||
type: this.type,
|
||||
requestKeyword: undefined,
|
||||
requestMatch: this.type === '3' ? 1 : undefined,
|
||||
requestMessageType: undefined,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单 Editor 重置
|
||||
resetEditor() {
|
||||
this.hackResetWxReplySelect = false // 销毁组件
|
||||
this.$nextTick(() => {
|
||||
this.hackResetWxReplySelect = true // 重建组件
|
||||
})
|
||||
},
|
||||
handleDelete: function(row) {
|
||||
const ids = row.id;
|
||||
this.$modal.confirm('是否确认删除此数据?').then(function() {
|
||||
return deleteAutoReply(ids);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,230 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
芋道源码:
|
||||
① 调整 uploadData 属性,只需要传入 accountId 即可
|
||||
-->
|
||||
<template>
|
||||
<div id="wxEditor">
|
||||
<div v-loading="quillUpdateImg" element-loading-text="请稍等,图片上传中">
|
||||
<!-- 图片上传组件辅助-->
|
||||
<el-upload class="avatar-uploader" name="file" :action="actionUrl" :headers="headers"
|
||||
:show-file-list="false" :data="uploadData"
|
||||
:on-success="uploadSuccess" :on-error="uploadError" :before-upload="beforeUpload">
|
||||
</el-upload>
|
||||
<quill-editor class="editor" v-model="content" ref="myQuillEditor" :options="editorOption"
|
||||
@change="onEditorChange($event)">
|
||||
</quill-editor>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 工具栏配置
|
||||
const toolbarOptions = [
|
||||
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
|
||||
["blockquote", "code-block"], // 引用 代码块
|
||||
[{ header: 1 }, { header: 2 }], // 1、2 级标题
|
||||
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
|
||||
[{ script: "sub" }, { script: "super" }], // 上标/下标
|
||||
[{ indent: "-1" }, { indent: "+1" }], // 缩进
|
||||
// [{'direction': 'rtl'}], // 文本方向
|
||||
[{ size: ["small", false, "large", "huge"] }], // 字体大小
|
||||
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
|
||||
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
|
||||
[{ font: [] }], // 字体种类
|
||||
[{ align: [] }], // 对齐方式
|
||||
["clean"], // 清除文本格式
|
||||
["link", "image", "video"] // 链接、图片、视频
|
||||
]
|
||||
|
||||
import { quillEditor } from "vue-quill-editor"
|
||||
import "quill/dist/quill.core.css"
|
||||
import "quill/dist/quill.snow.css"
|
||||
import "quill/dist/quill.bubble.css"
|
||||
import { getAccessToken } from "@/utils/auth";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
/* 公众号账号编号 */
|
||||
accountId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
/* 编辑器的内容 */
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
/* 图片大小 */
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 4000 // kb
|
||||
}
|
||||
},
|
||||
name: 'wxEditor',
|
||||
components: {
|
||||
quillEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editorType: '1',
|
||||
content: this.value.replace(/data-src/g, "src"),
|
||||
|
||||
quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
|
||||
editorOption: {
|
||||
theme: "snow", // or 'bubble'
|
||||
placeholder: "请输入文章内容",
|
||||
modules: {
|
||||
toolbar: {
|
||||
container: toolbarOptions,
|
||||
// container: "#toolbar",
|
||||
handlers: {
|
||||
image: function(value) {
|
||||
if (value) {
|
||||
// 触发input框选择图片文件
|
||||
document.querySelector(".avatar-uploader input").click();
|
||||
} else {
|
||||
this.quill.format("image", false);
|
||||
}
|
||||
},
|
||||
link: function(value) {
|
||||
if (value) {
|
||||
const href = prompt('注意!只支持公众号图文链接');
|
||||
this.quill.format("link", href);
|
||||
} else {
|
||||
this.quill.format("link", false);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actionUrl: process.env.VUE_APP_BASE_API +'/admin-api/mp/material/upload-news-image', // 这里写你要上传的图片服务器地址
|
||||
headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
|
||||
uploadData: {
|
||||
"type": 'image', // TODO 芋艿:试试要不要换成 thumb
|
||||
"accountId": this.accountId,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onEditorChange(editor) {
|
||||
//内容改变事件
|
||||
this.$emit("input", this.content)
|
||||
},
|
||||
|
||||
// 富文本图片上传前
|
||||
beforeUpload() {
|
||||
// 显示 loading 动画
|
||||
this.quillUpdateImg = true
|
||||
},
|
||||
|
||||
// 图片上传成功
|
||||
// 注意!由于微信公众号的图片有访问限制,所以会显示“此图片来自微信公众号,未经允许不可引用”
|
||||
uploadSuccess(res, file) {
|
||||
// res为图片服务器返回的数据
|
||||
// 获取富文本组件实例
|
||||
let quill = this.$refs.myQuillEditor.quill
|
||||
// 如果上传成功
|
||||
const link = res.data
|
||||
if (link){
|
||||
// 获取光标所在位置
|
||||
let length = quill.getSelection().index;
|
||||
// 插入图片 res.info为服务器返回的图片地址
|
||||
quill.insertEmbed(length, 'image', link)
|
||||
// 调整光标到最后
|
||||
quill.setSelection(length + 1)
|
||||
} else {
|
||||
this.$message.error('图片插入失败')
|
||||
}
|
||||
// loading 动画消失
|
||||
this.quillUpdateImg = false;
|
||||
},
|
||||
// 富文本图片上传失败
|
||||
uploadError() {
|
||||
// loading 动画消失
|
||||
this.quillUpdateImg = false;
|
||||
this.$message.error("图片插入失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.editor {
|
||||
line-height: normal !important;
|
||||
height: 500px;
|
||||
}
|
||||
.ql-snow .ql-tooltip[data-mode=link]::before {
|
||||
content: "请输入链接地址:";
|
||||
}
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0;
|
||||
content: '保存';
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode=video]::before {
|
||||
content: "请输入视频地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: '14px';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
|
||||
content: '10px';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
|
||||
content: '18px';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
|
||||
content: '32px';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: '文本';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: '标题1';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: '标题2';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: '标题3';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: '标题4';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: '标题5';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: '标题6';
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: '标准字体';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
|
||||
content: '衬线字体';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
|
||||
content: '等宽字体';
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<!--
|
||||
【微信消息 - 定位】
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<el-link type="primary" target="_blank" :href="'https://map.qq.com/?type=marker&isopeninfowin=1&markertype=1&pointx=' + locationY + '&pointy=' + locationX + '&name=' + label + '&ref=yudao'">
|
||||
<img :src="'https://apis.map.qq.com/ws/staticmap/v2/?zoom=10&markers=color:blue|label:A|' + locationX + ',' + locationY + '&key=' + qqMapKey + '&size=250*180'">
|
||||
<p/><i class="el-icon-map-location"></i>{{label}}
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "wxLocation",
|
||||
props: {
|
||||
locationX: {
|
||||
required: true,
|
||||
type: Number
|
||||
},
|
||||
locationY: {
|
||||
required: true,
|
||||
type: Number
|
||||
},
|
||||
label: { // 地名
|
||||
required: true,
|
||||
type: String
|
||||
},
|
||||
qqMapKey: { // QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
|
||||
required: false,
|
||||
type: String,
|
||||
default: 'TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E' // 需要自定义
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,247 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
芋道源码:
|
||||
① 移除 avue 组件,使用 ElementUI 原生组件
|
||||
-->
|
||||
<template>
|
||||
<!-- 类型:图片 -->
|
||||
<div v-if="objData.type === 'image'">
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div class="waterfall-item" v-for="item in list" :key="item.mediaId">
|
||||
<img class="material-img" :src="item.url">
|
||||
<p class="item-name">{{item.name}}</p>
|
||||
<el-row class="ope-row">
|
||||
<el-button size="mini" type="success" @click="selectMaterial(item)">选择
|
||||
<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getMaterialPage"/>
|
||||
</div>
|
||||
<!-- 类型:语音 -->
|
||||
<div v-else-if="objData.type === 'voice'">
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
<el-table-column label="文件名" align="center" prop="name" />
|
||||
<el-table-column label="语音" align="center">
|
||||
<template v-slot="scope">
|
||||
<wx-voice-player :url="scope.row.url" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-circle-plus"
|
||||
@click="selectMaterial(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getPage"/>
|
||||
</div>
|
||||
<div v-else-if="objData.type === 'video'">
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
<el-table-column label="文件名" align="center" prop="name" />
|
||||
<el-table-column label="标题" align="center" prop="title" />
|
||||
<el-table-column label="介绍" align="center" prop="introduction" />
|
||||
<el-table-column label="视频" align="center">
|
||||
<template v-slot="scope">
|
||||
<wx-video-player :url="scope.row.url" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-circle-plus"
|
||||
@click="selectMaterial(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getMaterialPage"/>
|
||||
</div>
|
||||
<div v-else-if="objData.type === 'news'">
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div class="waterfall-item" v-for="item in list" :key="item.mediaId" v-if="item.content && item.content.newsItem">
|
||||
<wx-news :articles="item.content.newsItem" />
|
||||
<el-row class="ope-row">
|
||||
<el-button size="mini" type="success" @click="selectMaterial(item)">
|
||||
选择<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getMaterialPage"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
import { getMaterialPage } from "@/api/mp/material";
|
||||
import { getFreePublishPage } from "@/api/mp/freePublish";
|
||||
import { getDraftPage } from "@/api/mp/draft";
|
||||
|
||||
export default {
|
||||
name: "wxMaterialSelect",
|
||||
components: {
|
||||
WxNews,
|
||||
WxVoicePlayer,
|
||||
WxVideoPlayer
|
||||
},
|
||||
props: {
|
||||
objData: {
|
||||
type: Object, // type - 类型;accountId - 公众号账号编号
|
||||
required: true
|
||||
},
|
||||
newsType:{ // 图文类型:1、已发布图文;2、草稿箱图文
|
||||
type: String,
|
||||
default: "1"
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 数据列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: this.objData.accountId,
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPage()
|
||||
},
|
||||
methods:{
|
||||
selectMaterial(item) {
|
||||
this.$emit('selectMaterial', item)
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.getPage()
|
||||
},
|
||||
getPage() {
|
||||
this.loading = true
|
||||
if (this.objData.type === 'news' && this.newsType === '1') { // 【图文】+ 【已发布】
|
||||
this.getFreePublishPage();
|
||||
} else if (this.objData.type === 'news' && this.newsType === '2') { // 【图文】+ 【草稿】
|
||||
this.getDraftPage();
|
||||
} else { // 【素材】
|
||||
this.getMaterialPage();
|
||||
}
|
||||
},
|
||||
getMaterialPage() {
|
||||
getMaterialPage({
|
||||
...this.queryParams,
|
||||
type: this.objData.type
|
||||
}).then(response => {
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getFreePublishPage() {
|
||||
getFreePublishPage(this.queryParams).then(response => {
|
||||
// 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
|
||||
response.data.list.forEach(item => {
|
||||
const newsItem = item.content.newsItem;
|
||||
newsItem.forEach(article => {
|
||||
article.picUrl = article.thumbUrl;
|
||||
})
|
||||
})
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getDraftPage() {
|
||||
getDraftPage((this.queryParams)).then(response => {
|
||||
// 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
|
||||
response.data.list.forEach(item => {
|
||||
const newsItem = item.content.newsItem;
|
||||
newsItem.forEach(article => {
|
||||
article.picUrl = article.thumbUrl;
|
||||
})
|
||||
})
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/*瀑布流样式*/
|
||||
.waterfall {
|
||||
width: 100%;
|
||||
column-gap:10px;
|
||||
column-count: 5;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.waterfall-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
break-inside: avoid;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.material-img {
|
||||
width: 100%;
|
||||
}
|
||||
p {
|
||||
line-height: 30px;
|
||||
}
|
||||
@media (min-width: 992px) and (max-width: 1300px) {
|
||||
.waterfall {
|
||||
column-count: 3;
|
||||
}
|
||||
p {
|
||||
color:red;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.waterfall {
|
||||
column-count: 2;
|
||||
}
|
||||
p {
|
||||
color: orange;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.waterfall {
|
||||
column-count: 1;
|
||||
}
|
||||
}
|
||||
/*瀑布流样式*/
|
||||
</style>
|
||||
@@ -1,101 +0,0 @@
|
||||
.avue-card{
|
||||
&__item{
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #e8e8e8;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
color: rgba(0,0,0,.65);
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5;
|
||||
list-style: none;
|
||||
font-feature-settings: "tnum";
|
||||
cursor: pointer;
|
||||
height:200px;
|
||||
&:hover{
|
||||
border-color: rgba(0,0,0,.09);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,.09);
|
||||
}
|
||||
&--add{
|
||||
border:1px dashed #000;
|
||||
width: 100%;
|
||||
color: rgba(0,0,0,.45);
|
||||
background-color: #fff;
|
||||
border-color: #d9d9d9;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
i{
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover{
|
||||
color: #40a9ff;
|
||||
background-color: #fff;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__body{
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
}
|
||||
&__detail{
|
||||
flex:1
|
||||
}
|
||||
&__avatar{
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 48px;
|
||||
overflow: hidden;
|
||||
margin-right: 12px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
&__title{
|
||||
color: rgba(0,0,0,.85);
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
&:hover{
|
||||
color:#1890ff;
|
||||
}
|
||||
}
|
||||
&__info{
|
||||
color: rgba(0,0,0,.45);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
height: 64px;
|
||||
}
|
||||
&__menu{
|
||||
display: flex;
|
||||
justify-content:space-around;
|
||||
height: 50px;
|
||||
background: #f7f9fa;
|
||||
color: rgba(0,0,0,.45);
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
&:hover{
|
||||
color:#1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** joolun 额外加的 */
|
||||
.avue-comment__main {
|
||||
flex: unset!important;
|
||||
border-radius: 5px!important;
|
||||
margin: 0 8px!important;
|
||||
}
|
||||
.avue-comment__header {
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
.avue-comment__body {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/* 来自 https://github.com/nmxiaowei/avue/blob/master/styles/src/element-ui/comment.scss */
|
||||
.avue-comment{
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
&--reverse{
|
||||
flex-direction:row-reverse;
|
||||
.avue-comment__main{
|
||||
&:before,&:after{
|
||||
left: auto;
|
||||
right: -8px;
|
||||
border-width: 8px 0 8px 8px;
|
||||
}
|
||||
&:before{
|
||||
border-left-color: #dedede;
|
||||
}
|
||||
&:after{
|
||||
border-left-color: #f8f8f8;
|
||||
margin-right: 1px;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__avatar{
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
}
|
||||
&__header{
|
||||
padding: 5px 15px;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
&__author{
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
&__main{
|
||||
flex:1;
|
||||
margin: 0 20px;
|
||||
position: relative;
|
||||
border: 1px solid #dedede;
|
||||
border-radius: 2px;
|
||||
&:before,&:after{
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: -8px;
|
||||
right: 100%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
display: block;
|
||||
content: " ";
|
||||
border-color: transparent;
|
||||
border-style: solid solid outset;
|
||||
border-width: 8px 8px 8px 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
&:before {
|
||||
border-right-color: #dedede;
|
||||
z-index: 1;
|
||||
}
|
||||
&:after{
|
||||
border-right-color: #f8f8f8;
|
||||
margin-left: 1px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
&__body{
|
||||
padding: 15px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
font-family: Segoe UI,Lucida Grande,Helvetica,Arial,Microsoft YaHei,FreeSans,Arimo,Droid Sans,wenquanyi micro hei,Hiragino Sans GB,Hiragino Sans GB W3,FontAwesome,sans-serif;color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
blockquote{
|
||||
margin:0;
|
||||
font-family: Georgia,Times New Roman,Times,Kai,Kaiti SC,KaiTi,BiauKai,FontAwesome,serif;
|
||||
padding: 1px 0 1px 15px;
|
||||
border-left: 4px solid #ddd;
|
||||
}
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
芋道源码:
|
||||
① 移除暂时用不到的 websocket
|
||||
② 代码优化,补充注释,提升阅读性
|
||||
-->
|
||||
<template>
|
||||
<div class="msg-main">
|
||||
<div class="msg-div" :id="'msg-div' + nowStr">
|
||||
<!-- 加载更多 -->
|
||||
<div v-loading="loading"></div>
|
||||
<div v-if="!loading">
|
||||
<div class="el-table__empty-block" v-if="loadMore" @click="loadingMore"><span class="el-table__empty-text">点击加载更多</span></div>
|
||||
<div class="el-table__empty-block" v-if="!loadMore"><span class="el-table__empty-text">没有更多了</span></div>
|
||||
</div>
|
||||
<!-- 消息列表 -->
|
||||
<div class="execution" v-for="item in list" :key='item.id'>
|
||||
<div class="avue-comment" :class="item.sendFrom === 2 ? 'avue-comment--reverse' : ''">
|
||||
<div class="avatar-div">
|
||||
<img :src="item.sendFrom === 1 ? user.avatar : mp.avatar" class="avue-comment__avatar">
|
||||
<div class="avue-comment__author">{{item.sendFrom === 1 ? user.nickname : mp.nickname }}</div>
|
||||
</div>
|
||||
<div class="avue-comment__main">
|
||||
<div class="avue-comment__header">
|
||||
<div class="avue-comment__create_time">{{ parseTime(item.createTime) }}</div>
|
||||
</div>
|
||||
<div class="avue-comment__body" :style="item.sendFrom === 2 ? 'background: #6BED72;' : ''">
|
||||
<!-- 【事件】区域 -->
|
||||
<div v-if="item.type === 'event' && item.event === 'subscribe'">
|
||||
<el-tag type="success" size="mini">关注</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'unsubscribe'">
|
||||
<el-tag type="danger" size="mini">取消关注</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'CLICK'">
|
||||
<el-tag size="mini">点击菜单</el-tag>【{{ item.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'VIEW'">
|
||||
<el-tag size="mini">点击菜单链接</el-tag>【{{ item.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'scancode_waitmsg'">
|
||||
<el-tag size="mini">扫码结果</el-tag>【{{ item.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'scancode_push'">
|
||||
<el-tag size="mini">扫码结果</el-tag>【{{ item.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'pic_sysphoto'">
|
||||
<el-tag size="mini">系统拍照发图</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'pic_photo_or_album'">
|
||||
<el-tag size="mini">拍照或者相册</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'pic_weixin'">
|
||||
<el-tag size="mini">微信相册</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event' && item.event === 'location_select'">
|
||||
<el-tag size="mini">选择地理位置</el-tag>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'event'">
|
||||
<el-tag type="danger" size="mini">未知事件类型</el-tag>
|
||||
</div>
|
||||
<!-- 【消息】区域 -->
|
||||
<div v-else-if="item.type === 'text'">{{ item.content }}</div>
|
||||
<div v-else-if="item.type === 'voice'">
|
||||
<wx-voice-player :url="item.mediaUrl" :content="item.recognition" />
|
||||
</div>
|
||||
<div v-else-if="item.type === 'image'">
|
||||
<a target="_blank" :href="item.mediaUrl">
|
||||
<img :src="item.mediaUrl" style="width: 100px">
|
||||
</a>
|
||||
</div>
|
||||
<div v-else-if="item.type === 'video' || item.type === 'shortvideo'" style="text-align: center">
|
||||
<wx-video-player :url="item.mediaUrl" />
|
||||
</div>
|
||||
<div v-else-if="item.type === 'link'" class="avue-card__detail">
|
||||
<el-link type="success" :underline="false" target="_blank" :href="item.url">
|
||||
<div class="avue-card__title"><i class="el-icon-link"></i>{{ item.title }}</div>
|
||||
</el-link>
|
||||
<div class="avue-card__info" style="height: unset">{{item.description}}</div>
|
||||
</div>
|
||||
<!-- TODO 芋艿:待完善 -->
|
||||
<div v-else-if="item.type === 'location'">
|
||||
<wx-location :label="item.label" :location-y="item.locationY" :location-x="item.locationX" />
|
||||
</div>
|
||||
<div v-else-if="item.type === 'news'" style="width: 300px"> <!-- TODO 芋艿:待测试;详情页也存在类似的情况 -->
|
||||
<wx-news :articles="item.articles" />
|
||||
</div>
|
||||
<div v-else-if="item.type === 'music'">
|
||||
<wx-music :title="item.title" :description="item.description" :thumb-media-url="item.thumbMediaUrl"
|
||||
:music-url="item.musicUrl" :hq-music-url="item.hqMusicUrl" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msg-send" v-loading="sendLoading">
|
||||
<wx-reply-select ref="replySelect" :objData="objData" />
|
||||
<el-button type="success" size="small" class="send-but" @click="sendMsg">发送(S)</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMessagePage, sendMessage } from '@/api/mp/message'
|
||||
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
||||
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
||||
import { getUser } from "@/api/mp/mpuser";
|
||||
|
||||
export default {
|
||||
name: "wxMsg",
|
||||
components: {
|
||||
WxReplySelect,
|
||||
WxVideoPlayer,
|
||||
WxVoicePlayer,
|
||||
WxNews,
|
||||
WxLocation,
|
||||
WxMusic
|
||||
},
|
||||
props: {
|
||||
userId: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
nowStr: new Date().getTime(), // 当前的时间戳,用于每次消息加载后,回到原位置;具体见 :id="'msg-div' + nowStr" 处
|
||||
loading: false, // 消息列表是否正在加载中
|
||||
loadMore: true, // 是否可以加载更多
|
||||
list: [], // 消息列表
|
||||
queryParams: {
|
||||
pageNo: 1, // 当前页数
|
||||
pageSize: 14, // 每页显示多少条
|
||||
accountId: undefined,
|
||||
},
|
||||
user: { // 由于微信不再提供昵称,直接使用“用户”展示
|
||||
nickname: '用户',
|
||||
avatar: require("@/assets/images/profile.jpg"),
|
||||
accountId: 0, // 公众号账号编号
|
||||
},
|
||||
mp: {
|
||||
nickname: '公众号',
|
||||
avatar: require("@/assets/images/wechat.png"),
|
||||
},
|
||||
|
||||
// ========= 消息发送 =========
|
||||
sendLoading: false, // 发送消息是否加载中
|
||||
objData: { // 微信发送消息
|
||||
type: 'text',
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 获得用户信息
|
||||
getUser(this.userId).then(response => {
|
||||
this.user.nickname = response.data.nickname && response.data.nickname.length > 0 ?
|
||||
response.data.nickname : this.user.nickname;
|
||||
this.user.avatar = response.data.avatar && this.user.avatar.length > 0 ?
|
||||
response.data.avatar : this.user.avatar;
|
||||
this.user.accountId = response.data.accountId;
|
||||
// 设置公众号账号编号
|
||||
this.queryParams.accountId = response.data.accountId;
|
||||
this.objData.accountId = response.data.accountId;
|
||||
|
||||
// 加载消息
|
||||
console.log(this.queryParams)
|
||||
this.refreshChange()
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
sendMsg(){
|
||||
if (!this.objData) {
|
||||
return;
|
||||
}
|
||||
// 公众号限制:客服消息,公众号只允许发送一条
|
||||
if (this.objData.type === 'news'
|
||||
&& this.objData.articles.length > 1) {
|
||||
this.objData.articles = [this.objData.articles[0]]
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '图文消息条数限制在 1 条以内,已默认发送第一条',
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
// 执行发送
|
||||
this.sendLoading = true
|
||||
sendMessage(Object.assign({
|
||||
userId: this.userId
|
||||
}, {
|
||||
...this.objData
|
||||
})).then(response => {
|
||||
this.sendLoading = false
|
||||
// 添加到消息列表,并滚动
|
||||
this.list = [...this.list , ...[response.data] ]
|
||||
this.scrollToBottom()
|
||||
// 重置 objData 状态
|
||||
this.$refs['replySelect'].deleteObj(); // 重置,避免 tab 的数据未清理
|
||||
}).catch(() => {
|
||||
this.sendLoading = false
|
||||
})
|
||||
},
|
||||
loadingMore() {
|
||||
this.queryParams.pageNo++
|
||||
this.getPage(this.queryParams)
|
||||
},
|
||||
getPage(page, params) {
|
||||
this.loading = true
|
||||
getMessagePage(Object.assign({
|
||||
pageNo: page.pageNo,
|
||||
pageSize: page.pageSize,
|
||||
userId: this.userId,
|
||||
accountId: page.accountId,
|
||||
}, params)).then(response => {
|
||||
// 计算当前的滚动高度
|
||||
const msgDiv = document.getElementById('msg-div' + this.nowStr);
|
||||
let scrollHeight = 0
|
||||
if(msgDiv){
|
||||
scrollHeight = msgDiv.scrollHeight
|
||||
}
|
||||
|
||||
// 处理数据
|
||||
const data = response.data.list.reverse();
|
||||
this.list = [...data, ...this.list]
|
||||
this.loading = false
|
||||
if (data.length < this.queryParams.pageSize || data.length === 0){
|
||||
this.loadMore = false
|
||||
}
|
||||
this.queryParams.pageNo = page.pageNo
|
||||
this.queryParams.pageSize = page.pageSize
|
||||
|
||||
// 滚动到原来的位置
|
||||
if(this.queryParams.pageNo === 1) { // 定位到消息底部
|
||||
this.scrollToBottom()
|
||||
} else if (data.length !== 0) { // 定位滚动条
|
||||
this.$nextTick(() => {
|
||||
if (scrollHeight !== 0){
|
||||
msgDiv.scrollTop = document.getElementById('msg-div'+this.nowStr).scrollHeight - scrollHeight - 100
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 刷新回调
|
||||
*/
|
||||
refreshChange() {
|
||||
this.getPage(this.queryParams)
|
||||
},
|
||||
/** 定位到消息底部 */
|
||||
scrollToBottom: function () {
|
||||
this.$nextTick(() => {
|
||||
let div = document.getElementById('msg-div' + this.nowStr)
|
||||
div.scrollTop = div.scrollHeight
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 comment.scss、card.scc */
|
||||
@import './comment.scss';
|
||||
@import './card.scss';
|
||||
|
||||
.msg-main {
|
||||
margin-top: -30px;
|
||||
padding: 10px;
|
||||
}
|
||||
.msg-div {
|
||||
height: 50vh;
|
||||
overflow: auto;
|
||||
background-color: #eaeaea;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.msg-send {
|
||||
padding: 10px;
|
||||
}
|
||||
.avatar-div {
|
||||
text-align: center;
|
||||
width: 80px;
|
||||
}
|
||||
.send-but {
|
||||
float: right;
|
||||
margin-top: 8px!important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<!--
|
||||
【微信消息 - 音乐】
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<el-link type="success" :underline="false" target="_blank" :href="hqMusicUrl ? hqMusicUrl : musicUrl">
|
||||
<div class="avue-card__body" style="padding:10px;background-color: #fff;border-radius: 5px">
|
||||
<div class="avue-card__avatar">
|
||||
<img :src="thumbMediaUrl" alt=""/>
|
||||
</div>
|
||||
<div class="avue-card__detail">
|
||||
<div class="avue-card__title" style="margin-bottom:unset">{{ title }}</div>
|
||||
<div class="avue-card__info" style="height: unset">{{ description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "wxMusic",
|
||||
props: {
|
||||
title: {
|
||||
required: false,
|
||||
type: String
|
||||
},
|
||||
description: {
|
||||
required: false,
|
||||
type: String
|
||||
},
|
||||
musicUrl: {
|
||||
required: false,
|
||||
type: String
|
||||
},
|
||||
hqMusicUrl: {
|
||||
required: false,
|
||||
type: String
|
||||
},
|
||||
thumbMediaUrl: {
|
||||
required: true,
|
||||
type: String
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 因为 joolun 实现依赖 avue 组件,该页面使用了 card.scc */
|
||||
@import '../wx-msg/card.scss';
|
||||
</style>
|
||||
@@ -1,104 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
【微信消息 - 图文】
|
||||
芋道源码:
|
||||
① 代码优化,补充注释,提升阅读性
|
||||
-->
|
||||
<template>
|
||||
<div class="news-home">
|
||||
<div v-for="(article, index) in articles" :key="index" class="news-div">
|
||||
<!-- 头条 -->
|
||||
<a target="_blank" :href="article.url" v-if="index === 0">
|
||||
<div class="news-main">
|
||||
<div class="news-content">
|
||||
<img class="material-img" :src="article.picUrl" width="280px" height="120px"/>
|
||||
<div class="news-content-title">
|
||||
<span>{{article.title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<!-- 二条/三条等等 -->
|
||||
<a target="_blank" :href="article.url" v-else>
|
||||
<div class="news-main-item">
|
||||
<div class="news-content-item">
|
||||
<div class="news-content-item-title">{{article.title}}</div>
|
||||
<div class="news-content-item-img">
|
||||
<img class="material-img" :src="article.picUrl" height="100%"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "wxNews",
|
||||
props: {
|
||||
articles: {
|
||||
type: Array // title - 标题;description - 描述;picUrl - 图片连接;url - 跳转链接
|
||||
}
|
||||
},
|
||||
// created() {
|
||||
// console.log(this.articles)
|
||||
// },
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-home {
|
||||
background-color: #FFFFFF;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.news-main {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.news-content {
|
||||
background-color: #acadae;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.news-content-title {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: black;
|
||||
width: 98%;
|
||||
padding: 1%;
|
||||
opacity: 0.65;
|
||||
white-space: normal;
|
||||
box-sizing: unset!important
|
||||
}
|
||||
.news-main-item {
|
||||
background-color: #FFFFFF;
|
||||
padding: 5px 0;
|
||||
border-top: 1px solid #eaeaea;
|
||||
}
|
||||
.news-content-item {
|
||||
position: relative;
|
||||
}
|
||||
.news-content-item-title {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
width: 70%;
|
||||
margin-left: 1%;
|
||||
white-space: normal
|
||||
}
|
||||
.news-content-item-img {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
background-color: #acadae;
|
||||
margin-right: 1%;
|
||||
}
|
||||
.material-img {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,547 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
芋道源码:
|
||||
① 移除多余的 rep 为前缀的变量,让 message 消息更简单
|
||||
② 代码优化,补充注释,提升阅读性
|
||||
③ 优化消息的临时缓存策略,发送消息时,只清理被发送消息的 tab,不会强制切回到 text 输入
|
||||
④ 支持发送【视频】消息时,支持新建视频
|
||||
-->
|
||||
<template>
|
||||
<el-tabs type="border-card" v-model="objData.type" @tab-click="handleClick">
|
||||
<!-- 类型 1:文本 -->
|
||||
<el-tab-pane name="text">
|
||||
<span slot="label"><i class="el-icon-document"></i> 文本</span>
|
||||
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="objData.content" @input="inputContent" />
|
||||
</el-tab-pane>
|
||||
<!-- 类型 2:图片 -->
|
||||
<el-tab-pane name="image">
|
||||
<span slot="label"><i class="el-icon-picture"></i> 图片</span>
|
||||
<el-row>
|
||||
<!-- 情况一:已经选择好素材、或者上传好图片 -->
|
||||
<div class="select-item" v-if="objData.url">
|
||||
<img class="material-img" :src="objData.url">
|
||||
<p class="item-name" v-if="objData.name">{{objData.name}}</p>
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="deleteObj"></el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 情况二:未做完上述操作 -->
|
||||
<div v-else>
|
||||
<el-row style="text-align: center">
|
||||
<!-- 选择素材 -->
|
||||
<el-col :span="12" class="col-select">
|
||||
<el-button type="success" @click="openMaterial">
|
||||
素材库选择<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dialog title="选择图片" :visible.sync="dialogImageVisible" width="90%" append-to-body>
|
||||
<wx-material-select :obj-data="objData" @selectMaterial="selectMaterial" />
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
<el-col :span="12" class="col-add">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeImageUpload" :on-success="handleUploadSuccess">
|
||||
<el-button type="primary">上传图片</el-button>
|
||||
<div slot="tip" class="el-upload__tip">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</div>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<!-- 类型 3:语音 -->
|
||||
<el-tab-pane name="voice">
|
||||
<span slot="label"><i class="el-icon-phone"></i> 语音</span>
|
||||
<el-row>
|
||||
<div class="select-item2" v-if="objData.url">
|
||||
<p class="item-name">{{objData.name}}</p>
|
||||
<div class="item-infos">
|
||||
<wx-voice-player :url="objData.url" />
|
||||
</div>
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="deleteObj"></el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-row style="text-align: center">
|
||||
<!-- 选择素材 -->
|
||||
<el-col :span="12" class="col-select">
|
||||
<el-button type="success" @click="openMaterial">
|
||||
素材库选择<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dialog title="选择语音" :visible.sync="dialogVoiceVisible" width="90%" append-to-body>
|
||||
<WxMaterialSelect :objData="objData" @selectMaterial="selectMaterial"></WxMaterialSelect>
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
<el-col :span="12" class="col-add">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeVoiceUpload" :on-success="handleUploadSuccess">
|
||||
<el-button type="primary">点击上传</el-button>
|
||||
<div slot="tip" class="el-upload__tip">格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s</div>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<!-- 类型 4:视频 -->
|
||||
<el-tab-pane name="video">
|
||||
<span slot="label"><i class="el-icon-share"></i> 视频</span>
|
||||
<el-row>
|
||||
<el-input v-model="objData.title" placeholder="请输入标题" @input="inputContent" />
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<el-input v-model="objData.description" placeholder="请输入描述" @input="inputContent" />
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<div style="text-align: center;">
|
||||
<wx-video-player v-if="objData.url" :url="objData.url" />
|
||||
</div>
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<el-row style="text-align: center">
|
||||
<!-- 选择素材 -->
|
||||
<el-col :span="12">
|
||||
<el-button type="success" @click="openMaterial">
|
||||
素材库选择<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dialog title="选择视频" :visible.sync="dialogVideoVisible" width="90%" append-to-body>
|
||||
<wx-material-select :objData="objData" @selectMaterial="selectMaterial" />
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<!-- 文件上传 -->
|
||||
<el-col :span="12">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeVideoUpload" :on-success="handleUploadSuccess">
|
||||
<el-button type="primary">新建视频<i class="el-icon-upload el-icon--right"></i></el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<!-- 类型 5:图文 -->
|
||||
<el-tab-pane name="news">
|
||||
<span slot="label"><i class="el-icon-news"></i> 图文</span>
|
||||
<el-row>
|
||||
<div class="select-item" v-if="objData.articles">
|
||||
<wx-news :articles="objData.articles" />
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="deleteObj" />
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 选择素材 -->
|
||||
<div v-if="!objData.content">
|
||||
<el-row style="text-align: center">
|
||||
<el-col :span="24">
|
||||
<el-button type="success" @click="openMaterial">{{newsType === '1' ? '选择已发布图文' : '选择草稿箱图文'}}<i class="el-icon-circle-check el-icon--right"></i></el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-dialog title="选择图文" :visible.sync="dialogNewsVisible" width="90%" append-to-body>
|
||||
<wx-material-select :objData="objData" @selectMaterial="selectMaterial" :newsType="newsType" />
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<!-- 类型 6:音乐 -->
|
||||
<el-tab-pane name="music">
|
||||
<span slot="label"><i class="el-icon-service"></i> 音乐</span>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<div class="thumb-div">
|
||||
<img style="width: 100px" v-if="objData.thumbMediaUrl" :src="objData.thumbMediaUrl">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
<div class="thumb-but">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeThumbImageUpload" :on-success="handleUploadSuccess">
|
||||
<el-button slot="trigger" size="mini" type="text">本地上传</el-button>
|
||||
<el-button size="mini" type="text" @click="openMaterial" style="margin-left: 5px">素材库选择</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog title="选择图片" :visible.sync="dialogThumbVisible" width="80%" append-to-body>
|
||||
<wx-material-select :objData="{type:'image', accountId: objData.accountId}" @selectMaterial="selectMaterial" />
|
||||
</el-dialog>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<el-input v-model="objData.title" placeholder="请输入标题" @input="inputContent" />
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<el-input v-model="objData.description" placeholder="请输入描述" @input="inputContent" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<el-input v-model="objData.musicUrl" placeholder="请输入音乐链接" @input="inputContent" />
|
||||
<div style="margin: 20px 0;"></div>
|
||||
<el-input v-model="objData.hqMusicUrl" placeholder="请输入高质量音乐链接" @input="inputContent" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue'
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
name: "wxReplySelect",
|
||||
components: {
|
||||
WxNews,
|
||||
WxMaterialSelect,
|
||||
WxVoicePlayer,
|
||||
WxVideoPlayer
|
||||
},
|
||||
props: {
|
||||
objData: { // 消息对象。
|
||||
type: Object, // 设置为 Object 的原因,方便属性的传递
|
||||
required: true,
|
||||
},
|
||||
newsType:{ // 图文类型:1、已发布图文;2、草稿箱图文
|
||||
type: String,
|
||||
default: "1"
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tempPlayerObj: {
|
||||
type: '2'
|
||||
},
|
||||
|
||||
tempObj: new Map().set( // 临时缓存,切换消息类型的 tab 的时候,可以保存对应的数据;
|
||||
this.objData.type, // 消息类型
|
||||
Object.assign({}, this.objData)), // 消息内容
|
||||
|
||||
// ========== 素材选择的弹窗,是否可见 ==========
|
||||
dialogNewsVisible: false, // 图文
|
||||
dialogImageVisible: false, // 图片
|
||||
dialogVoiceVisible: false, // 语音
|
||||
dialogVideoVisible: false, // 视频
|
||||
dialogThumbVisible: false, // 缩略图
|
||||
|
||||
// ========== 文件上传(图片、语音、视频) ==========
|
||||
fileList: [], // 文件列表
|
||||
uploadData: {
|
||||
"accountId": undefined,
|
||||
"type": this.objData.type,
|
||||
"title":'',
|
||||
"introduction":''
|
||||
},
|
||||
actionUrl: process.env.VUE_APP_BASE_API + '/admin-api/mp/material/upload-temporary',
|
||||
headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
beforeThumbImageUpload(file){
|
||||
const isType = file.type === 'image/jpeg'
|
||||
|| file.type === 'image/png'
|
||||
|| file.type === 'image/gif'
|
||||
|| file.type === 'image/bmp'
|
||||
|| file.type === 'image/jpg';
|
||||
if (!isType) {
|
||||
this.$message.error('上传图片格式不对!');
|
||||
return false;
|
||||
}
|
||||
const isLt = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt) {
|
||||
this.$message.error('上传图片大小不能超过 2M!');
|
||||
return false;
|
||||
}
|
||||
this.uploadData.accountId = this.objData.accountId;
|
||||
return true;
|
||||
},
|
||||
beforeVoiceUpload(file){
|
||||
// 校验格式
|
||||
const isType = file.type === 'audio/mp3'
|
||||
|| file.type === 'audio/mpeg'
|
||||
|| file.type === 'audio/wma'
|
||||
|| file.type === 'audio/wav'
|
||||
|| file.type === 'audio/amr';
|
||||
if (!isType) {
|
||||
this.$message.error('上传语音格式不对!' + file.type);
|
||||
return false;
|
||||
}
|
||||
// 校验大小
|
||||
const isLt = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt) {
|
||||
this.$message.error('上传语音大小不能超过 2M!');
|
||||
return false;
|
||||
}
|
||||
this.uploadData.accountId = this.objData.accountId;
|
||||
return true;
|
||||
},
|
||||
beforeImageUpload(file) {
|
||||
// 校验格式
|
||||
const isType = file.type === 'image/jpeg'
|
||||
|| file.type === 'image/png'
|
||||
|| file.type === 'image/gif'
|
||||
|| file.type === 'image/bmp'
|
||||
|| file.type === 'image/jpg';
|
||||
if (!isType) {
|
||||
this.$message.error('上传图片格式不对!');
|
||||
return false;
|
||||
}
|
||||
// 校验大小
|
||||
const isLt = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt) {
|
||||
this.$message.error('上传图片大小不能超过 2M!');
|
||||
return false;
|
||||
}
|
||||
this.uploadData.accountId = this.objData.accountId;
|
||||
return true;
|
||||
},
|
||||
beforeVideoUpload(file){
|
||||
// 校验格式
|
||||
const isType = file.type === 'video/mp4';
|
||||
if (!isType) {
|
||||
this.$message.error('上传视频格式不对!');
|
||||
return false;
|
||||
}
|
||||
// 校验大小
|
||||
const isLt = file.size / 1024 / 1024 < 10;
|
||||
if (!isLt) {
|
||||
this.$message.error('上传视频大小不能超过 10M!');
|
||||
return false;
|
||||
}
|
||||
this.uploadData.accountId = this.objData.accountId;
|
||||
return true;
|
||||
},
|
||||
handleUploadSuccess(response, file, fileList) {
|
||||
if (response.code !== 0) {
|
||||
this.$message.error('上传出错:' + response.msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 清空上传时的各种数据
|
||||
this.fileList = []
|
||||
this.uploadData.title = ''
|
||||
this.uploadData.introduction = ''
|
||||
|
||||
// 上传好的文件,本质是个素材,所以可以进行选中
|
||||
let item = response.data
|
||||
this.selectMaterial(item)
|
||||
},
|
||||
/**
|
||||
* 切换消息类型的 tab
|
||||
*
|
||||
* @param tab tab
|
||||
*/
|
||||
handleClick(tab) {
|
||||
// 设置后续文件上传的文件类型
|
||||
this.uploadData.type = this.objData.type;
|
||||
if (this.uploadData.type === 'music') { // 【音乐】上传的是缩略图
|
||||
this.uploadData.type = 'thumb';
|
||||
}
|
||||
|
||||
// 从 tempObj 临时缓存中,获取对应的数据,并设置回 objData
|
||||
let tempObjItem = this.tempObj.get(this.objData.type)
|
||||
if (tempObjItem) {
|
||||
this.objData.content = tempObjItem.content ? tempObjItem.content : null
|
||||
this.objData.mediaId = tempObjItem.mediaId ? tempObjItem.mediaId : null
|
||||
this.objData.url = tempObjItem.url ? tempObjItem.url : null
|
||||
this.objData.name = tempObjItem.url ? tempObjItem.name : null
|
||||
this.objData.title = tempObjItem.title ? tempObjItem.title : null
|
||||
this.objData.description = tempObjItem.description ? tempObjItem.description : null
|
||||
return;
|
||||
}
|
||||
// 如果获取不到,需要把 objData 复原
|
||||
// 必须使用 $set 赋值,不然 input 无法输入内容
|
||||
this.$set(this.objData, 'content', '');
|
||||
this.$delete(this.objData, 'mediaId');
|
||||
this.$delete(this.objData, 'url');
|
||||
this.$set(this.objData, 'title', '');
|
||||
this.$set(this.objData, 'description', '');
|
||||
|
||||
},
|
||||
/**
|
||||
* 选择素材,将设置设置到 objData 变量
|
||||
*
|
||||
* @param item 素材
|
||||
*/
|
||||
selectMaterial(item) {
|
||||
// 选择好素材,所以隐藏弹窗
|
||||
this.closeMaterial();
|
||||
|
||||
// 创建 tempObjItem 对象,并设置对应的值
|
||||
let tempObjItem = {}
|
||||
tempObjItem.type = this.objData.type;
|
||||
if (this.objData.type === 'news') {
|
||||
tempObjItem.articles = item.content.newsItem
|
||||
this.objData.articles = item.content.newsItem
|
||||
} else if (this.objData.type === 'music') { // 音乐需要特殊处理,因为选择的是图片的缩略图
|
||||
tempObjItem.thumbMediaId = item.mediaId
|
||||
this.objData.thumbMediaId = item.mediaId
|
||||
tempObjItem.thumbMediaUrl = item.url
|
||||
this.objData.thumbMediaUrl = item.url
|
||||
// title、introduction、musicUrl、hqMusicUrl:从 objData 到 tempObjItem,避免上传素材后,被覆盖掉
|
||||
tempObjItem.title = this.objData.title || ''
|
||||
tempObjItem.introduction = this.objData.introduction || ''
|
||||
tempObjItem.musicUrl = this.objData.musicUrl || ''
|
||||
tempObjItem.hqMusicUrl = this.objData.hqMusicUrl || ''
|
||||
} else if (this.objData.type === 'image'
|
||||
|| this.objData.type === 'voice') {
|
||||
tempObjItem.mediaId = item.mediaId
|
||||
this.objData.mediaId = item.mediaId
|
||||
tempObjItem.url = item.url;
|
||||
this.objData.url = item.url;
|
||||
tempObjItem.name = item.name
|
||||
this.objData.name = item.name
|
||||
} else if (this.objData.type === 'video') {
|
||||
tempObjItem.mediaId = item.mediaId
|
||||
this.objData.mediaId = item.mediaId
|
||||
tempObjItem.url = item.url;
|
||||
this.objData.url = item.url;
|
||||
tempObjItem.name = item.name
|
||||
this.objData.name = item.name
|
||||
// title、introduction:从 item 到 tempObjItem,因为素材里有 title、introduction
|
||||
if (item.title) {
|
||||
this.objData.title = item.title || ''
|
||||
tempObjItem.title = item.title || ''
|
||||
}
|
||||
if (item.introduction) {
|
||||
this.objData.description = item.introduction || '' // 消息使用的是 description,素材使用的是 introduction,所以转换下
|
||||
tempObjItem.description = item.introduction || ''
|
||||
}
|
||||
} else if (this.objData.type === 'text') {
|
||||
this.objData.content = item.content || ''
|
||||
}
|
||||
// 最终设置到临时缓存
|
||||
this.tempObj.set(this.objData.type, tempObjItem)
|
||||
},
|
||||
openMaterial() {
|
||||
if (this.objData.type === 'news') {
|
||||
this.dialogNewsVisible = true
|
||||
} else if(this.objData.type === 'image') {
|
||||
this.dialogImageVisible = true
|
||||
} else if(this.objData.type === 'voice') {
|
||||
this.dialogVoiceVisible = true
|
||||
} else if(this.objData.type === 'video') {
|
||||
this.dialogVideoVisible = true
|
||||
} else if(this.objData.type === 'music') {
|
||||
this.dialogThumbVisible = true
|
||||
}
|
||||
},
|
||||
closeMaterial() {
|
||||
this.dialogNewsVisible = false
|
||||
this.dialogImageVisible = false
|
||||
this.dialogVoiceVisible = false
|
||||
this.dialogVideoVisible = false
|
||||
this.dialogThumbVisible = false
|
||||
},
|
||||
deleteObj() {
|
||||
if (this.objData.type === 'news') {
|
||||
this.$delete(this.objData, 'articles');
|
||||
} else if(this.objData.type === 'image') {
|
||||
this.objData.mediaId = null
|
||||
this.$delete(this.objData, 'url');
|
||||
this.objData.name = null
|
||||
} else if(this.objData.type === 'voice') {
|
||||
this.objData.mediaId = null
|
||||
this.$delete(this.objData, 'url');
|
||||
this.objData.name = null
|
||||
} else if(this.objData.type === 'video') {
|
||||
this.objData.mediaId = null
|
||||
this.$delete(this.objData, 'url');
|
||||
this.objData.name = null
|
||||
this.objData.title = null
|
||||
this.objData.description = null
|
||||
} else if(this.objData.type === 'music') {
|
||||
this.objData.thumbMediaId = null
|
||||
this.objData.thumbMediaUrl = null
|
||||
this.objData.title = null
|
||||
this.objData.description = null
|
||||
this.objData.musicUrl = null
|
||||
this.objData.hqMusicUrl = null
|
||||
} else if(this.objData.type === 'text') {
|
||||
this.objData.content = null
|
||||
}
|
||||
// 覆盖缓存
|
||||
this.tempObj.set(this.objData.type, Object.assign({}, this.objData));
|
||||
},
|
||||
/**
|
||||
* 输入时,缓存每次 objData 到 tempObj 中
|
||||
*
|
||||
* why?不确定为什么 v-model="objData.content" 不能自动缓存,所以通过这样的方式
|
||||
*/
|
||||
inputContent(str) {
|
||||
// 覆盖缓存
|
||||
this.tempObj.set(this.objData.type, Object.assign({}, this.objData));
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.public-account-management{
|
||||
.el-input{
|
||||
width: 70%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
}
|
||||
.pagination{
|
||||
text-align: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
.select-item{
|
||||
width: 280px;
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.select-item2{
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.ope-row{
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.item-name{
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
.el-form-item__content{
|
||||
line-height:unset!important;
|
||||
}
|
||||
.col-select{
|
||||
border: 1px solid rgb(234, 234, 234);
|
||||
padding: 50px 0px;
|
||||
height: 160px;
|
||||
width: 49.5%;
|
||||
}
|
||||
.col-select2{
|
||||
border: 1px solid rgb(234, 234, 234);
|
||||
padding: 50px 0px;
|
||||
height: 160px;
|
||||
}
|
||||
.col-add{
|
||||
border: 1px solid rgb(234, 234, 234);
|
||||
padding: 50px 0px;
|
||||
height: 160px;
|
||||
width: 49.5%;
|
||||
float: right
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
border: 1px solid #d9d9d9;
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 100px!important;
|
||||
height: 100px!important;
|
||||
line-height: 100px!important;
|
||||
text-align: center;
|
||||
}
|
||||
.material-img {
|
||||
width: 100%;
|
||||
}
|
||||
.thumb-div{
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.item-infos{
|
||||
width: 30%;
|
||||
margin: auto
|
||||
}
|
||||
</style>
|
||||
@@ -1,91 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
【微信消息 - 视频】
|
||||
芋道源码:
|
||||
① bug 修复:
|
||||
1)joolun 的做法:使用 mediaId 从微信公众号,下载对应的 mp4 素材,从而播放内容;
|
||||
存在的问题:mediaId 有效期是 3 天,超过时间后无法播放
|
||||
2)重构后的做法:后端接收到微信公众号的视频消息后,将视频消息的 media_id 的文件内容保存到文件服务器中,这样前端可以直接使用 URL 播放。
|
||||
② 体验优化:弹窗关闭后,自动暂停视频的播放
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<!-- 提示 -->
|
||||
<div @click="playVideo()">
|
||||
<i class="el-icon-video-play" style="font-size: 40px!important;" ></i>
|
||||
<p>点击播放视频</p>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗播放 -->
|
||||
<el-dialog title="视频播放" :visible.sync="dialogVideo" width="40%" append-to-body @close="closeDialog">
|
||||
<video-player v-if="playerOptions.sources[0].src" class="video-player vjs-custom-skin" ref="videoPlayer"
|
||||
:playsinline="true" :options="playerOptions"
|
||||
@play="onPlayerPlay($event)" @pause="onPlayerPause($event)">
|
||||
</video-player>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入 videoPlayer 相关组件。教程:https://juejin.cn/post/6923056942281654285
|
||||
import { videoPlayer } from 'vue-video-player'
|
||||
require('video.js/dist/video-js.css')
|
||||
require('vue-video-player/src/custom-theme.css')
|
||||
|
||||
export default {
|
||||
name: "wxVideoPlayer",
|
||||
props: {
|
||||
url: { // 视频地址,例如说:https://www.iocoder.cn/xxx.mp4
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
components: {
|
||||
videoPlayer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVideo:false,
|
||||
playerOptions: {
|
||||
playbackRates: [0.5, 1.0, 1.5, 2.0], // 播放速度
|
||||
autoplay: false, // 如果 true,浏览器准备好时开始回放。
|
||||
muted: false, // 默认情况下将会消除任何音频。
|
||||
loop: false, // 导致视频一结束就重新开始。
|
||||
preload: 'auto', // 建议浏览器在 <video> 加载元素后是否应该开始下载视频数据。auto 浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
|
||||
language: 'zh-CN',
|
||||
aspectRatio: '16:9', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
|
||||
fluid: true, // 当true时,Video.js player 将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
|
||||
sources: [{
|
||||
type: "video/mp4",
|
||||
src: "" // 你的视频地址(必填)【重要】
|
||||
}],
|
||||
poster: "", // 你的封面地址
|
||||
width: document.documentElement.clientWidth,
|
||||
notSupportedMessage: '此视频暂无法播放,请稍后再试', //允许覆盖 Video.js 无法播放媒体源时显示的默认信息。
|
||||
controlBar: {
|
||||
timeDivider: true,
|
||||
durationDisplay: true,
|
||||
remainingTimeDisplay: false,
|
||||
fullscreenToggle: true //全屏按钮
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playVideo(){
|
||||
this.dialogVideo = true
|
||||
// 设置地址
|
||||
this.$set(this.playerOptions.sources[0], 'src', this.url)
|
||||
},
|
||||
closeDialog(){
|
||||
// 暂停播放
|
||||
this.$refs.videoPlayer.player.pause()
|
||||
},
|
||||
onPlayerPlay(player) {
|
||||
},
|
||||
onPlayerPause(player) {
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,98 +0,0 @@
|
||||
<!--
|
||||
- Copyright (C) 2018-2019
|
||||
- All rights reserved, Designed By www.joolun.com
|
||||
【微信消息 - 语音】
|
||||
芋道源码:
|
||||
① bug 修复:
|
||||
1)joolun 的做法:使用 mediaId 从微信公众号,下载对应的 mp4 素材,从而播放内容;
|
||||
存在的问题:mediaId 有效期是 3 天,超过时间后无法播放
|
||||
2)重构后的做法:后端接收到微信公众号的视频消息后,将视频消息的 media_id 的文件内容保存到文件服务器中,这样前端可以直接使用 URL 播放。
|
||||
② 代码优化:将 props 中的 objData 调成为 data 中对应的属性,并补充相关注释
|
||||
-->
|
||||
<template>
|
||||
<div class="wx-voice-div" @click="playVoice">
|
||||
<i :class="playing !== true ? 'el-icon-video-play': 'el-icon-video-pause'">
|
||||
<span class="amr-duration" v-if="duration">{{ duration }} 秒</span>
|
||||
</i>
|
||||
<div v-if="content">
|
||||
<el-tag type="success" size="mini">语音识别</el-tag>
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 因为微信语音是 amr 格式,所以需要用到 amr 解码器:https://www.npmjs.com/package/benz-amr-recorder
|
||||
const BenzAMRRecorder = require('benz-amr-recorder')
|
||||
|
||||
export default {
|
||||
name: "wxVoicePlayer",
|
||||
props: {
|
||||
url: { // 语音地址,例如说:https://www.iocoder.cn/xxx.amr
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
content: { // 语音文本
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
amr: undefined, // BenzAMRRecorder 对象
|
||||
playing: false, // 是否在播放中
|
||||
duration: undefined, // 播放时长
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
playVoice() {
|
||||
debugger
|
||||
// 情况一:未初始化,则创建 BenzAMRRecorder
|
||||
if (this.amr === undefined){
|
||||
this.amrInit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.amr.isPlaying()) {
|
||||
this.amrStop();
|
||||
} else {
|
||||
this.amrPlay();
|
||||
}
|
||||
},
|
||||
amrInit() {
|
||||
const amr = new BenzAMRRecorder();
|
||||
this.amr = amr;
|
||||
// 设置播放
|
||||
const that = this
|
||||
amr.initWithUrl(this.url).then(function() {
|
||||
that.amrPlay()
|
||||
that.duration = amr.getDuration();
|
||||
})
|
||||
// 监听暂停
|
||||
amr.onEnded(function() {
|
||||
that.playing = false;
|
||||
})
|
||||
},
|
||||
amrPlay() {
|
||||
this.playing = true;
|
||||
this.amr.play()
|
||||
},
|
||||
amrStop() {
|
||||
this.playing = false;
|
||||
this.amr.stop()
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wx-voice-div {
|
||||
padding: 5px;
|
||||
background-color: #eaeaea;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.amr-duration {
|
||||
font-size: 11px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,700 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.joolun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
芋道源码:
|
||||
① 优化代码,和项目的代码保持一致
|
||||
② 清理冗余代码,保证代码整洁
|
||||
③ 增加注释,提升可读性
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['mp:draft:create']">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div v-if="item.content && item.content.newsItem" class="waterfall-item" v-for="item in list"
|
||||
:key='item.articleId'>
|
||||
<wx-news :articles="item.content.newsItem" />
|
||||
<!-- 操作按钮 -->
|
||||
<el-row class="ope-row">
|
||||
<el-button type="success" circle @click="handlePublish(item)" v-hasPermi="['mp:free-publish:submit']">发布</el-button>
|
||||
<el-button type="primary" icon="el-icon-edit" circle @click="handleUpdate(item)" v-hasPermi="['mp:draft:update']" />
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(item)" v-hasPermi="['mp:draft:delete']" />
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页记录 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 添加或修改草稿对话框 -->
|
||||
<el-dialog :title="operateMaterial === 'add' ? '新建图文' : '修改图文'"
|
||||
append-to-body width="80%" top="20px" :visible.sync="dialogNewsVisible"
|
||||
:before-close="dialogNewsClose" :close-on-click-modal="false">
|
||||
<div class="left">
|
||||
<div class="select-item">
|
||||
<div v-for="(news, index) in articlesAdd" :key='news.id'>
|
||||
<div class="news-main father" v-if="index === 0" :class="{'activeAddNews': isActiveAddNews === index}"
|
||||
@click="activeNews(index)">
|
||||
<div class="news-content">
|
||||
<img class="material-img" v-if="news.thumbUrl" :src="news.thumbUrl"/>
|
||||
<div class="news-content-title">{{news.title}}</div>
|
||||
</div>
|
||||
<div class="child" v-if="articlesAdd.length>1">
|
||||
<el-button type="mini" icon="el-icon-sort-down" @click="downNews(index)">下移</el-button>
|
||||
<el-button v-if="operateMaterial === 'add'" type="mini" icon="el-icon-delete"
|
||||
@click="minusNews(index)">删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="news-main-item father" v-if="index>0" :class="{'activeAddNews': isActiveAddNews === index}"
|
||||
@click="activeNews(index)">
|
||||
<div class="news-content-item">
|
||||
<div class="news-content-item-title ">{{news.title}}</div>
|
||||
<div class="news-content-item-img">
|
||||
<img class="material-img" v-if="news.thumbUrl" :src="news.thumbUrl" height="100%"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child">
|
||||
<el-button v-if="articlesAdd.length > index+1" type="mini" icon="el-icon-sort-down"
|
||||
@click="downNews(index)">下移
|
||||
</el-button>
|
||||
<el-button type="mini" icon="el-icon-sort-up" @click="upNews(index)">上移</el-button>
|
||||
<el-button v-if="operateMaterial=== 'add'" type="mini" icon="el-icon-delete"
|
||||
@click="minusNews(index)">删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="news-main-plus" @click="plusNews" v-if="articlesAdd.length<8 && operateMaterial==='add'">
|
||||
<i class="el-icon-circle-plus icon-plus"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right" v-loading="addMaterialLoading" v-if="articlesAdd.length > 0">
|
||||
<br /> <br /> <br /> <br />
|
||||
<!-- 标题、作者、原文地址 -->
|
||||
<el-input v-model="articlesAdd[isActiveAddNews].title" placeholder="请输入标题(必填)" />
|
||||
<el-input v-model="articlesAdd[isActiveAddNews].author" placeholder="请输入作者" style="margin-top: 5px;" />
|
||||
<el-input v-model="articlesAdd[isActiveAddNews].contentSourceUrl" placeholder="请输入原文地址" style="margin-top: 5px;" />
|
||||
<!-- 封面和摘要 -->
|
||||
<div class="input-tt">封面和摘要:</div>
|
||||
<div>
|
||||
<div class="thumb-div">
|
||||
<img class="material-img" v-if="articlesAdd[isActiveAddNews].thumbUrl"
|
||||
:src="articlesAdd[isActiveAddNews].thumbUrl" :class="isActiveAddNews === 0 ? 'avatar':'avatar1'">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"
|
||||
:class="isActiveAddNews === 0 ? 'avatar':'avatar1'"></i>
|
||||
<div class="thumb-but">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeThumbImageUpload" :on-success="handleUploadSuccess">
|
||||
<el-button slot="trigger" size="mini" type="primary">本地上传</el-button>
|
||||
<el-button size="mini" type="primary" @click="openMaterial" style="margin-left: 5px">素材库选择</el-button>
|
||||
<div slot="tip" class="el-upload__tip">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<el-dialog title="选择图片" :visible.sync="dialogImageVisible" width="80%" append-to-body>
|
||||
<wx-material-select ref="materialSelect" :objData="{type: 'image', accountId: this.queryParams.accountId}"
|
||||
@selectMaterial="selectMaterial" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
<el-input :rows="8" type="textarea" v-model="articlesAdd[isActiveAddNews].digest" placeholder="请输入摘要"
|
||||
class="digest" maxlength="120" style="float: right" />
|
||||
</div>
|
||||
<!--富文本编辑器组件-->
|
||||
<el-row>
|
||||
<wx-editor v-model="articlesAdd[isActiveAddNews].content" :account-id="this.uploadData.accountId"
|
||||
v-if="hackResetEditor"/>
|
||||
</el-row>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogNewsVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitForm">提 交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxEditor from '@/views/mp/components/wx-editor/WxEditor.vue';
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import {createDraft, deleteDraft, getDraftPage, updateDraft} from "@/api/mp/draft";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
import {deleteFreePublish, submitFreePublish} from "@/api/mp/freePublish";
|
||||
|
||||
export default {
|
||||
name: 'MpDraft',
|
||||
components: {
|
||||
WxEditor,
|
||||
WxNews,
|
||||
WxMaterialSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 数据列表
|
||||
list: [],
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: undefined,
|
||||
},
|
||||
|
||||
// ========== 文件上传 ==========
|
||||
actionUrl: process.env.VUE_APP_BASE_API + "/admin-api/mp/material/upload-permanent", // 上传永久素材的地址
|
||||
headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
|
||||
fileList: [],
|
||||
uploadData: {
|
||||
"type": 'image',
|
||||
// "accountId": 1,
|
||||
},
|
||||
|
||||
// ========== 草稿新建 or 修改 ==========
|
||||
dialogNewsVisible: false,
|
||||
addMaterialLoading: false, // 添加草稿的 loading 标识
|
||||
articlesAdd: [],
|
||||
isActiveAddNews: 0,
|
||||
dialogImageVisible: false,
|
||||
operateMaterial: 'add',
|
||||
articlesMediaId: '',
|
||||
hackResetEditor: false,
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id);
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// ======================== 列表查询 ========================
|
||||
/** 设置账号编号 */
|
||||
setAccountId(accountId) {
|
||||
this.queryParams.accountId = accountId;
|
||||
this.uploadData.accountId = accountId;
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询草稿箱')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
getDraftPage(this.queryParams).then(response => {
|
||||
// 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
|
||||
response.data.list.forEach(item => {
|
||||
const newsItem = item.content.newsItem;
|
||||
newsItem.forEach(article => {
|
||||
article.picUrl = article.thumbUrl;
|
||||
})
|
||||
})
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
// 默认选中第一个
|
||||
if (this.queryParams.accountId) {
|
||||
this.setAccountId(this.queryParams.accountId)
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id)
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
|
||||
// ======================== 新增/修改草稿 ========================
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.resetEditor();
|
||||
this.reset();
|
||||
// 打开表单,并设置初始化
|
||||
this.operateMaterial = 'add'
|
||||
this.dialogNewsVisible = true
|
||||
},
|
||||
/** 更新按钮操作 */
|
||||
handleUpdate(item){
|
||||
this.resetEditor();
|
||||
this.reset();
|
||||
this.articlesMediaId = item.mediaId
|
||||
this.articlesAdd = JSON.parse(JSON.stringify(item.content.newsItem))
|
||||
// 打开表单,并设置初始化
|
||||
this.operateMaterial = 'edit'
|
||||
this.dialogNewsVisible = true
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.addMaterialLoading = true
|
||||
if (this.operateMaterial === 'add') {
|
||||
createDraft(this.queryParams.accountId, this.articlesAdd).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.dialogNewsVisible = false;
|
||||
this.getList()
|
||||
}).finally(() => {
|
||||
this.addMaterialLoading = false
|
||||
})
|
||||
} else {
|
||||
updateDraft(this.queryParams.accountId, this.articlesMediaId, this.articlesAdd).then(response => {
|
||||
this.$modal.msgSuccess("更新成功");
|
||||
this.dialogNewsVisible = false;
|
||||
this.getList()
|
||||
}).finally(() => {
|
||||
this.addMaterialLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
// 关闭弹窗
|
||||
dialogNewsClose(done) {
|
||||
this.$modal.confirm('修改内容可能还未保存,确定关闭吗?').then(() => {
|
||||
this.reset()
|
||||
this.resetEditor()
|
||||
done()
|
||||
}).catch(() => {})
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.isActiveAddNews = 0
|
||||
this.articlesAdd = [this.buildEmptyArticle()]
|
||||
},
|
||||
// 表单 Editor 重置
|
||||
resetEditor() {
|
||||
this.hackResetEditor = false // 销毁组件
|
||||
this.$nextTick(() => {
|
||||
this.hackResetEditor = true // 重建组件
|
||||
})
|
||||
},
|
||||
// 将图文向下移动
|
||||
downNews(index) {
|
||||
let temp = this.articlesAdd[index]
|
||||
this.articlesAdd[index] = this.articlesAdd[index+1]
|
||||
this.articlesAdd[index + 1] = temp
|
||||
this.isActiveAddNews = index + 1
|
||||
},
|
||||
// 将图文向上移动
|
||||
upNews(index) {
|
||||
let temp = this.articlesAdd[index]
|
||||
this.articlesAdd[index] = this.articlesAdd[index - 1]
|
||||
this.articlesAdd[index - 1] = temp
|
||||
this.isActiveAddNews = index - 1
|
||||
},
|
||||
// 选中指定 index 的图文
|
||||
activeNews(index) {
|
||||
this.resetEditor();
|
||||
this.isActiveAddNews = index
|
||||
},
|
||||
// 删除指定 index 的图文
|
||||
minusNews(index) {
|
||||
this.$modal.confirm('确定删除该图文吗?').then(() => {
|
||||
this.articlesAdd.splice(index,1);
|
||||
if (this.isActiveAddNews === index) {
|
||||
this.isActiveAddNews = 0
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
// 添加一个图文
|
||||
plusNews() {
|
||||
this.articlesAdd.push(this.buildEmptyArticle())
|
||||
this.isActiveAddNews = this.articlesAdd.length - 1
|
||||
},
|
||||
// 创建空的 article
|
||||
buildEmptyArticle() {
|
||||
return {
|
||||
"title": '',
|
||||
"thumbMediaId": '',
|
||||
"author": '',
|
||||
"digest": '',
|
||||
"showCoverPic": '',
|
||||
"content": '',
|
||||
"contentSourceUrl": '',
|
||||
"needOpenComment":'',
|
||||
"onlyFansCanComment":'',
|
||||
"thumbUrl":''
|
||||
}
|
||||
},
|
||||
|
||||
// ======================== 文件上传 ========================
|
||||
beforeThumbImageUpload(file) {
|
||||
this.addMaterialLoading = true
|
||||
const isType = file.type === 'image/jpeg'
|
||||
|| file.type === 'image/png'
|
||||
|| file.type === 'image/gif'
|
||||
|| file.type === 'image/bmp'
|
||||
|| file.type === 'image/jpg';
|
||||
if (!isType) {
|
||||
this.$message.error('上传图片格式不对!')
|
||||
this.addMaterialLoading = false
|
||||
return false;
|
||||
}
|
||||
const isLt = file.size / 1024 / 1024 < 2
|
||||
if (!isLt) {
|
||||
this.$message.error('上传图片大小不能超过 2M!')
|
||||
this.addMaterialLoading = false
|
||||
return false;
|
||||
}
|
||||
// 校验通过
|
||||
return true;
|
||||
},
|
||||
handleUploadSuccess(response, file, fileList) {
|
||||
this.addMaterialLoading = false // 关闭 loading
|
||||
if (response.code !== 0) {
|
||||
this.$message.error('上传出错:' + response.msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 重置上传文件的表单
|
||||
this.fileList = []
|
||||
|
||||
// 设置草稿的封面字段
|
||||
this.articlesAdd[this.isActiveAddNews].thumbMediaId = response.data.mediaId
|
||||
this.articlesAdd[this.isActiveAddNews].thumbUrl = response.data.url
|
||||
},
|
||||
// 选择 or 上传完素材,设置回草稿
|
||||
selectMaterial(item) {
|
||||
this.dialogImageVisible = false
|
||||
this.articlesAdd[this.isActiveAddNews].thumbMediaId = item.mediaId
|
||||
this.articlesAdd[this.isActiveAddNews].thumbUrl = item.url
|
||||
},
|
||||
// 打开素材选择
|
||||
openMaterial() {
|
||||
this.dialogImageVisible = true
|
||||
try {
|
||||
this.$refs['materialSelect'].queryParams.accountId = this.queryParams.accountId // 强制设置下 accountId,避免二次查询不对
|
||||
this.$refs['materialSelect'].handleQuery(); // 刷新列表,失败也无所谓
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// ======================== 草稿箱发布 ========================
|
||||
handlePublish(item) {
|
||||
const accountId = this.queryParams.accountId;
|
||||
const mediaId = item.mediaId;
|
||||
const content = '你正在通过发布的方式发表内容。 发布不占用群发次数,一天可多次发布。已发布内容不会推送给用户,也不会展示在公众号主页中。 发布后,你可以前往发表记录获取链接,也可以将发布内容添加到自定义菜单、自动回复、话题和页面模板中。';
|
||||
this.$modal.confirm(content).then(function() {
|
||||
return submitFreePublish(accountId, mediaId);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("发布成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
handleDelete(item) {
|
||||
const accountId = this.queryParams.accountId;
|
||||
const mediaId = item.mediaId;
|
||||
this.$modal.confirm('此操作将永久删除该草稿, 是否继续?').then(function() {
|
||||
return deleteDraft(accountId, mediaId);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pagination {
|
||||
float: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.add_but {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.ope-row {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #eaeaea;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/*新增图文*/
|
||||
.left {
|
||||
display: inline-block;
|
||||
width: 35%;
|
||||
vertical-align: top;
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
margin-top: -40px;
|
||||
}
|
||||
|
||||
.avatar-uploader {
|
||||
width: 20%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload {
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: unset !important;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #165dff;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
border: 1px solid #d9d9d9;
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 230px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.avatar1 {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.digest {
|
||||
width: 60%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/*新增图文*/
|
||||
/*瀑布流样式*/
|
||||
.waterfall {
|
||||
width: 100%;
|
||||
column-gap: 10px;
|
||||
column-count: 5;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.waterfall-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
break-inside: avoid;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1300px) {
|
||||
.waterfall {
|
||||
column-count: 3;
|
||||
}
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.waterfall {
|
||||
column-count: 2;
|
||||
}
|
||||
p {
|
||||
color: orange;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.waterfall {
|
||||
column-count: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*瀑布流样式*/
|
||||
.news-main {
|
||||
background-color: #FFFFFF;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.news-content {
|
||||
background-color: #acadae;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.news-content-title {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
background-color: black;
|
||||
width: 98%;
|
||||
padding: 1%;
|
||||
opacity: 0.65;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.news-main-item {
|
||||
background-color: #FFFFFF;
|
||||
padding: 5px 0px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.news-content-item {
|
||||
position: relative;
|
||||
margin-left: -3px
|
||||
}
|
||||
|
||||
.news-content-item-title {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.news-content-item-img {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
background-color: #acadae
|
||||
}
|
||||
|
||||
.input-tt {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.activeAddNews {
|
||||
border: 5px solid #2bb673;
|
||||
}
|
||||
|
||||
.news-main-plus {
|
||||
width: 280px;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.icon-plus {
|
||||
margin: 10px;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.select-item {
|
||||
width: 60%;
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
.father .child {
|
||||
display: none;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
bottom: 25px;
|
||||
}
|
||||
|
||||
.father:hover .child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumb-div {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.thumb-but {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.material-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,395 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.joolun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
芋道源码:
|
||||
① 优化代码,和项目的代码保持一致
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div v-if="item.content && item.content.newsItem" class="waterfall-item" v-for="item in list"
|
||||
:key='item.articleId'>
|
||||
<wx-news :articles="item.content.newsItem" />
|
||||
<!-- 操作 -->
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(item)"
|
||||
v-hasPermi="['mp:free-publish:delete']" />
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFreePublishPage, deleteFreePublish } from "@/api/mp/freePublish";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
|
||||
export default {
|
||||
name: 'MpFreePublish',
|
||||
components: {
|
||||
WxNews
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 已发表列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
total: 0, // 总页数
|
||||
currentPage: 1, // 当前页数
|
||||
queryParamsSize: 10 // 每页显示多少条
|
||||
},
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询已发表图文')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
getFreePublishPage(this.queryParams).then(response => {
|
||||
// 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
|
||||
response.data.list.forEach(item => {
|
||||
const newsItem = item.content.newsItem;
|
||||
newsItem.forEach(article => {
|
||||
article.picUrl = article.thumbUrl;
|
||||
})
|
||||
})
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(item){
|
||||
const articleId = item.articleId;
|
||||
const accountId = this.queryParams.accountId;
|
||||
this.$modal.confirm('删除后用户将无法访问此页面,确定删除?').then(function() {
|
||||
return deleteFreePublish(accountId, articleId);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pagination {
|
||||
float: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.add_but {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.ope-row {
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #eaeaea;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/*新增图文*/
|
||||
.left {
|
||||
display: inline-block;
|
||||
width: 35%;
|
||||
vertical-align: top;
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.right {
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
margin-top: -40px;
|
||||
}
|
||||
|
||||
.avatar-uploader {
|
||||
width: 20%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload {
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-align: unset !important;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #165dff;
|
||||
}
|
||||
|
||||
.avatar-uploader-icon {
|
||||
border: 1px solid #d9d9d9;
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 230px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.avatar1 {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.digest {
|
||||
width: 60%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/*新增图文*/
|
||||
/*瀑布流样式*/
|
||||
.waterfall {
|
||||
width: 100%;
|
||||
column-gap: 10px;
|
||||
column-count: 5;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.waterfall-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
break-inside: avoid;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) and (max-width: 1300px) {
|
||||
.waterfall {
|
||||
column-count: 3;
|
||||
}
|
||||
p {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.waterfall {
|
||||
column-count: 2;
|
||||
}
|
||||
p {
|
||||
color: orange;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.waterfall {
|
||||
column-count: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*瀑布流样式*/
|
||||
.news-main {
|
||||
background-color: #FFFFFF;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.news-content {
|
||||
background-color: #acadae;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.news-content-title {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
background-color: black;
|
||||
width: 98%;
|
||||
padding: 1%;
|
||||
opacity: 0.65;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.news-main-item {
|
||||
background-color: #FFFFFF;
|
||||
padding: 5px 0px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.news-content-item {
|
||||
position: relative;
|
||||
margin-left: -3px
|
||||
}
|
||||
|
||||
.news-content-item-title {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.news-content-item-img {
|
||||
display: inline-block;
|
||||
width: 25%;
|
||||
background-color: #acadae
|
||||
}
|
||||
|
||||
.input-tt {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.activeAddNews {
|
||||
border: 5px solid #2bb673;
|
||||
}
|
||||
|
||||
.news-main-plus {
|
||||
width: 280px;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.icon-plus {
|
||||
margin: 10px;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.select-item {
|
||||
width: 60%;
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
.father .child {
|
||||
display: none;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
bottom: 25px;
|
||||
}
|
||||
|
||||
.father:hover .child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumb-div {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.thumb-but {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.material-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,440 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.joolun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
芋道源码:
|
||||
① 清理冗余 css 内容,清理冗余 data 变量
|
||||
② 美化样式,支持播放,提升使用体验
|
||||
③ 优化代码,特别是方法名和变量,提升可读性
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号素材" url="https://doc.iocoder.cn/mp/material/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-tabs v-model="type" @tab-click="handleClick">
|
||||
<!-- tab 1:图片 -->
|
||||
<el-tab-pane name="image">
|
||||
<span slot="label"><i class="el-icon-picture"></i> 图片</span>
|
||||
<div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeImageUpload" :on-success="handleUploadSuccess">
|
||||
<el-button size="mini" type="primary">点击上传</el-button>
|
||||
<sapn slot="tip" class="el-upload__tip" style="margin-left: 5px">支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M</sapn>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="waterfall" v-loading="loading">
|
||||
<div class="waterfall-item" v-for="item in list" :key='item.id'>
|
||||
<a target="_blank" :href="item.url">
|
||||
<img class="material-img" :src="item.url">
|
||||
<div class="item-name">{{item.name}}</div>
|
||||
</a>
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="handleDelete(item)"
|
||||
v-hasPermi="['mp:material:delete']"/>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- tab 2:语音 -->
|
||||
<el-tab-pane name="voice">
|
||||
<span slot="label"><i class="el-icon-microphone"></i> 语音</span>
|
||||
<div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:on-success="handleUploadSuccess" :before-upload="beforeVoiceUpload">
|
||||
<el-button size="mini" type="primary">点击上传</el-button>
|
||||
<span slot="tip" class="el-upload__tip" style="margin-left: 5px">格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s</span>
|
||||
</el-upload>
|
||||
</div>
|
||||
<el-table :data="list" stripe border v-loading="loading" style="margin-top: 10px;">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
<el-table-column label="文件名" align="center" prop="name" />
|
||||
<el-table-column label="语音" align="center">
|
||||
<template v-slot="scope">
|
||||
<wx-voice-player :url="scope.row.url" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" icon="el-icon-download" size="small" plain @click="handleDownload(scope.row)">下载</el-button>
|
||||
<el-button type="text" icon="el-icon-delete" size="small" plain @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mp:material:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- tab 3:视频 -->
|
||||
<el-tab-pane name="video">
|
||||
<span slot="label"><i class="el-icon-video-play"></i> 视频</span>
|
||||
<div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
|
||||
<el-button size="mini" type="primary" @click="handleAddVideo">新建视频</el-button>
|
||||
</div>
|
||||
<!-- 新建视频的弹窗 -->
|
||||
<el-dialog title="新建视频" :visible.sync="dialogVideoVisible" append-to-body width="600px"
|
||||
v-loading="addMaterialLoading">
|
||||
<el-upload :action="actionUrl" :headers="headers" multiple :limit="1" :file-list="fileList" :data="uploadData"
|
||||
:before-upload="beforeVideoUpload" :on-success="handleUploadSuccess"
|
||||
ref="uploadVideo" :auto-upload="false">
|
||||
<el-button slot="trigger" size="mini" type="primary">选择视频</el-button>
|
||||
<span class="el-upload__tip" style="margin-left: 10px;">格式支持 MP4,文件大小不超过 10MB</span>
|
||||
</el-upload>
|
||||
<el-form :model="uploadData" :rules="uploadRules" ref="uploadForm" label-width="80px">
|
||||
<el-row>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="uploadData.title" placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题" />
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-form-item label="描述" prop="introduction">
|
||||
<el-input :rows="3" type="textarea" v-model="uploadData.introduction"
|
||||
placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容" />
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="cancelVideo">取 消</el-button>
|
||||
<el-button type="primary" @click="submitVideo">提 交</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-table :data="list" stripe border v-loading="loading" style="margin-top: 10px;">
|
||||
<el-table-column label="编号" align="center" prop="mediaId" />
|
||||
<el-table-column label="文件名" align="center" prop="name" />
|
||||
<el-table-column label="标题" align="center" prop="title" />
|
||||
<el-table-column label="介绍" align="center" prop="introduction" />
|
||||
<el-table-column label="视频" align="center">
|
||||
<template v-slot="scope">
|
||||
<wx-video-player :url="scope.row.url" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" icon="el-icon-download" size="small" plain @click="handleDownload(scope.row)">下载</el-button>
|
||||
<el-button type="text" icon="el-icon-delete" size="small" plain @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mp:material:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
import { getMaterialPage, deletePermanentMaterial } from "@/api/mp/material";
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
name: 'MpMaterial',
|
||||
components: {
|
||||
WxVoicePlayer,
|
||||
WxVideoPlayer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'image',
|
||||
// 遮罩层
|
||||
loading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 数据列表
|
||||
list: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: undefined,
|
||||
permanent: true,
|
||||
},
|
||||
|
||||
actionUrl: process.env.VUE_APP_BASE_API + '/admin-api/mp/material/upload-permanent',
|
||||
headers: { Authorization: "Bearer " + getAccessToken() }, // 设置上传的请求头部
|
||||
fileList:[],
|
||||
uploadData: {
|
||||
"type": 'image',
|
||||
"title":'',
|
||||
"introduction":''
|
||||
},
|
||||
// === 视频上传,独有变量 ===
|
||||
dialogVideoVisible: false,
|
||||
addMaterialLoading: false,
|
||||
uploadRules: { // 视频上传的校验规则
|
||||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||||
introduction: [{ required: true, message: '请输入描述', trigger: 'blur' }],
|
||||
},
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id);
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// ======================== 列表查询 ========================
|
||||
/** 设置账号编号 */
|
||||
setAccountId(accountId) {
|
||||
this.queryParams.accountId = accountId;
|
||||
this.uploadData.accountId = accountId;
|
||||
},
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询草稿箱')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
getMaterialPage({
|
||||
...this.queryParams,
|
||||
type: this.type
|
||||
}).then(response => {
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
// 默认选中第一个
|
||||
if (this.queryParams.accountId) {
|
||||
this.setAccountId(this.queryParams.accountId)
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id)
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
handleClick(tab, event) {
|
||||
// 设置 type
|
||||
this.uploadData.type = tab.name
|
||||
// 从第一页开始查询
|
||||
this.handleQuery();
|
||||
},
|
||||
|
||||
// ======================== 文件上传 ========================
|
||||
beforeImageUpload(file) {
|
||||
const isType = file.type === 'image/jpeg'
|
||||
|| file.type === 'image/png'
|
||||
|| file.type === 'image/gif'
|
||||
|| file.type === 'image/bmp'
|
||||
|| file.type === 'image/jpg';
|
||||
if (!isType) {
|
||||
this.$message.error('上传图片格式不对!')
|
||||
return false;
|
||||
}
|
||||
const isLt = file.size / 1024 / 1024 < 2
|
||||
if (!isLt) {
|
||||
this.$message.error('上传图片大小不能超过 2M!')
|
||||
return false;
|
||||
}
|
||||
this.loading = true
|
||||
return true;
|
||||
},
|
||||
beforeVoiceUpload(file){
|
||||
const isType = file.type === 'audio/mp3'
|
||||
|| file.type === 'audio/wma'
|
||||
|| file.type === 'audio/wav'
|
||||
|| file.type === 'audio/amr';
|
||||
const isLt = file.size / 1024 / 1024 < 2
|
||||
if (!isType) {
|
||||
this.$message.error('上传语音格式不对!')
|
||||
return false;
|
||||
}
|
||||
if (!isLt) {
|
||||
this.$message.error('上传语音大小不能超过 2M!')
|
||||
return false;
|
||||
}
|
||||
this.loading = true
|
||||
return true;
|
||||
},
|
||||
beforeVideoUpload(file){
|
||||
const isType = file.type === 'video/mp4'
|
||||
if (!isType) {
|
||||
this.$message.error('上传视频格式不对!')
|
||||
return false;
|
||||
}
|
||||
const isLt = file.size / 1024 / 1024 < 10
|
||||
if (!isLt) {
|
||||
this.$message.error('上传视频大小不能超过 10M!')
|
||||
return false
|
||||
}
|
||||
this.addMaterialLoading = true
|
||||
return true
|
||||
},
|
||||
handleUploadSuccess(response, file, fileList) {
|
||||
this.loading = false
|
||||
this.addMaterialLoading = false
|
||||
if (response.code !== 0) {
|
||||
this.$message.error('上传出错:' + response.msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 清空上传时的各种数据
|
||||
this.dialogVideoVisible = false
|
||||
this.fileList = []
|
||||
this.uploadData.title = ''
|
||||
this.uploadData.introduction = ''
|
||||
|
||||
// 加载数据
|
||||
this.getList()
|
||||
},
|
||||
// 下载文件
|
||||
handleDownload(row) {
|
||||
window.open(row.url,'_blank')
|
||||
},
|
||||
// 提交 video 新建的表单
|
||||
submitVideo() {
|
||||
this.$refs['uploadForm'].validate((valid) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
this.$refs.uploadVideo.submit()
|
||||
})
|
||||
},
|
||||
handleAddVideo() {
|
||||
this.resetVideo();
|
||||
this.dialogVideoVisible = true
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancelVideo() {
|
||||
this.dialogVideoVisible = false;
|
||||
this.resetVideo();
|
||||
},
|
||||
/** 表单重置 */
|
||||
resetVideo() {
|
||||
this.fileList = []
|
||||
this.uploadData.title = ''
|
||||
this.uploadData.introduction = ''
|
||||
this.resetForm("uploadForm");
|
||||
},
|
||||
|
||||
// ======================== 其它操作 ========================
|
||||
handleDelete(item) {
|
||||
const id = item.id
|
||||
this.$modal.confirm('此操作将永久删除该文件, 是否继续?').then(function() {
|
||||
return deletePermanentMaterial(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/*瀑布流样式*/
|
||||
.waterfall {
|
||||
width: 100%;
|
||||
column-gap:10px;
|
||||
column-count: 5;
|
||||
margin-top: 10px; /* 芋道源码:增加 10px,避免顶着上面 */
|
||||
}
|
||||
.waterfall-item {
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
break-inside: avoid;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.material-img {
|
||||
width: 100%;
|
||||
}
|
||||
p {
|
||||
line-height: 30px;
|
||||
}
|
||||
@media (min-width: 992px) and (max-width: 1300px) {
|
||||
.waterfall {
|
||||
column-count: 3;
|
||||
}
|
||||
p {
|
||||
color:red;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.waterfall {
|
||||
column-count: 2;
|
||||
}
|
||||
p {
|
||||
color: orange;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.waterfall {
|
||||
column-count: 1;
|
||||
}
|
||||
}
|
||||
/*瀑布流样式*/
|
||||
</style>
|
||||
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,714 +0,0 @@
|
||||
<!--
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 www.joolun.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
芋道源码:
|
||||
① less 切到 scss,减少对 less 和 less-loader 的依赖
|
||||
②
|
||||
-->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号菜单" url="https://doc.iocoder.cn/mp/menu/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="public-account-management clearfix" v-loading="loading">
|
||||
<!--左边配置菜单-->
|
||||
<div class="left">
|
||||
<div class="weixin-hd">
|
||||
<div class="weixin-title">{{ name }}</div>
|
||||
</div>
|
||||
<div class="weixin-menu menu_main clearfix">
|
||||
<div class="menu_bottom" v-for="(item, i) of menuList" :key="i" >
|
||||
<!-- 一级菜单 -->
|
||||
<div @click="menuClick(i, item)" class="menu_item el-icon-s-fold" :class="{'active': isActive === i}">{{item.name}}</div>
|
||||
<!-- 以下为二级菜单-->
|
||||
<div class="submenu" v-if="isSubMenuFlag === i">
|
||||
<div class="subtitle menu_bottom" v-if="item.children" v-for="(subItem, k) in item.children" :key="k">
|
||||
<div class="menu_subItem" :class="{'active': isSubMenuActive === i + '' + k}" @click="subMenuClick(subItem, i, k)">
|
||||
{{subItem.name}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 二级菜单加号, 当长度 小于 5 才显示二级菜单的加号 -->
|
||||
<div class="menu_bottom menu_addicon" v-if="!item.children || item.children.length < 5" @click="addSubMenu(i,item)">
|
||||
<i class="el-icon-plus" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 一级菜单加号 -->
|
||||
<div class="menu_bottom menu_addicon" v-if="this.menuList.length < 3" @click="addMenu"><i class="el-icon-plus"></i></div>
|
||||
</div>
|
||||
<div class="save_div">
|
||||
<el-button class="save_btn" type="success" size="small" @click="handleSave" v-hasPermi="['mp:menu:save']">保存并发布菜单</el-button>
|
||||
<el-button class="save_btn" type="danger" size="small" @click="handleDelete" v-hasPermi="['mp:menu:delete']">清空菜单</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--右边配置-->
|
||||
<div v-if="showRightFlag" class="right">
|
||||
<div class="configure_page">
|
||||
<div class="delete_btn">
|
||||
<el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteMenu(tempObj)">删除当前菜单</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<span>菜单名称:</span>
|
||||
<el-input class="input_width" v-model="tempObj.name" placeholder="请输入菜单名称" :maxlength="nameMaxLength" clearable />
|
||||
</div>
|
||||
<div v-if="showConfigureContent">
|
||||
<div class="menu_content">
|
||||
<span>菜单标识:</span>
|
||||
<el-input class="input_width" v-model="tempObj.menuKey" placeholder="请输入菜单 KEY" clearable />
|
||||
</div>
|
||||
<div class="menu_content">
|
||||
<span>菜单内容:</span>
|
||||
<el-select v-model="tempObj.type" clearable placeholder="请选择" class="menu_option">
|
||||
<el-option v-for="item in menuOptions" :label="item.label" :value="item.value" :key="item.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'view'">
|
||||
<span>跳转链接:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="请输入链接" clearable />
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'miniprogram'">
|
||||
<div class="applet">
|
||||
<span>小程序的 appid :</span>
|
||||
<el-input class="input_width" v-model="tempObj.miniProgramAppId" placeholder="请输入小程序的appid" clearable />
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的页面路径:</span>
|
||||
<el-input class="input_width" v-model="tempObj.miniProgramPagePath"
|
||||
placeholder="请输入小程序的页面路径,如:pages/index" clearable />
|
||||
</div>
|
||||
<div class="applet">
|
||||
<span>小程序的备用网页:</span>
|
||||
<el-input class="input_width" v-model="tempObj.url" placeholder="不支持小程序的老版本客户端将打开本网页" clearable />
|
||||
</div>
|
||||
<p class="blue">tips:需要和公众号进行关联才可以把小程序绑定带微信菜单上哟!</p>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'article_view_limited'">
|
||||
<el-row>
|
||||
<div class="select-item" v-if="tempObj && tempObj.replyArticles">
|
||||
<wx-news :articles="tempObj.replyArticles" />
|
||||
<el-row class="ope-row">
|
||||
<el-button type="danger" icon="el-icon-delete" circle @click="deleteMaterial" />
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-row>
|
||||
<el-col :span="24" style="text-align: center">
|
||||
<el-button type="success" @click="openMaterial">
|
||||
素材库选择<i class="el-icon-circle-check el-icon--right"></i>
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-dialog title="选择图文" :visible.sync="dialogNewsVisible" width="90%">
|
||||
<wx-material-select :objData="{type: 'news', accountId: this.accountId}" @selectMaterial="selectMaterial" />
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="configur_content" v-if="tempObj.type === 'click' || tempObj.type === 'scancode_waitmsg'">
|
||||
<wx-reply-select :objData="tempObj.reply" v-if="hackResetWxReplySelect" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 一进页面就显示的默认页面,当点击左边按钮的时候,就不显示了-->
|
||||
<div v-else class="right">
|
||||
<p>请选择菜单配置</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxReplySelect from '@/views/mp/components/wx-reply/main.vue'
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import WxMaterialSelect from '@/views/mp/components/wx-material-select/main.vue'
|
||||
import { deleteMenu, getMenuList, saveMenu } from "@/api/mp/menu";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
|
||||
export default {
|
||||
name: 'MpMenu',
|
||||
components: {
|
||||
WxReplySelect,
|
||||
WxNews,
|
||||
WxMaterialSelect
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
// ======================== 列表查询 ========================
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 查询参数
|
||||
accountId: undefined,
|
||||
name:'', // 公众号名
|
||||
menuList: {
|
||||
children: [],
|
||||
},
|
||||
|
||||
// ======================== 菜单操作 ========================
|
||||
isActive: -1,// 一级菜单点中样式
|
||||
isSubMenuActive: -1, // 一级菜单点中样式
|
||||
isSubMenuFlag: -1, // 二级菜单显示标志
|
||||
|
||||
// ======================== 菜单编辑 ========================
|
||||
showRightFlag: false, // 右边配置显示默认详情还是配置详情
|
||||
nameMaxLength: 0, // 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符;
|
||||
showConfigureContent: true, // 是否展示配置内容;如果有子菜单,就不显示配置内容
|
||||
hackResetWxReplySelect: false, // 重置 WxReplySelect 组件
|
||||
tempObj: {}, // 右边临时变量,作为中间值牵引关系
|
||||
tempSelfObj: { // 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数
|
||||
},
|
||||
dialogNewsVisible: false, // 跳转图文时的素材选择弹窗
|
||||
menuOptions: [{
|
||||
value: 'view',
|
||||
label: '跳转网页'
|
||||
}, {
|
||||
value: 'miniprogram',
|
||||
label: '跳转小程序'
|
||||
}, {
|
||||
value: 'click',
|
||||
label: '点击回复'
|
||||
}, {
|
||||
value: 'article_view_limited',
|
||||
label: '跳转图文消息'
|
||||
}, {
|
||||
value: 'scancode_push',
|
||||
label: '扫码直接返回结果'
|
||||
}, {
|
||||
value: 'scancode_waitmsg',
|
||||
label: '扫码回复'
|
||||
}, {
|
||||
value: 'pic_sysphoto',
|
||||
label: '系统拍照发图'
|
||||
}, {
|
||||
value: 'pic_photo_or_album',
|
||||
label: '拍照或者相册'
|
||||
}, {
|
||||
value: 'pic_weixin',
|
||||
label: '微信相册'
|
||||
}, {
|
||||
value: 'location_select',
|
||||
label: '选择地理位置'
|
||||
}],
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id);
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// ======================== 列表查询 ========================
|
||||
/** 设置账号编号 */
|
||||
setAccountId(accountId) {
|
||||
this.accountId = accountId;
|
||||
this.name = this.accounts.find(item => item.id === accountId)?.name;
|
||||
},
|
||||
getList() {
|
||||
this.loading = false;
|
||||
getMenuList(this.accountId).then(response => {
|
||||
response.data = this.convertMenuList(response.data);
|
||||
this.menuList = this.handleTree(response.data, "id");
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.resetForm();
|
||||
// 默认选中第一个
|
||||
if (this.accountId) {
|
||||
this.setAccountId(this.accountId)
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm();
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.setAccountId(this.accounts[0].id)
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
// 将后端返回的 menuList,转换成前端的 menuList
|
||||
convertMenuList(list) {
|
||||
const menuList = [];
|
||||
list.forEach(item => {
|
||||
const menu = {
|
||||
...item,
|
||||
};
|
||||
if (item.type === 'click' || item.type === 'scancode_waitmsg') {
|
||||
this.$delete(menu, 'replyMessageType');
|
||||
this.$delete(menu, 'replyContent');
|
||||
this.$delete(menu, 'replyMediaId');
|
||||
this.$delete(menu, 'replyMediaUrl');
|
||||
this.$delete(menu, 'replyDescription');
|
||||
this.$delete(menu, 'replyArticles');
|
||||
menu.reply = {
|
||||
type: item.replyMessageType,
|
||||
accountId: item.accountId,
|
||||
content: item.replyContent,
|
||||
mediaId: item.replyMediaId,
|
||||
url: item.replyMediaUrl,
|
||||
title: item.replyTitle,
|
||||
description: item.replyDescription,
|
||||
thumbMediaId: item.replyThumbMediaId,
|
||||
thumbMediaUrl: item.replyThumbMediaUrl,
|
||||
articles: item.replyArticles,
|
||||
musicUrl: item.replyMusicUrl,
|
||||
hqMusicUrl: item.replyHqMusicUrl,
|
||||
}
|
||||
}
|
||||
menuList.push(menu);
|
||||
});
|
||||
return menuList;
|
||||
},
|
||||
// 重置表单,清空表单数据
|
||||
resetForm() {
|
||||
// 菜单操作
|
||||
this.isActive = -1;
|
||||
this.isSubMenuActive = -1;
|
||||
this.isSubMenuFlag = -1;
|
||||
|
||||
// 菜单编辑
|
||||
this.showRightFlag = false;
|
||||
this.nameMaxLength = 0;
|
||||
this.showConfigureContent = 0;
|
||||
this.hackResetWxReplySelect = true;
|
||||
this.hackResetWxReplySelect = false;
|
||||
this.tempObj = {};
|
||||
this.tempSelfObj = {};
|
||||
this.dialogNewsVisible = false;
|
||||
},
|
||||
|
||||
// ======================== 菜单操作 ========================
|
||||
// 一级菜单点击事件
|
||||
menuClick(i, item) {
|
||||
// 右侧的表单相关
|
||||
this.resetEditor();
|
||||
this.showRightFlag = true; // 右边菜单
|
||||
this.tempObj = item; // 这个如果放在顶部,flag 会没有。因为重新赋值了。
|
||||
this.tempSelfObj.grand = "1"; // 表示一级菜单
|
||||
this.tempSelfObj.index = i; // 表示一级菜单索引
|
||||
this.nameMaxLength = 4
|
||||
this.showConfigureContent = !(item.children && item.children.length > 0); // 有子菜单,就不显示配置内容
|
||||
|
||||
// 左侧的选中
|
||||
this.isActive = i; // 一级菜单选中样式
|
||||
this.isSubMenuFlag = i; // 二级菜单显示标志
|
||||
this.isSubMenuActive = -1; // 二级菜单去除选中样式
|
||||
},
|
||||
// 二级菜单点击事件
|
||||
subMenuClick(subItem, index, k) {
|
||||
// 右侧的表单相关
|
||||
this.resetEditor();
|
||||
this.showRightFlag = true; // 右边菜单
|
||||
this.tempObj = subItem; // 将点击的数据放到临时变量,对象有引用作用
|
||||
this.tempSelfObj.grand = "2"; // 表示二级菜单
|
||||
this.tempSelfObj.index = index; // 表示一级菜单索引
|
||||
this.tempSelfObj.secondIndex = k; // 表示二级菜单索引
|
||||
this.nameMaxLength = 7
|
||||
this.showConfigureContent = true;
|
||||
|
||||
// 左侧的选中
|
||||
this.isActive = -1; // 一级菜单去除样式
|
||||
this.isSubMenuActive = index + "" + k; // 二级菜单选中样式
|
||||
},
|
||||
// 添加横向一级菜单
|
||||
addMenu() {
|
||||
const menuKeyLength = this.menuList.length;
|
||||
const addButton = {
|
||||
name: "菜单名称",
|
||||
children: [],
|
||||
reply: { // 用于存储回复内容
|
||||
'type': 'text',
|
||||
'accountId': this.accountId // 保证组件里,可以使用到对应的公众号
|
||||
}
|
||||
}
|
||||
this.$set(this.menuList, menuKeyLength, addButton)
|
||||
this.menuClick(this.menuKeyLength - 1, addButton)
|
||||
},
|
||||
// 添加横向二级菜单;item 表示要操作的父菜单
|
||||
addSubMenu(i, item) {
|
||||
// 清空父菜单的属性,因为它只需要 name 属性即可
|
||||
if (!item.children || item.children.length <= 0) {
|
||||
this.$set( item, 'children',[])
|
||||
this.$delete( item, 'type')
|
||||
this.$delete( item, 'menuKey')
|
||||
this.$delete( item, 'miniProgramAppId')
|
||||
this.$delete( item, 'miniProgramPagePath')
|
||||
this.$delete( item, 'url')
|
||||
this.$delete( item, 'reply')
|
||||
this.$delete( item, 'articleId')
|
||||
this.$delete( item, 'replyArticles')
|
||||
// 关闭配置面板
|
||||
this.showConfigureContent = false
|
||||
}
|
||||
|
||||
let subMenuKeyLength = item.children.length; // 获取二级菜单key长度
|
||||
let addButton = {
|
||||
name: "子菜单名称",
|
||||
reply: { // 用于存储回复内容
|
||||
'type': 'text',
|
||||
'accountId': this.accountId // 保证组件里,可以使用到对应的公众号
|
||||
}
|
||||
}
|
||||
this.$set(item.children, subMenuKeyLength, addButton);
|
||||
this.subMenuClick(item.children[subMenuKeyLength], i, subMenuKeyLength)
|
||||
},
|
||||
// 删除当前菜单
|
||||
deleteMenu(item) {
|
||||
this.$modal.confirm('确定要删除吗?').then(() => {
|
||||
// 删除数据
|
||||
if (this.tempSelfObj.grand === "1") { // 一级菜单的删除方法
|
||||
this.menuList.splice(this.tempSelfObj.index, 1);
|
||||
} else if (this.tempSelfObj.grand === "2") { // 二级菜单的删除方法
|
||||
this.menuList[this.tempSelfObj.index].children.splice(this.tempSelfObj.secondIndex, 1);
|
||||
}
|
||||
// 提示
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
|
||||
// 处理菜单的选中
|
||||
this.tempObj = {};
|
||||
this.showRightFlag = false;
|
||||
this.isActive = -1;
|
||||
this.isSubMenuActive = -1;
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
// ======================== 菜单编辑 ========================
|
||||
handleSave() {
|
||||
this.$modal.confirm('确定要保证并发布该菜单吗?').then(() => {
|
||||
this.loading = true
|
||||
return saveMenu(this.accountId, this.convertMenuFormList());
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("发布成功");
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
});
|
||||
},
|
||||
// 表单 Editor 重置
|
||||
resetEditor() {
|
||||
this.hackResetWxReplySelect = false // 销毁组件
|
||||
this.$nextTick(() => {
|
||||
this.hackResetWxReplySelect = true // 重建组件
|
||||
})
|
||||
},
|
||||
handleDelete() {
|
||||
this.$modal.confirm('确定要清空所有菜单吗?').then(() => {
|
||||
this.loading = true
|
||||
return deleteMenu(this.accountId);
|
||||
}).then(() => {
|
||||
this.handleQuery();
|
||||
this.$modal.msgSuccess("清空成功");
|
||||
}).catch(() => {}).finally(() => {
|
||||
this.loading = false
|
||||
});
|
||||
},
|
||||
// 将前端的 menuList,转换成后端接收的 menuList
|
||||
convertMenuFormList() {
|
||||
const menuList = [];
|
||||
this.menuList.forEach(item => {
|
||||
let menu = this.convertMenuForm(item);
|
||||
menuList.push(menu);
|
||||
// 处理子菜单
|
||||
if (!item.children || item.children.length <= 0) {
|
||||
return;
|
||||
}
|
||||
menu.children = [];
|
||||
item.children.forEach(subItem => {
|
||||
menu.children.push(this.convertMenuForm(subItem))
|
||||
})
|
||||
})
|
||||
return menuList;
|
||||
},
|
||||
// 将前端的 menu,转换成后端接收的 menu
|
||||
convertMenuForm(menu) {
|
||||
let result = {
|
||||
...menu,
|
||||
children: undefined, // 不处理子节点
|
||||
reply: undefined, // 稍后复制
|
||||
}
|
||||
if (menu.type === 'click' || menu.type === 'scancode_waitmsg') {
|
||||
result.replyMessageType = menu.reply.type;
|
||||
result.replyContent = menu.reply.content;
|
||||
result.replyMediaId = menu.reply.mediaId;
|
||||
result.replyMediaUrl = menu.reply.url;
|
||||
result.replyTitle = menu.reply.title;
|
||||
result.replyDescription = menu.reply.description;
|
||||
result.replyThumbMediaId = menu.reply.thumbMediaId;
|
||||
result.replyThumbMediaUrl = menu.reply.thumbMediaUrl;
|
||||
result.replyArticles = menu.reply.articles;
|
||||
result.replyMusicUrl = menu.reply.musicUrl;
|
||||
result.replyHqMusicUrl = menu.reply.hqMusicUrl;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
// ======================== 菜单编辑(素材选择) ========================
|
||||
openMaterial() {
|
||||
this.dialogNewsVisible = true
|
||||
},
|
||||
selectMaterial(item) {
|
||||
const articleId = item.articleId;
|
||||
const articles = item.content.newsItem;
|
||||
// 提示,针对多图文
|
||||
if (articles.length > 1) {
|
||||
this.$alert('您选择的是多图文,将默认跳转第一篇', '提示', {
|
||||
confirmButtonText: '确定'
|
||||
})
|
||||
}
|
||||
this.dialogNewsVisible = false
|
||||
|
||||
// 设置菜单的回复
|
||||
this.tempObj.articleId = articleId;
|
||||
this.tempObj.replyArticles = [];
|
||||
articles.forEach(article => {
|
||||
this.tempObj.replyArticles.push({
|
||||
title: article.title,
|
||||
description: article.digest,
|
||||
picUrl: article.picUrl,
|
||||
url: article.url,
|
||||
})
|
||||
})
|
||||
},
|
||||
deleteMaterial() {
|
||||
this.$delete(this.tempObj,'articleId')
|
||||
this.$delete(this.tempObj,'replyArticles')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<!--本组件样式-->
|
||||
<style lang="scss" scoped="scoped">
|
||||
/* 公共颜色变量 */
|
||||
.clearfix{*zoom:1;}
|
||||
.clearfix::after{content: "";display: table; clear: both;}
|
||||
div{
|
||||
text-align: left;
|
||||
}
|
||||
.weixin-hd{
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
bottom: 426px;
|
||||
left:0px;
|
||||
width: 300px;
|
||||
height:64px;
|
||||
background: transparent url("assets/menu_head.png") no-repeat 0 0;
|
||||
background-position: 0 0;
|
||||
background-size: 100%
|
||||
}
|
||||
.weixin-title{
|
||||
color:#fff;
|
||||
font-size:14px;
|
||||
width:100%;
|
||||
text-align: center;
|
||||
position:absolute;
|
||||
top: 33px;
|
||||
left: 0px;
|
||||
}
|
||||
.weixin-menu{
|
||||
background: transparent url("assets/menu_foot.png") no-repeat 0 0;
|
||||
padding-left: 43px;
|
||||
font-size: 12px
|
||||
}
|
||||
.menu_option{
|
||||
width: 40%!important;
|
||||
}
|
||||
.public-account-management{
|
||||
min-width: 1200px;
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
.left{
|
||||
float: left;
|
||||
display: inline-block;
|
||||
width: 350px;
|
||||
height: 715px;
|
||||
background: url("assets/iphone_backImg.png") no-repeat;
|
||||
background-size: 100% auto;
|
||||
padding: 518px 25px 88px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
/*第一级菜单*/
|
||||
.menu_main{
|
||||
.menu_bottom{
|
||||
position: relative;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 85.5px;
|
||||
text-align: center;
|
||||
border: 1px solid #ebedee;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
&.menu_addicon{
|
||||
height: 46px;
|
||||
line-height: 46px;
|
||||
}
|
||||
.menu_item{
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
&.active{
|
||||
border: 1px solid #2bb673;
|
||||
}
|
||||
}
|
||||
.menu_subItem{
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
&.active{
|
||||
border: 1px solid #2bb673;
|
||||
}
|
||||
}
|
||||
}
|
||||
i{
|
||||
color:#2bb673;
|
||||
}
|
||||
/*第二级菜单*/
|
||||
.submenu{
|
||||
position: absolute;
|
||||
width: 85.5px;
|
||||
bottom: 45px;
|
||||
.subtitle{
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
.save_div{
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
.save_btn{
|
||||
bottom: 20px;
|
||||
left: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*右边菜单内容*/
|
||||
.right {
|
||||
float: left;
|
||||
width: 63%;
|
||||
background-color: #e8e7e7;
|
||||
padding: 20px;
|
||||
margin-left: 20px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
.configure_page {
|
||||
.delete_btn {
|
||||
text-align: right;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.menu_content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.configur_content {
|
||||
margin-top: 20px;
|
||||
background-color: #fff;
|
||||
padding: 20px 10px;
|
||||
border-radius: 5px
|
||||
}
|
||||
.blue {
|
||||
color:#29b6f6;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.applet{
|
||||
margin-bottom: 20px;
|
||||
span{
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
.input_width {
|
||||
width: 40%;
|
||||
}
|
||||
.material{
|
||||
.input_width{
|
||||
width: 30%;
|
||||
}
|
||||
.el-textarea{
|
||||
width: 80%
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-input {
|
||||
width: 70%;
|
||||
margin-right: 2%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!--素材样式-->
|
||||
<style lang="scss" scoped>
|
||||
.pagination {
|
||||
text-align: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
.select-item {
|
||||
width: 280px;
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.select-item2 {
|
||||
padding: 10px;
|
||||
margin: 0 auto 10px auto;
|
||||
border: 1px solid #eaeaea;
|
||||
}
|
||||
.ope-row {
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
.item-name {
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,238 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号消息" url="https://doc.iocoder.cn/mp/message/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- TODO 等待处理 -->
|
||||
<el-form-item label="消息类型" prop="type">
|
||||
<el-select v-model="queryParams.type" placeholder="请选择消息类型" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.MP_MESSAGE_TYPE)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户标识" prop="openid">
|
||||
<el-input v-model="queryParams.openid" placeholder="请输入用户标识" clearable @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
|
||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="发送时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="消息类型" align="center" prop="type" width="80"/>
|
||||
<el-table-column label="发送方" align="center" prop="sendFrom" width="80">
|
||||
<template v-slot="scope">
|
||||
<el-tag v-if="scope.row.sendFrom === 1" type="success">粉丝</el-tag>
|
||||
<el-tag v-else type="info">公众号</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="用户标识" align="center" prop="openid" width="300" />
|
||||
<el-table-column label="内容" prop="content">
|
||||
<template v-slot="scope">
|
||||
<!-- 【事件】区域 -->
|
||||
<div v-if="scope.row.type === 'event' && scope.row.event === 'subscribe'">
|
||||
<el-tag type="success" size="mini">关注</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'unsubscribe'">
|
||||
<el-tag type="danger" size="mini">取消关注</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'CLICK'">
|
||||
<el-tag size="mini">点击菜单</el-tag>【{{ scope.row.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'VIEW'">
|
||||
<el-tag size="mini">点击菜单链接</el-tag>【{{ scope.row.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'scancode_waitmsg'">
|
||||
<el-tag size="mini">扫码结果</el-tag>【{{ scope.row.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'scancode_push'">
|
||||
<el-tag size="mini">扫码结果</el-tag>【{{ scope.row.eventKey }}】
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'pic_sysphoto'">
|
||||
<el-tag size="mini">系统拍照发图</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'pic_photo_or_album'">
|
||||
<el-tag size="mini">拍照或者相册</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'pic_weixin'">
|
||||
<el-tag size="mini">微信相册</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event' && scope.row.event === 'location_select'">
|
||||
<el-tag size="mini">选择地理位置</el-tag>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'event'">
|
||||
<el-tag type="danger" size="mini">未知事件类型</el-tag>
|
||||
</div>
|
||||
<!-- 【消息】区域 -->
|
||||
<div v-else-if="scope.row.type === 'text'">{{ scope.row.content }}</div>
|
||||
<div v-else-if="scope.row.type === 'voice'">
|
||||
<wx-voice-player :url="scope.row.mediaUrl" :content="scope.row.recognition" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'image'">
|
||||
<a target="_blank" :href="scope.row.mediaUrl">
|
||||
<img :src="scope.row.mediaUrl" style="width: 100px">
|
||||
</a>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'video' || scope.row.type === 'shortvideo'">
|
||||
<wx-video-player :url="scope.row.mediaUrl" style="margin-top: 10px" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'link'">
|
||||
<el-tag size="mini">链接</el-tag>:
|
||||
<a :href="scope.row.url" target="_blank">{{scope.row.title}}</a>
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'location'">
|
||||
<wx-location :label="scope.row.label" :location-y="scope.row.locationY" :location-x="scope.row.locationX" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'music'">
|
||||
<wx-music :title="scope.row.title" :description="scope.row.description" :thumb-media-url="scope.row.thumbMediaUrl"
|
||||
:music-url="scope.row.musicUrl" :hq-music-url="scope.row.hqMusicUrl" />
|
||||
</div>
|
||||
<div v-else-if="scope.row.type === 'news'">
|
||||
<wx-news :articles="scope.row.articles" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-tag type="danger" size="mini">未知消息类型</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleSend(scope.row)"
|
||||
v-hasPermi="['mp:message:send']">消息
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 发送消息的弹窗 -->
|
||||
<el-dialog title="粉丝消息列表" :visible.sync="open" width="50%">
|
||||
<wx-msg :user-id="userId" v-if="open" />
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue';
|
||||
import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue';
|
||||
import WxMsg from '@/views/mp/components/wx-msg/main.vue';
|
||||
import WxLocation from '@/views/mp/components/wx-location/main.vue';
|
||||
import WxMusic from '@/views/mp/components/wx-music/main.vue';
|
||||
import WxNews from '@/views/mp/components/wx-news/main.vue';
|
||||
import { getMessagePage } from "@/api/mp/message";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
|
||||
export default {
|
||||
name: "MpMessage",
|
||||
components: {
|
||||
WxVideoPlayer,
|
||||
WxVoicePlayer,
|
||||
WxMsg,
|
||||
WxLocation,
|
||||
WxMusic,
|
||||
WxNews
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 导出遮罩层
|
||||
exportLoading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 粉丝消息列表
|
||||
list: [],
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
openid: null,
|
||||
accountId: null,
|
||||
type: null,
|
||||
createTime: []
|
||||
},
|
||||
// 操作的用户编号
|
||||
userId: 0,
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询消息')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getMessagePage(this.queryParams).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
this.handleQuery();
|
||||
},
|
||||
handleSend(row) {
|
||||
this.userId = row.userId;
|
||||
this.open = true;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,364 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号统计" url="https://doc.iocoder.cn/mp/statistics/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form ref="queryForm" size="small" :inline="true" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="accountId" @change="getSummary">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间范围" prop="date">
|
||||
<el-date-picker v-model="date" style="width: 260px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
|
||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
:picker-options="datePickerOptions" :default-time="['00:00:00', '23:59:59']"
|
||||
@change="getSummary">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 图表 -->
|
||||
<el-row>
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header">
|
||||
<span>用户增减数据</span>
|
||||
</div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<div ref="userSummaryChart" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header">
|
||||
<span>累计用户数据</span>
|
||||
</div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<div ref="userCumulateChart" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header">
|
||||
<span>消息概况数据</span>
|
||||
</div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<div ref="upstreamMessageChart" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header">
|
||||
<span>接口分析数据</span>
|
||||
</div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<div ref="interfaceSummaryChart" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入基本模板
|
||||
import * as echarts from 'echarts'
|
||||
// 引入柱状图组件
|
||||
require('echarts/lib/chart/bar')
|
||||
// 引入柱拆线组件
|
||||
require('echarts/lib/chart/line')
|
||||
// 引入提示框和title组件
|
||||
require('echarts/lib/component/tooltip')
|
||||
require('echarts/lib/component/title')
|
||||
require('echarts/lib/component/legend')
|
||||
|
||||
import { getInterfaceSummary, getUserSummary, getUserCumulate, getUpstreamMessage} from '@/api/mp/statistics'
|
||||
import { datePickerOptions } from "@/utils/constants";
|
||||
import {addTime, beginOfDay, betweenDay, endOfDay, formatDate} from "@/utils/dateUtils";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
|
||||
export default {
|
||||
name: 'MpStatistics',
|
||||
data() {
|
||||
return {
|
||||
date : [beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7)), // -7 天
|
||||
endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))], // -1 天
|
||||
accountId: undefined,
|
||||
accounts: [],
|
||||
|
||||
xAxisDate: [], // X 轴的日期范围
|
||||
userSummaryOption: { // 用户增减数据
|
||||
color: ['#67C23A', '#e5323e'],
|
||||
legend: {
|
||||
data: ['新增用户','取消关注的用户']
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: [] // X 轴的日期范围
|
||||
},
|
||||
yAxis: {
|
||||
minInterval: 1
|
||||
},
|
||||
series: [{
|
||||
name: '新增用户',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
barGap: 0,
|
||||
data: [] // 新增用户的数据
|
||||
}, {
|
||||
name: '取消关注的用户',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 取消关注的用户的数据
|
||||
}]
|
||||
},
|
||||
userCumulateOption: { // 累计用户数据
|
||||
legend: {
|
||||
data: ['累计用户量']
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: []
|
||||
},
|
||||
yAxis: {
|
||||
minInterval: 1
|
||||
},
|
||||
series: [{
|
||||
name:'累计用户量',
|
||||
data: [], // 累计用户量的数据
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
}
|
||||
}]
|
||||
},
|
||||
upstreamMessageOption: { // 消息发送概况数据
|
||||
color: ['#67C23A', '#e5323e'],
|
||||
legend: {
|
||||
data: ['用户发送人数', '用户发送条数']
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: [] // X 轴的日期范围
|
||||
},
|
||||
yAxis: {
|
||||
minInterval: 1
|
||||
},
|
||||
series: [{
|
||||
name: '用户发送人数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 用户发送人数的数据
|
||||
}, {
|
||||
name: '用户发送条数',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 用户发送条数的数据
|
||||
}]
|
||||
},
|
||||
interfaceSummaryOption: { // 接口分析况数据
|
||||
color: ['#67C23A', '#e5323e', '#E6A23C', '#409EFF'],
|
||||
legend: {
|
||||
data: ['被动回复用户消息的次数','失败次数', '最大耗时','总耗时']
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: [] // X 轴的日期范围
|
||||
},
|
||||
yAxis: {},
|
||||
series: [{
|
||||
name: '被动回复用户消息的次数',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
barGap: 0,
|
||||
data: [] // 被动回复用户消息的次数的数据
|
||||
}, {
|
||||
name: '失败次数',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 失败次数的数据
|
||||
}, {
|
||||
name: '最大耗时',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 最大耗时的数据
|
||||
}, {
|
||||
name: '总耗时',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [] // 总耗时的数据
|
||||
}]
|
||||
},
|
||||
|
||||
// 静态变量
|
||||
datePickerOptions: datePickerOptions,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getSummary();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getSummary() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.accountId) {
|
||||
this.$message.error('未选中公众号,无法统计数据')
|
||||
return false
|
||||
}
|
||||
// 必须选择 7 天内,因为公众号有时间跨度限制为 7
|
||||
if (betweenDay(this.date[0], this.date[1]) >= 7) {
|
||||
this.$message.error('时间间隔 7 天以内,请重新选择')
|
||||
return false
|
||||
}
|
||||
this.xAxisDate = []
|
||||
const days = betweenDay(this.date[0], this.date[1]) // 相差天数
|
||||
for(let i = 0; i <= days; i++){
|
||||
this.xAxisDate.push(formatDate(addTime(this.date[0], 3600 * 1000 * 24 * i), 'yyyy-MM-dd'));
|
||||
}
|
||||
|
||||
// 初始化图表
|
||||
this.initUserSummaryChart();
|
||||
this.initUserCumulateChart();
|
||||
this.initUpstreamMessageChart();
|
||||
this.interfaceSummaryChart();
|
||||
},
|
||||
initUserSummaryChart() {
|
||||
this.userSummaryOption.xAxis.data = [];
|
||||
this.userSummaryOption.series[0].data = [];
|
||||
this.userSummaryOption.series[1].data = [];
|
||||
getUserSummary({
|
||||
accountId: this.accountId,
|
||||
date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),]
|
||||
}).then(response => {
|
||||
this.userSummaryOption.xAxis.data = this.xAxisDate;
|
||||
// 处理数据
|
||||
this.xAxisDate.forEach((date, index) => {
|
||||
response.data.forEach((item) => {
|
||||
// 匹配日期
|
||||
const refDate = formatDate(new Date(item.refDate), 'yyyy-MM-dd');
|
||||
if (refDate.indexOf(date) === -1) {
|
||||
return;
|
||||
}
|
||||
// 设置数据到对应的位置
|
||||
this.userSummaryOption.series[0].data[index] = item.newUser;
|
||||
this.userSummaryOption.series[1].data[index] = item.cancelUser;
|
||||
})
|
||||
})
|
||||
// 绘制图表
|
||||
const userSummaryChart = echarts.init(this.$refs.userSummaryChart);
|
||||
userSummaryChart.setOption(this.userSummaryOption)
|
||||
}).catch(() => {})
|
||||
},
|
||||
initUserCumulateChart() {
|
||||
this.userCumulateOption.xAxis.data = [];
|
||||
this.userCumulateOption.series[0].data = [];
|
||||
// 发起请求
|
||||
getUserCumulate({
|
||||
accountId: this.accountId,
|
||||
date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),]
|
||||
}).then(response => {
|
||||
this.userCumulateOption.xAxis.data = this.xAxisDate;
|
||||
// 处理数据
|
||||
response.data.forEach((item, index) => {
|
||||
this.userCumulateOption.series[0].data[index] = item.cumulateUser;
|
||||
})
|
||||
// 绘制图表
|
||||
const userCumulateChart = echarts.init(this.$refs.userCumulateChart);
|
||||
userCumulateChart.setOption(this.userCumulateOption)
|
||||
}).catch(() => {})
|
||||
},
|
||||
initUpstreamMessageChart() {
|
||||
this.upstreamMessageOption.xAxis.data = [];
|
||||
this.upstreamMessageOption.series[0].data = [];
|
||||
this.upstreamMessageOption.series[1].data = [];
|
||||
// 发起请求
|
||||
getUpstreamMessage({
|
||||
accountId: this.accountId,
|
||||
date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),]
|
||||
}).then(response => {
|
||||
this.upstreamMessageOption.xAxis.data = this.xAxisDate;
|
||||
// 处理数据
|
||||
response.data.forEach((item, index) => {
|
||||
this.upstreamMessageOption.series[0].data[index] = item.messageUser;
|
||||
this.upstreamMessageOption.series[1].data[index] = item.messageCount;
|
||||
})
|
||||
// 绘制图表
|
||||
const upstreamMessageChart = echarts.init(this.$refs.upstreamMessageChart);
|
||||
upstreamMessageChart.setOption(this.upstreamMessageOption);
|
||||
}).catch(() => {})
|
||||
},
|
||||
interfaceSummaryChart() {
|
||||
this.interfaceSummaryOption.xAxis.data = [];
|
||||
this.interfaceSummaryOption.series[0].data = [];
|
||||
this.interfaceSummaryOption.series[1].data = [];
|
||||
this.interfaceSummaryOption.series[2].data = [];
|
||||
this.interfaceSummaryOption.series[3].data = [];
|
||||
// 发起请求
|
||||
getInterfaceSummary({
|
||||
accountId: this.accountId,
|
||||
date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),]
|
||||
}).then(response => {
|
||||
this.interfaceSummaryOption.xAxis.data = this.xAxisDate;
|
||||
// 处理数据
|
||||
response.data.forEach((item, index) => {
|
||||
this.interfaceSummaryOption.series[0].data[index] = item.callbackCount;
|
||||
this.interfaceSummaryOption.series[1].data[index] = item.failCount;
|
||||
this.interfaceSummaryOption.series[2].data[index] = item.maxTimeCost;
|
||||
this.interfaceSummaryOption.series[3].data[index] = item.totalTimeCost;
|
||||
})
|
||||
// 绘制图表
|
||||
const interfaceSummaryChart = echarts.init(this.$refs.interfaceSummaryChart);
|
||||
interfaceSummaryChart.setOption(this.interfaceSummaryOption);
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,243 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号标签" url="https://doc.iocoder.cn/mp/tag/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入标签名称" clearable @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['mp:tag:create']">新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="el-icon-refresh" size="mini" @click="handleSync"
|
||||
v-hasPermi="['mp:tag:sync']">同步
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id"/>
|
||||
<el-table-column label="标签名称" align="center" prop="name"/>
|
||||
<el-table-column label="粉丝数" align="center" prop="count"/>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['mp:tag:update']">修改
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-hasPermi="['mp:tag:delete']">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="标签名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入标签名称"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createTag,
|
||||
updateTag,
|
||||
deleteTag,
|
||||
getTag,
|
||||
getTagPage,
|
||||
syncTag,
|
||||
} from '@/api/mp/tag'
|
||||
import { getSimpleAccounts} from '@/api/mp/account'
|
||||
|
||||
export default {
|
||||
name: 'MpTag',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 公众号标签列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: '',
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
accountId: null,
|
||||
name: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {
|
||||
accountId: undefined,
|
||||
name: undefined,
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [{ required: true, message: '请输入标签名称', trigger: 'blur' }]
|
||||
},
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询标签')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams}
|
||||
// 执行查询
|
||||
getTagPage(params).then(response => {
|
||||
this.list = response.data.list
|
||||
this.total = response.data.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
accountId: undefined,
|
||||
name: undefined,
|
||||
}
|
||||
this.resetForm('form')
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = '添加公众号标签'
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id
|
||||
getTag(id).then(response => {
|
||||
this.form = response.data
|
||||
this.open = true
|
||||
this.title = '修改公众号标签'
|
||||
})
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.form.accountId = this.queryParams.accountId;
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateTag(this.form).then(response => {
|
||||
this.$modal.msgSuccess('修改成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
return
|
||||
}
|
||||
// 添加的提交
|
||||
createTag(this.form).then(response => {
|
||||
this.$modal.msgSuccess('新增成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id
|
||||
this.$modal.confirm('是否确认删除公众号标签编号为"' + id + '"的数据项?').then(function () {
|
||||
return deleteTag(id)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
/** 同步标签 */
|
||||
handleSync() {
|
||||
const accountId = this.queryParams.accountId
|
||||
this.$modal.confirm('是否确认同步标签?').then(function () {
|
||||
return syncTag(accountId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('同步标签成功')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<doc-alert title="公众号粉丝" url="https://doc.iocoder.cn/mp/user/" />
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="公众号" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择公众号">
|
||||
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户标识" prop="openid">
|
||||
<el-input v-model="queryParams.openid" placeholder="请输入用户标识" clearable @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="queryParams.nickname" placeholder="请输入昵称" clearable @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="el-icon-refresh" size="mini" @click="handleSync"
|
||||
v-hasPermi="['mp:user:sync']">同步
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="编号" align="center" prop="id" />
|
||||
<el-table-column label="用户标识" align="center" prop="openid" width="260" />
|
||||
<el-table-column label="昵称" align="center" prop="nickname" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="标签" align="center" prop="tagIds" width="200">
|
||||
<template v-slot="scope">
|
||||
<span v-for="(tagId, index) in scope.row.tagIds" :key="index">
|
||||
<el-tag>{{ tags.find(tag => tag.tagId === tagId)?.name }} </el-tag>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订阅状态" align="center" prop="subscribeStatus">
|
||||
<template v-slot="scope">
|
||||
<el-tag v-if="scope.row.subscribeStatus === 0" type="success">已订阅</el-tag>
|
||||
<el-tag v-else type="danger">未订阅</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订阅时间" align="center" prop="subscribeTime" width="180">
|
||||
<template v-slot="scope">
|
||||
<span>{{ parseTime(scope.row.subscribeTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['mp:user:update']">修改</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="form.nickname" placeholder="请输入昵称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="标签" prop="tagIds">
|
||||
<el-select v-model="form.tagIds" multiple clearable placeholder="请选择标签">
|
||||
<el-option v-for="item in tags" :key="parseInt(item.tagId)" :label="item.name" :value="parseInt(item.tagId)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updateUser, getUser, getUserPage, syncUser } from "@/api/mp/mpuser";
|
||||
import { getSimpleAccounts } from "@/api/mp/account";
|
||||
import { getSimpleTags } from "@/api/mp/tag";
|
||||
|
||||
export default {
|
||||
name: "MpUser",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 微信公众号粉丝列表
|
||||
list: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
accountId: null,
|
||||
openid: null,
|
||||
nickname: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {},
|
||||
|
||||
// 公众号账号列表
|
||||
accounts: [],
|
||||
// 公众号标签列表
|
||||
tags: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
getSimpleAccounts().then(response => {
|
||||
this.accounts = response.data;
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
// 加载数据
|
||||
this.getList();
|
||||
})
|
||||
|
||||
// 加载标签
|
||||
getSimpleTags().then(response => {
|
||||
this.tags = response.data;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
// 如果没有选中公众号账号,则进行提示。
|
||||
if (!this.queryParams.accountId) {
|
||||
this.$message.error('未选中公众号,无法查询用户')
|
||||
return false
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
// 处理查询参数
|
||||
let params = {...this.queryParams};
|
||||
// 执行查询
|
||||
getUserPage(params).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
nickname: undefined,
|
||||
remark: undefined,
|
||||
tagIds: [],
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
// 默认选中第一个
|
||||
if (this.accounts.length > 0) {
|
||||
this.queryParams.accountId = this.accounts[0].id;
|
||||
}
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
getUser(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改公众号粉丝";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateUser(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 同步标签 */
|
||||
handleSync() {
|
||||
const accountId = this.queryParams.accountId
|
||||
this.$modal.confirm('是否确认同步粉丝?').then(function () {
|
||||
return syncUser(accountId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('开始从微信公众号同步粉丝信息,同步需要一段时间,建议稍后再查询')
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -55,7 +55,6 @@
|
||||
:has-files="true"
|
||||
:disabled="editMode === 'detail'"
|
||||
:rows="computedRows" />
|
||||
<!-- :has-files="['files', 'files2']" -->
|
||||
</base-dialog>
|
||||
|
||||
<!-- 设备 详情 - 编辑 -->
|
||||
@@ -134,7 +133,7 @@ export default {
|
||||
components: {
|
||||
Editor,
|
||||
EquipmentDrawer,
|
||||
BaseDialog: BaseDialogWrapper
|
||||
BaseDialog: BaseDialogWrapper,
|
||||
},
|
||||
mixins: [basicPageMixin],
|
||||
data() {
|
||||
@@ -161,13 +160,6 @@ export default {
|
||||
: undefined,
|
||||
].filter((v) => v),
|
||||
tableProps: [
|
||||
// {
|
||||
// prop: 'createTime',
|
||||
// label: '添加时间',
|
||||
// fixed: true,
|
||||
// width: 180,
|
||||
// filter: (val) => moment(val).format('yyyy-MM-DD HH:mm:ss'),
|
||||
// },
|
||||
{ prop: 'name', label: '设备名称' },
|
||||
{ width: 256, prop: 'code', label: '设备编码' },
|
||||
{ prop: 'location', label: '位置' },
|
||||
@@ -413,34 +405,16 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['drawer'].init();
|
||||
});
|
||||
// this.reset();
|
||||
// this.showUploadComponents = false;
|
||||
// this.editMode = 'edit';
|
||||
// const id = row.id;
|
||||
// getEquipment(id).then((response) => {
|
||||
// this.form = response.data;
|
||||
// this.open = true;
|
||||
// this.title = '修改设备';
|
||||
// });
|
||||
},
|
||||
handleDetail(row, mode='detail') {
|
||||
const {id} = row;
|
||||
handleDetail(row, mode = 'detail') {
|
||||
const { id } = row;
|
||||
this.form.id = id;
|
||||
// 打开抽屉
|
||||
this.editMode = mode;
|
||||
this.editVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs['drawer'].init();
|
||||
})
|
||||
// this.reset();
|
||||
// this.showUploadComponents = false;
|
||||
// const id = row.id;
|
||||
// this.editMode = 'detail';
|
||||
// getEquipment(id).then((response) => {
|
||||
// this.form = response.data;
|
||||
// this.open = true;
|
||||
// this.title = '查看详情';
|
||||
// });
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
@@ -514,33 +488,6 @@ export default {
|
||||
this.$refs['drawer'].init();
|
||||
});
|
||||
},
|
||||
// overwrite basicPageMixin 里的 处理表格按钮 方法
|
||||
// handleTableBtnClick({ data, type }) {
|
||||
// switch (type) {
|
||||
// case 'edit':
|
||||
// this.reset();
|
||||
// this.editMode = 'edit';
|
||||
// this.showUploadComponents = true;
|
||||
// this.form.id = data.id;
|
||||
// this.editVisible = true;
|
||||
// this.$nextTick(() => {
|
||||
// this.$refs['drawer'].init();
|
||||
// });
|
||||
// break;
|
||||
// case 'delete':
|
||||
// this.handleDelete(data);
|
||||
// break;
|
||||
// case 'detail':
|
||||
// const { id } = data;
|
||||
// this.viewDetail(id);
|
||||
// break;
|
||||
// }
|
||||
// },
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.SpecialEquipmentForFireFighting {
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -177,7 +177,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import './iconfont/iconfont.css';
|
||||
@import '../../../styles/iconfont/iconfont.css';
|
||||
.delete-color {
|
||||
color: #ff5454;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<el-date-picker
|
||||
v-model="dataForm.planCheckTime"
|
||||
type="datetime"
|
||||
placeholder="请选择计划开始时间"
|
||||
placeholder="请选择巡检时间"
|
||||
value-format="timestamp"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -107,6 +107,9 @@ export default {
|
||||
name: [
|
||||
{ required: true, message: '巡检单名称不能为空', trigger: 'blur' },
|
||||
],
|
||||
planCheckTime: [
|
||||
{ required: true, message: '巡检时间不能为空', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
equipmentOptions: [],
|
||||
groupOptions: [],
|
||||
|
||||
@@ -145,7 +145,7 @@ export default {
|
||||
equipmentId: null,
|
||||
},
|
||||
attrFormVisible: false,
|
||||
attrRows: [
|
||||
attrRows: [
|
||||
[
|
||||
{
|
||||
select: true,
|
||||
@@ -157,16 +157,8 @@ export default {
|
||||
],
|
||||
bind: {
|
||||
clearable: true,
|
||||
filterable: true
|
||||
}
|
||||
},
|
||||
{
|
||||
input: true,
|
||||
label: '巡检项目',
|
||||
prop: 'program',
|
||||
rules: [
|
||||
{ required: true, message: '巡检项目不能为空', trigger: 'blur' },
|
||||
],
|
||||
filterable: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
<div class="drawer-body flex">
|
||||
<div class="drawer-body__content">
|
||||
<div class="form-part" style="margin-bottom: 32px">
|
||||
<div
|
||||
class="form-part"
|
||||
style="margin-bottom: 32px">
|
||||
<!-- <el-skeleton v-if="!showForm" animated /> -->
|
||||
<el-form
|
||||
class="equipment-info-form"
|
||||
@@ -49,7 +51,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="部门" prop="departmentId">
|
||||
<el-form-item
|
||||
label="部门"
|
||||
prop="departmentId">
|
||||
<el-select
|
||||
v-model="form.departmentId"
|
||||
filterable
|
||||
@@ -66,7 +70,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="班次" prop="groupClass">
|
||||
<el-form-item
|
||||
label="班次"
|
||||
prop="groupClass">
|
||||
<el-select
|
||||
v-model="form.groupClass"
|
||||
filterable
|
||||
@@ -85,7 +91,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="巡检人" prop="checkPerson">
|
||||
<el-form-item
|
||||
label="巡检人"
|
||||
prop="checkPerson">
|
||||
<!-- :rules="[
|
||||
{
|
||||
required: true,
|
||||
@@ -110,7 +118,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="巡检时间" prop="planCheckTime">
|
||||
<el-form-item
|
||||
label="巡检时间"
|
||||
prop="planCheckTime">
|
||||
<el-date-picker
|
||||
v-model="form.planCheckTime"
|
||||
type="datetime"
|
||||
@@ -142,7 +152,9 @@
|
||||
<div
|
||||
v-if="!disableEdit && !disableModifyDetail"
|
||||
style="position: absolute; top: -40px; right: 0">
|
||||
<el-button @click="handleAddAttr" type="text">
|
||||
<el-button
|
||||
@click="handleAddAttr"
|
||||
type="text">
|
||||
<i class="el-icon-plus"></i>
|
||||
添加内容
|
||||
</el-button>
|
||||
@@ -173,7 +185,9 @@
|
||||
</div>
|
||||
|
||||
<div class="drawer-body__footer">
|
||||
<el-button v-if="!disableEdit" @click="handleCancel">
|
||||
<el-button
|
||||
v-if="!disableEdit"
|
||||
@click="handleCancel">
|
||||
{{ disableEdit ? '返回' : '取消' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -254,7 +268,7 @@ export default {
|
||||
bind: {
|
||||
filterable: true,
|
||||
clearable: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
@close="cancel"
|
||||
@cancel="cancel"
|
||||
@confirm="handleSubmit">
|
||||
<add ref="add" @refreshDataList="successSubmit" />
|
||||
<add
|
||||
ref="add"
|
||||
@refreshDataList="successSubmit" />
|
||||
</base-dialog>
|
||||
|
||||
<edit
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3821755 */
|
||||
src: url('iconfont.eot?t=1689233106339'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1689233106339#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARgAAsAAAAACcAAAAQUAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDKAqGSIUsATYCJAMYCw4ABCAFhGcHVBtUCMiuMG7hiaIkox1FaBhxvd1fpwAN4YKo1v7tWTr8hBRkBQgO7yqKUJKPUKzDjkixjn7/q0vlANCkEHCJtsMvx2eQn04h5rHEE8593TK2y1SC5nbvNG5gqgZBNEWTqFUQLGVFNnVu1TjyMm3SafEsC3y0myW12KdEh2x+deP/zzHTJeG3AVBm4lrnAxpQN0US7s3ijuSE6Jbh1UGv08cgQEivMg5z6m49Qj77TVxDEZww6gXicNkviSbkxgswNeGCj+CgMw1yFRpAnUNegSv+8+UfU/igsBpjnRV3rRV9+Su8Fk1Agv6CW4eAeyvAAhronJlI1tcrVnIMHZ0cCcsUTrRTnQ0CP50B4KfgEub9Lw80BougQBwGI8bYJU4LPwUbBw0/HXAw8NORUM90wsT9JeIMFACux9QckHyQ9FDYTobcGi+FLSjwMxDe3L5s+w9THFYeEs8H303FWMnZ1JuBWFgNPh3bd5wOvJmKI9aTqXeD8eJ66HnfnV1dJPE8cy4EgqT+s/SbdSWbp9Pn24NbZ1MnGw7CDbvT6+lL1CXVh++hcH56umDT9vOviL/grQ6srHjE57uLHdQn+dtO9x2v94WN6+eXm0HWlZOzta3tUDp1JWjymsiD8r0ViWGkC+n4GeH5aODSM+9COnilpdfdZsRIvMerLmS0uICTplrOnb99LT3NkJNeajPfpDznblq6bXH8efBjlPIUxhQcX+U0qEdt4bjxy6rMdOkbEn0/3mlvrXZL60ysxdwcn/qKLJ/82pnzGS61z5rBeGmrxf33ZXN/IBWUvb8KSvnttbwwq+YTkweZHue0M0+c0ssZGY/Rs+aVF8+3GaW07CkvLC/KcBvP8c2uGpsdm0THlazwlPE22Kdi9ZK4Hdsmtw9eHVQwPjG0p33Q7tGMJ6TUJ2VK1MMw6ftI6qPPtruCvEPmLZqiHcj1Aw3Rup/sdzj+lt/w3f5TrAHgx++nD7A+8xaD4CL8m60Q+KWYO7CgUY3gTFl+OwUBHKteh00BoWmGDIYm301frAJwKAg+BTEoPCpA41OPNNh2sET0g8NnCkI61M6PKKBzREwANBtGIOS6BEU2D0CT6xvSYP+Apdg/cOT6DyErI68W0RzbqhmYOFixuRNLFqoRi839Zh+A2KqYWJH1CTC7hM04My0j664HDVgXY+xtYhbnBBNGVVzH7geKQrHOqA0sPK2Fc70oPZ2UPSTNQlVUjQEmHLDCzDphEgtKQ9zCPP16DwBRK4UJAyKfyBg7jaeaxzKlyQAg6xkaKO9M2tu1EWXhOEL3IxhKhdWpMqCYDgrTy7vZAAsuTUsLm65IOlWIQBlp47PUS9wAhBgHOFGixYgVJx7+dtqutZuY1eXTvXYncJOkOF1Wicd+CnBACA==') format('woff2'),
|
||||
url('iconfont.woff?t=1689233106339') format('woff'),
|
||||
url('iconfont.ttf?t=1689233106339') format('truetype'),
|
||||
url('iconfont.svg?t=1689233106339#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-downward:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-upward:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-detail:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-edit:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-delete:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"id": "3821755",
|
||||
"name": "component",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "封装的组件中的icon",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "36426261",
|
||||
"name": "downward",
|
||||
"font_class": "downward",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "36426301",
|
||||
"name": "upward",
|
||||
"font_class": "upward",
|
||||
"unicode": "e605",
|
||||
"unicode_decimal": 58885
|
||||
},
|
||||
{
|
||||
"icon_id": "33347867",
|
||||
"name": "detail",
|
||||
"font_class": "detail",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "33347918",
|
||||
"name": "edit",
|
||||
"font_class": "edit",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "33347930",
|
||||
"name": "delete",
|
||||
"font_class": "delete",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Created by iconfont</metadata>
|
||||
<defs>
|
||||
<font id="iconfont" horiz-adv-x="1024">
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="400"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="downward" unicode="" d="M556.942222 144.099556l363.064889 401.806222c24.860444 21.617778 24.860444 56.263111 0 77.880889a68.437333 68.437333 0 0 1-44.942222 16.156444c-16.896 0-33.052444-5.859556-44.885333-16.156444L512 260.949333l-318.236444 362.951111a68.437333 68.437333 0 0 1-44.942223 16.099556c-16.896 0-33.109333-5.802667-44.942222-16.156444-24.746667-21.617778-24.746667-56.206222 0-77.824l363.121778-401.749334c5.973333-5.290667 13.141333-9.443556 21.048889-12.231111 23.722667-8.305778 51.029333-3.527111 68.892444 12.060445z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="upward" unicode="" d="M556.942222 623.900444l363.064889-401.806222c24.860444-21.617778 24.860444-56.263111 0-77.880889a68.437333 68.437333 0 0 0-44.942222-16.156444c-16.896 0-33.052444 5.859556-44.885333 16.156444L512 507.050667l-318.236444-362.951111a68.437333 68.437333 0 0 0-44.942223-16.099556c-16.896 0-33.109333 5.802667-44.942222 16.156444-24.746667 21.617778-24.746667 56.206222 0 77.824L467.057778 623.729778c5.973333 5.290667 13.141333 9.443556 21.048889 12.231111 23.722667 8.305778 51.029333 3.527111 68.892444-12.060445z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="detail" unicode="" d="M902.428444 705.251556H332.401778a7.964444 7.964444 0 0 1-7.793778-8.021334v-56.206222a7.964444 7.964444 0 0 1 7.793778-8.078222h570.026666A7.964444 7.964444 0 0 1 910.222222 641.024v56.206222a7.964444 7.964444 0 0 1-7.793778 8.021334z m0-285.127112H332.401778a7.964444 7.964444 0 0 1-7.793778-7.964444v-56.32a7.964444 7.964444 0 0 1 7.793778-7.964444h570.026666a7.964444 7.964444 0 0 1 7.793778 7.964444v56.32a7.964444 7.964444 0 0 1-7.793778 7.964444z m0-285.070222H332.401778a7.964444 7.964444 0 0 1-7.793778-8.078222v-56.206222a7.964444 7.964444 0 0 1 7.793778-8.021334h570.026666a7.964444 7.964444 0 0 1 7.793778 8.021334v56.206222a7.964444 7.964444 0 0 1-7.793778 8.078222zM113.777778 669.127111c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0 56.547556 56.547556 0 0 1 27.306666 48.696889 56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0A56.547556 56.547556 0 0 1 113.777778 669.127111zM113.777778 384c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0A56.547556 56.547556 0 0 1 223.061333 384a56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0A56.547556 56.547556 0 0 1 113.777778 384z m0-285.127111c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0 56.547556 56.547556 0 0 1 27.306666 48.696889 56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0 56.547556 56.547556 0 0 1-27.363555-48.696889z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="edit" unicode="" d="M873.016889 395.264a32.824889 32.824889 0 0 0 65.649778 0v-273.806222a164.124444 164.124444 0 0 0-164.124445-164.124445h-525.084444A164.124444 164.124444 0 0 0 85.333333 121.457778v525.084444A164.124444 164.124444 0 0 0 249.457778 810.666667h312.32a32.824889 32.824889 0 1 0 0-65.649778h-312.32a98.417778 98.417778 0 0 1-98.474667-98.417778v-525.141333c0-54.385778 44.088889-98.474667 98.417778-98.474667h525.141333a98.417778 98.417778 0 0 1 98.474667 98.417778V395.320889z m-14.222222 362.097778a32.824889 32.824889 0 0 0 48.014222-44.771556L548.750222 328.533333a32.824889 32.824889 0 1 0-48.014222 44.771556l358.115556 384.056889z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="delete" unicode="" d="M601.024 146.24a29.632 29.632 0 0 0-29.696 29.696V503.04a29.632 29.632 0 1 0 59.456 0v-326.848a29.76 29.76 0 0 0-29.76-29.888z m-178.24 0a29.632 29.632 0 0 0-29.696 29.696V503.04a29.632 29.632 0 1 0 59.392 0v-326.848a29.76 29.76 0 0 0-29.696-29.888z m475.52 505.216h-148.544v59.456c0 49.152-39.616 89.088-88.512 89.088H363.392c-49.216 0-89.152-39.936-89.152-89.088v-59.456H125.696a29.632 29.632 0 1 1 0-59.392h772.608a29.632 29.632 0 1 1 0 59.392z m-564.608 59.456c0 16.256 13.44 29.696 29.696 29.696h297.856c16.32 0 29.056-13.12 29.056-29.696v-59.456H333.696v59.456zM720-32h-416a89.152 89.152 0 0 0-89.088 89.088V503.232a29.632 29.632 0 1 0 59.456 0v-446.08c0-16.512 13.44-29.76 29.696-29.76h416.064a29.632 29.632 0 0 1 29.696 29.696V502.144a29.632 29.632 0 1 0 59.456 0v-445.056A89.536 89.536 0 0 0 720-32z" horiz-adv-x="1024" />
|
||||
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
@@ -20,8 +20,9 @@
|
||||
|
||||
<div class="drawer-body flex">
|
||||
<div class="drawer-body__content">
|
||||
<div class="form-part" style="margin-bottom: 32px">
|
||||
<!-- <el-skeleton v-if="!showForm" animated /> -->
|
||||
<div
|
||||
class="form-part"
|
||||
style="margin-bottom: 32px">
|
||||
<el-form
|
||||
class="equipment-info-form"
|
||||
ref="form"
|
||||
@@ -31,7 +32,9 @@
|
||||
v-loading="formLoading">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="保养计划单号" prop="maintainOrderNumber">
|
||||
<el-form-item
|
||||
label="保养计划单号"
|
||||
prop="maintainOrderNumber">
|
||||
<!-- :rules="[
|
||||
{
|
||||
required: true,
|
||||
@@ -47,7 +50,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="保养计划名称" prop="planName">
|
||||
<el-form-item
|
||||
label="保养计划名称"
|
||||
prop="planName">
|
||||
<el-input
|
||||
v-model="form.planName"
|
||||
placeholder="请输入保养计划名称"
|
||||
@@ -56,10 +61,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="部门" prop="departmentId">
|
||||
<!-- :rules="[
|
||||
{ required: true, message: '请选择部门', trigger: 'blur' },
|
||||
]" -->
|
||||
<el-form-item
|
||||
label="部门"
|
||||
prop="departmentId">
|
||||
<el-select
|
||||
v-model="form.departmentId"
|
||||
:placeholder="`请选择部门`"
|
||||
@@ -76,7 +80,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="产线" prop="lineId">
|
||||
<el-form-item
|
||||
label="产线"
|
||||
prop="lineId">
|
||||
<!-- :rules="[
|
||||
{ required: true, message: '请选择产线', trigger: 'blur' },
|
||||
]" -->
|
||||
@@ -96,7 +102,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划保养人员" prop="maintainer">
|
||||
<el-form-item
|
||||
label="计划保养人员"
|
||||
prop="maintainer">
|
||||
<el-select
|
||||
v-model="form.planMaintainWorker"
|
||||
placeholder="请选择计划保养人员"
|
||||
@@ -107,7 +115,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划开始时间" prop="planStartTime">
|
||||
<el-form-item
|
||||
label="计划开始时间"
|
||||
prop="planStartTime">
|
||||
<el-date-picker
|
||||
v-model="form.planStartTime"
|
||||
type="datetime"
|
||||
@@ -118,7 +128,9 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划结束时间" prop="planEndTime">
|
||||
<el-form-item
|
||||
label="计划结束时间"
|
||||
prop="planEndTime">
|
||||
<el-date-picker
|
||||
v-model="form.planEndTime"
|
||||
type="datetime"
|
||||
@@ -193,8 +205,12 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" :placeholder="`请输入备注`" />
|
||||
<el-form-item
|
||||
label="备注"
|
||||
prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
:placeholder="`请输入备注`" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -223,13 +239,7 @@
|
||||
:page="attrQuery?.params.pageNo || 1"
|
||||
:limit="attrQuery?.params.pageSize || 10"
|
||||
:table-data="attrList"
|
||||
@emitFun="handleEmitFun">
|
||||
<!-- <method-btn
|
||||
slot="handleBtn"
|
||||
label="操作"
|
||||
:method-list="tableBtn"
|
||||
@clickBtn="handleTableBtnClick" /> -->
|
||||
</base-table>
|
||||
@emitFun="handleEmitFun"></base-table>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<pagination
|
||||
@@ -242,15 +252,16 @@
|
||||
</div>
|
||||
|
||||
<div class="drawer-body__footer">
|
||||
<el-button style="" @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">保存</el-button>
|
||||
<!-- sections的第二项必须是 属性列表 -->
|
||||
<!-- <el-button
|
||||
v-if="sections[1].allowAdd"
|
||||
type="primary"
|
||||
@click="handleAddAttr">
|
||||
添加属性
|
||||
</el-button> -->
|
||||
<el-button
|
||||
style=""
|
||||
@click="handleCancel">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleConfirm">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -385,12 +396,6 @@ export default {
|
||||
label: '设备名称',
|
||||
prop: 'equipmentId',
|
||||
url: '/base/core-equipment/page?pageNo=1&pageSize=100&special=true',
|
||||
// method: 'post',
|
||||
// queryParams: {
|
||||
// pageNo: 1,
|
||||
// pageSize: 100,
|
||||
// special: true,
|
||||
// },
|
||||
rules: [
|
||||
{ required: true, message: '设备不能为空', trigger: 'blur' },
|
||||
],
|
||||
@@ -441,7 +446,6 @@ export default {
|
||||
],
|
||||
attrFormSubmitting: false,
|
||||
attrListLoading: false,
|
||||
// syncFileListFlag: null,
|
||||
tableBtn: [
|
||||
{
|
||||
type: 'edit',
|
||||
@@ -599,7 +603,6 @@ export default {
|
||||
'/base/core-production-line/listAll',
|
||||
'/base/core-department/listAll',
|
||||
'/base/core-worker/workerList',
|
||||
// '/base/core-worker/listAll',
|
||||
];
|
||||
let res;
|
||||
switch (source) {
|
||||
@@ -619,22 +622,6 @@ export default {
|
||||
this.formLoading = false;
|
||||
},
|
||||
|
||||
// 保存表单
|
||||
handleSave() {
|
||||
this.$refs.form.validate(async (valid) => {
|
||||
if (valid) {
|
||||
await this.$axios({
|
||||
url: '/urlupdate', // this.sections[0][isEdit ? 'urlUpdate' : 'urlCreate'],
|
||||
method: 'post', // isEdit ? 'put' : 'post',
|
||||
data: this.form,
|
||||
});
|
||||
this.$modal.msgSuccess(`${isEdit ? '更新' : '创建'}成功`);
|
||||
this.visible = false;
|
||||
this.$emit('refreshDataList');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleCancel() {
|
||||
this.visible = false;
|
||||
},
|
||||
|
||||
@@ -20,17 +20,27 @@
|
||||
type="selection"
|
||||
:width="50"
|
||||
:selectable="checkSelectable" />
|
||||
<el-table-column prop="_pageIndex" width="80" align="center">
|
||||
<el-table-column
|
||||
prop="_pageIndex"
|
||||
width="80"
|
||||
align="center">
|
||||
<template slot="header">
|
||||
<el-popover placement="bottom-start" width="300" trigger="click">
|
||||
<div class="setting-box" style="max-height: 400px; overflow-y: auto">
|
||||
<el-popover
|
||||
placement="bottom-start"
|
||||
width="300"
|
||||
trigger="click">
|
||||
<div
|
||||
class="setting-box"
|
||||
style="max-height: 400px; overflow-y: auto">
|
||||
<el-checkbox
|
||||
v-for="(item, index) in tablePropsLabelList"
|
||||
:key="'cb' + index"
|
||||
v-model="selectedBox[index]"
|
||||
:label="item.label" />
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-s-tools" />
|
||||
<i
|
||||
slot="reference"
|
||||
class="el-icon-s-tools" />
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -39,17 +49,27 @@
|
||||
width="128"
|
||||
label="设备保养单号"
|
||||
prop="maintainOrderNumber"></el-table-column>
|
||||
<el-table-column v-if="selectedBox[1]" width="128" label="保养计划名称" prop="planName">
|
||||
<el-table-column
|
||||
v-if="selectedBox[1]"
|
||||
width="128"
|
||||
label="保养计划名称"
|
||||
prop="planName">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.planName || '---' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="selectedBox[2]" label="部门" prop="departmentName">
|
||||
<el-table-column
|
||||
v-if="selectedBox[2]"
|
||||
label="部门"
|
||||
prop="departmentName">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.departmentName || '---' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="selectedBox[3]" label="产线名" prop="lineName">
|
||||
<el-table-column
|
||||
v-if="selectedBox[3]"
|
||||
label="产线名"
|
||||
prop="lineName">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.lineName || '---' }}
|
||||
</template>
|
||||
@@ -108,15 +128,13 @@
|
||||
{{ scope.row.relatePlan | relatePlanFilter }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column v-if="selectedBox[10]" width="60" label="详情">
|
||||
<el-table-column
|
||||
width="188"
|
||||
label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="handelDetail(scope.row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<!-- btns -->
|
||||
<el-table-column width="188" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip content="确认" placement="top">
|
||||
<el-tooltip
|
||||
content="确认"
|
||||
placement="top">
|
||||
<el-button
|
||||
type="text"
|
||||
style="margin: 5px 0; padding: 0"
|
||||
@@ -127,7 +145,9 @@
|
||||
</el-tooltip>
|
||||
<!-- line -->
|
||||
<span style="margin: 0 4px; font-size: 18px; color: #e5e7eb">|</span>
|
||||
<el-tooltip content="查看详情" placement="top">
|
||||
<el-tooltip
|
||||
content="查看详情"
|
||||
placement="top">
|
||||
<el-button
|
||||
type="text"
|
||||
style="margin: 5px 0; padding: 0"
|
||||
@@ -137,7 +157,9 @@
|
||||
</el-tooltip>
|
||||
<!-- line -->
|
||||
<span style="margin: 0 4px; font-size: 18px; color: #e5e7eb">|</span>
|
||||
<el-tooltip content="编辑" placement="top">
|
||||
<el-tooltip
|
||||
content="编辑"
|
||||
placement="top">
|
||||
<el-button
|
||||
type="text"
|
||||
style="margin: 5px 0; padding: 0"
|
||||
@@ -147,7 +169,9 @@
|
||||
</el-tooltip>
|
||||
<!-- line -->
|
||||
<span style="margin: 0 4px; font-size: 18px; color: #e5e7eb">|</span>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-tooltip
|
||||
content="删除"
|
||||
placement="top">
|
||||
<el-button
|
||||
type="text"
|
||||
style="margin: 5px 0; padding: 0"
|
||||
@@ -254,7 +278,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import './iconfont/iconfont.css';
|
||||
@import '../../../styles/iconfont/iconfont.css';
|
||||
.delete-color {
|
||||
color: #ff5454;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
|
||||
<div style="margin-top: 12px; position: relative">
|
||||
<div style="position: absolute; top: -40px; right: 0">
|
||||
<el-button @click="handleAddAttr" type="text">
|
||||
<el-button
|
||||
@click="handleAddAttr"
|
||||
type="text">
|
||||
<i class="el-icon-plus"></i>
|
||||
添加项目
|
||||
</el-button>
|
||||
@@ -61,8 +63,16 @@
|
||||
</div>
|
||||
|
||||
<div class="drawer-body__footer">
|
||||
<el-button style="" @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleConfirm">保存</el-button>
|
||||
<el-button
|
||||
style=""
|
||||
@click="handleCancel">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleConfirm">
|
||||
保存
|
||||
</el-button>
|
||||
<!-- sections的第二项必须是 属性列表 -->
|
||||
<!-- <el-button
|
||||
v-if="sections[1].allowAdd"
|
||||
@@ -165,12 +175,6 @@ export default {
|
||||
label: '设备名称',
|
||||
prop: 'equipmentId',
|
||||
url: '/base/core-equipment/page?pageNo=1&pageSize=100&special=true',
|
||||
// method: 'post',
|
||||
// queryParams: {
|
||||
// pageNo: 1,
|
||||
// pageSize: 100,
|
||||
// special: true,
|
||||
// },
|
||||
rules: [
|
||||
{ required: true, message: '设备不能为空', trigger: 'blur' },
|
||||
],
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
/* Logo 字体 */
|
||||
@font-face {
|
||||
font-family: "iconfont logo";
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "iconfont logo";
|
||||
font-size: 160px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.nav-tabs {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-more {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#tabs {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#tabs li {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: -1px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
|
||||
#tabs .active {
|
||||
border-bottom-color: #f00;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.tab-container .content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 页面布局 */
|
||||
.main {
|
||||
padding: 30px 100px;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.main .logo {
|
||||
color: #333;
|
||||
text-align: left;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1;
|
||||
height: 110px;
|
||||
margin-top: -50px;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.main .logo a {
|
||||
font-size: 160px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.helps {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.helps pre {
|
||||
padding: 20px;
|
||||
margin: 10px 0;
|
||||
border: solid 1px #e7e1cd;
|
||||
background-color: #fffdef;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.icon_lists {
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.icon_lists li {
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 20px;
|
||||
text-align: center;
|
||||
list-style: none !important;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.icon_lists li .code-name {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.icon_lists .icon {
|
||||
display: block;
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
font-size: 42px;
|
||||
margin: 10px auto;
|
||||
color: #333;
|
||||
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||
transition: font-size 0.25s linear, width 0.25s linear;
|
||||
}
|
||||
|
||||
.icon_lists .icon:hover {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.icon_lists .svg-icon {
|
||||
/* 通过设置 font-size 来改变图标大小 */
|
||||
width: 1em;
|
||||
/* 图标和文字相邻时,垂直对齐 */
|
||||
vertical-align: -0.15em;
|
||||
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||
fill: currentColor;
|
||||
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||
normalize.css 中也包含这行 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon_lists li .name,
|
||||
.icon_lists li .code-name {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* markdown 样式 */
|
||||
.markdown {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.markdown img {
|
||||
vertical-align: middle;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
color: #404040;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown h2,
|
||||
.markdown h3,
|
||||
.markdown h4,
|
||||
.markdown h5,
|
||||
.markdown h6 {
|
||||
color: #404040;
|
||||
margin: 1.6em 0 0.6em 0;
|
||||
font-weight: 500;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.markdown h5 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown h6 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #e9e9e9;
|
||||
margin: 16px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown p {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown>p,
|
||||
.markdown>blockquote,
|
||||
.markdown>.highlight,
|
||||
.markdown>ol,
|
||||
.markdown>ul {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.markdown ul>li {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
.markdown>ul li,
|
||||
.markdown blockquote ul>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown>ul li p,
|
||||
.markdown>ol li p {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown ol>li {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
.markdown>ol li,
|
||||
.markdown blockquote ol>li {
|
||||
margin-left: 20px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.markdown code {
|
||||
margin: 0 3px;
|
||||
padding: 0 5px;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown strong,
|
||||
.markdown b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
empty-cells: show;
|
||||
border: 1px solid #e9e9e9;
|
||||
width: 95%;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
white-space: nowrap;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown>table th,
|
||||
.markdown>table td {
|
||||
border: 1px solid #e9e9e9;
|
||||
padding: 8px 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown>table th {
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
.markdown blockquote {
|
||||
font-size: 90%;
|
||||
color: #999;
|
||||
border-left: 4px solid #e9e9e9;
|
||||
padding-left: 0.8em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.markdown blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown .anchor {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.markdown .waiting {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.markdown h1:hover .anchor,
|
||||
.markdown h2:hover .anchor,
|
||||
.markdown h3:hover .anchor,
|
||||
.markdown h4:hover .anchor,
|
||||
.markdown h5:hover .anchor,
|
||||
.markdown h6:hover .anchor {
|
||||
opacity: 1;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown>br,
|
||||
.markdown>p>br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
background: white;
|
||||
padding: 0.5em;
|
||||
color: #333333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-meta {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-strong,
|
||||
.hljs-emphasis,
|
||||
.hljs-quote {
|
||||
color: #df5000;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-type {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.hljs-literal,
|
||||
.hljs-symbol,
|
||||
.hljs-bullet,
|
||||
.hljs-attribute {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-section,
|
||||
.hljs-name {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.hljs-tag {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-attr,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 代码高亮 */
|
||||
/* PrismJS 1.15.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre)>code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre)>code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #9a6e3a;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.class-name {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3821755 */
|
||||
src: url('iconfont.eot?t=1689233106339'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1689233106339#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARgAAsAAAAACcAAAAQUAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACDKAqGSIUsATYCJAMYCw4ABCAFhGcHVBtUCMiuMG7hiaIkox1FaBhxvd1fpwAN4YKo1v7tWTr8hBRkBQgO7yqKUJKPUKzDjkixjn7/q0vlANCkEHCJtsMvx2eQn04h5rHEE8593TK2y1SC5nbvNG5gqgZBNEWTqFUQLGVFNnVu1TjyMm3SafEsC3y0myW12KdEh2x+deP/zzHTJeG3AVBm4lrnAxpQN0US7s3ijuSE6Jbh1UGv08cgQEivMg5z6m49Qj77TVxDEZww6gXicNkviSbkxgswNeGCj+CgMw1yFRpAnUNegSv+8+UfU/igsBpjnRV3rRV9+Su8Fk1Agv6CW4eAeyvAAhronJlI1tcrVnIMHZ0cCcsUTrRTnQ0CP50B4KfgEub9Lw80BougQBwGI8bYJU4LPwUbBw0/HXAw8NORUM90wsT9JeIMFACux9QckHyQ9FDYTobcGi+FLSjwMxDe3L5s+w9THFYeEs8H303FWMnZ1JuBWFgNPh3bd5wOvJmKI9aTqXeD8eJ66HnfnV1dJPE8cy4EgqT+s/SbdSWbp9Pn24NbZ1MnGw7CDbvT6+lL1CXVh++hcH56umDT9vOviL/grQ6srHjE57uLHdQn+dtO9x2v94WN6+eXm0HWlZOzta3tUDp1JWjymsiD8r0ViWGkC+n4GeH5aODSM+9COnilpdfdZsRIvMerLmS0uICTplrOnb99LT3NkJNeajPfpDznblq6bXH8efBjlPIUxhQcX+U0qEdt4bjxy6rMdOkbEn0/3mlvrXZL60ysxdwcn/qKLJ/82pnzGS61z5rBeGmrxf33ZXN/IBWUvb8KSvnttbwwq+YTkweZHue0M0+c0ssZGY/Rs+aVF8+3GaW07CkvLC/KcBvP8c2uGpsdm0THlazwlPE22Kdi9ZK4Hdsmtw9eHVQwPjG0p33Q7tGMJ6TUJ2VK1MMw6ftI6qPPtruCvEPmLZqiHcj1Aw3Rup/sdzj+lt/w3f5TrAHgx++nD7A+8xaD4CL8m60Q+KWYO7CgUY3gTFl+OwUBHKteh00BoWmGDIYm301frAJwKAg+BTEoPCpA41OPNNh2sET0g8NnCkI61M6PKKBzREwANBtGIOS6BEU2D0CT6xvSYP+Apdg/cOT6DyErI68W0RzbqhmYOFixuRNLFqoRi839Zh+A2KqYWJH1CTC7hM04My0j664HDVgXY+xtYhbnBBNGVVzH7geKQrHOqA0sPK2Fc70oPZ2UPSTNQlVUjQEmHLDCzDphEgtKQ9zCPP16DwBRK4UJAyKfyBg7jaeaxzKlyQAg6xkaKO9M2tu1EWXhOEL3IxhKhdWpMqCYDgrTy7vZAAsuTUsLm65IOlWIQBlp47PUS9wAhBgHOFGixYgVJx7+dtqutZuY1eXTvXYncJOkOF1Wicd+CnBACA==') format('woff2'),
|
||||
url('iconfont.woff?t=1689233106339') format('woff'),
|
||||
url('iconfont.ttf?t=1689233106339') format('truetype'),
|
||||
url('iconfont.svg?t=1689233106339#iconfont') format('svg');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-downward:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-upward:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-detail:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-edit:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-delete:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"id": "3821755",
|
||||
"name": "component",
|
||||
"font_family": "iconfont",
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "封装的组件中的icon",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "36426261",
|
||||
"name": "downward",
|
||||
"font_class": "downward",
|
||||
"unicode": "e604",
|
||||
"unicode_decimal": 58884
|
||||
},
|
||||
{
|
||||
"icon_id": "36426301",
|
||||
"name": "upward",
|
||||
"font_class": "upward",
|
||||
"unicode": "e605",
|
||||
"unicode_decimal": 58885
|
||||
},
|
||||
{
|
||||
"icon_id": "33347867",
|
||||
"name": "detail",
|
||||
"font_class": "detail",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "33347918",
|
||||
"name": "edit",
|
||||
"font_class": "edit",
|
||||
"unicode": "e602",
|
||||
"unicode_decimal": 58882
|
||||
},
|
||||
{
|
||||
"icon_id": "33347930",
|
||||
"name": "delete",
|
||||
"font_class": "delete",
|
||||
"unicode": "e603",
|
||||
"unicode_decimal": 58883
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Created by iconfont</metadata>
|
||||
<defs>
|
||||
<font id="iconfont" horiz-adv-x="1024">
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="400"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="downward" unicode="" d="M556.942222 144.099556l363.064889 401.806222c24.860444 21.617778 24.860444 56.263111 0 77.880889a68.437333 68.437333 0 0 1-44.942222 16.156444c-16.896 0-33.052444-5.859556-44.885333-16.156444L512 260.949333l-318.236444 362.951111a68.437333 68.437333 0 0 1-44.942223 16.099556c-16.896 0-33.109333-5.802667-44.942222-16.156444-24.746667-21.617778-24.746667-56.206222 0-77.824l363.121778-401.749334c5.973333-5.290667 13.141333-9.443556 21.048889-12.231111 23.722667-8.305778 51.029333-3.527111 68.892444 12.060445z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="upward" unicode="" d="M556.942222 623.900444l363.064889-401.806222c24.860444-21.617778 24.860444-56.263111 0-77.880889a68.437333 68.437333 0 0 0-44.942222-16.156444c-16.896 0-33.052444 5.859556-44.885333 16.156444L512 507.050667l-318.236444-362.951111a68.437333 68.437333 0 0 0-44.942223-16.099556c-16.896 0-33.109333 5.802667-44.942222 16.156444-24.746667 21.617778-24.746667 56.206222 0 77.824L467.057778 623.729778c5.973333 5.290667 13.141333 9.443556 21.048889 12.231111 23.722667 8.305778 51.029333 3.527111 68.892444-12.060445z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="detail" unicode="" d="M902.428444 705.251556H332.401778a7.964444 7.964444 0 0 1-7.793778-8.021334v-56.206222a7.964444 7.964444 0 0 1 7.793778-8.078222h570.026666A7.964444 7.964444 0 0 1 910.222222 641.024v56.206222a7.964444 7.964444 0 0 1-7.793778 8.021334z m0-285.127112H332.401778a7.964444 7.964444 0 0 1-7.793778-7.964444v-56.32a7.964444 7.964444 0 0 1 7.793778-7.964444h570.026666a7.964444 7.964444 0 0 1 7.793778 7.964444v56.32a7.964444 7.964444 0 0 1-7.793778 7.964444z m0-285.070222H332.401778a7.964444 7.964444 0 0 1-7.793778-8.078222v-56.206222a7.964444 7.964444 0 0 1 7.793778-8.021334h570.026666a7.964444 7.964444 0 0 1 7.793778 8.021334v56.206222a7.964444 7.964444 0 0 1-7.793778 8.078222zM113.777778 669.127111c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0 56.547556 56.547556 0 0 1 27.306666 48.696889 56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0A56.547556 56.547556 0 0 1 113.777778 669.127111zM113.777778 384c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0A56.547556 56.547556 0 0 1 223.061333 384a56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0A56.547556 56.547556 0 0 1 113.777778 384z m0-285.127111c0-20.081778 10.410667-38.684444 27.306666-48.696889a53.361778 53.361778 0 0 1 54.670223 0 56.547556 56.547556 0 0 1 27.306666 48.696889 56.547556 56.547556 0 0 1-27.306666 48.696889 53.361778 53.361778 0 0 1-54.613334 0 56.547556 56.547556 0 0 1-27.363555-48.696889z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="edit" unicode="" d="M873.016889 395.264a32.824889 32.824889 0 0 0 65.649778 0v-273.806222a164.124444 164.124444 0 0 0-164.124445-164.124445h-525.084444A164.124444 164.124444 0 0 0 85.333333 121.457778v525.084444A164.124444 164.124444 0 0 0 249.457778 810.666667h312.32a32.824889 32.824889 0 1 0 0-65.649778h-312.32a98.417778 98.417778 0 0 1-98.474667-98.417778v-525.141333c0-54.385778 44.088889-98.474667 98.417778-98.474667h525.141333a98.417778 98.417778 0 0 1 98.474667 98.417778V395.320889z m-14.222222 362.097778a32.824889 32.824889 0 0 0 48.014222-44.771556L548.750222 328.533333a32.824889 32.824889 0 1 0-48.014222 44.771556l358.115556 384.056889z" horiz-adv-x="1024" />
|
||||
|
||||
<glyph glyph-name="delete" unicode="" d="M601.024 146.24a29.632 29.632 0 0 0-29.696 29.696V503.04a29.632 29.632 0 1 0 59.456 0v-326.848a29.76 29.76 0 0 0-29.76-29.888z m-178.24 0a29.632 29.632 0 0 0-29.696 29.696V503.04a29.632 29.632 0 1 0 59.392 0v-326.848a29.76 29.76 0 0 0-29.696-29.888z m475.52 505.216h-148.544v59.456c0 49.152-39.616 89.088-88.512 89.088H363.392c-49.216 0-89.152-39.936-89.152-89.088v-59.456H125.696a29.632 29.632 0 1 1 0-59.392h772.608a29.632 29.632 0 1 1 0 59.392z m-564.608 59.456c0 16.256 13.44 29.696 29.696 29.696h297.856c16.32 0 29.056-13.12 29.056-29.696v-59.456H333.696v59.456zM720-32h-416a89.152 89.152 0 0 0-89.088 89.088V503.232a29.632 29.632 0 1 0 59.456 0v-446.08c0-16.512 13.44-29.76 29.696-29.76h416.064a29.632 29.632 0 0 1 29.696 29.696V502.144a29.632 29.632 0 1 0 59.456 0v-445.056A89.536 89.536 0 0 0 720-32z" horiz-adv-x="1024" />
|
||||
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |