Merge branch 'projects/mesxc-test' into projects/mesxc-zhp
@@ -1,9 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getActivityList(query) {
|
||||
return request({
|
||||
url: '/bpm/activity/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getProcessDefinitionPage(query) {
|
||||
return request({
|
||||
url: '/bpm/process-definition/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getProcessDefinitionList(query) {
|
||||
return request({
|
||||
url: '/bpm/process-definition/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getProcessDefinitionBpmnXML(id) {
|
||||
return request({
|
||||
url: '/bpm/process-definition/get-bpmn-xml?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建工作流的表单定义
|
||||
export function createForm(data) {
|
||||
return request({
|
||||
url: '/bpm/form/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新工作流的表单定义
|
||||
export function updateForm(data) {
|
||||
return request({
|
||||
url: '/bpm/form/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除工作流的表单定义
|
||||
export function deleteForm(id) {
|
||||
return request({
|
||||
url: '/bpm/form/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得工作流的表单定义
|
||||
export function getForm(id) {
|
||||
return request({
|
||||
url: '/bpm/form/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得工作流的表单定义分页
|
||||
export function getFormPage(query) {
|
||||
return request({
|
||||
url: '/bpm/form/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得动态表单的精简列表
|
||||
export function getSimpleForms() {
|
||||
return request({
|
||||
url: '/bpm/form/list-all-simple',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建请假申请
|
||||
export function createLeave(data) {
|
||||
return request({
|
||||
url: '/bpm/oa/leave/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获得请假申请
|
||||
export function getLeave(id) {
|
||||
return request({
|
||||
url: '/bpm/oa/leave/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得请假申请分页
|
||||
export function getLeavePage(query) {
|
||||
return request({
|
||||
url: '/bpm/oa/leave/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getModelPage(query) {
|
||||
return request({
|
||||
url: '/bpm/model/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getModel(id) {
|
||||
return request({
|
||||
url: '/bpm/model/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function updateModel(data) {
|
||||
return request({
|
||||
url: '/bpm/model/update',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 任务状态修改
|
||||
export function updateModelState(id, state) {
|
||||
return request({
|
||||
url: '/bpm/model/update-state',
|
||||
method: 'put',
|
||||
data: {
|
||||
id,
|
||||
state
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function createModel(data) {
|
||||
return request({
|
||||
url: '/bpm/model/create',
|
||||
method: 'POST',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteModel(id) {
|
||||
return request({
|
||||
url: '/bpm/model/delete?id=' + id,
|
||||
method: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
export function deployModel(id) {
|
||||
return request({
|
||||
url: '/bpm/model/deploy?id=' + id,
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getMyProcessInstancePage(query) {
|
||||
return request({
|
||||
url: '/bpm/process-instance/my-page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createProcessInstance(data) {
|
||||
return request({
|
||||
url: '/bpm/process-instance/create',
|
||||
method: 'POST',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function cancelProcessInstance(id, reason) {
|
||||
return request({
|
||||
url: '/bpm/process-instance/cancel',
|
||||
method: 'DELETE',
|
||||
data: {
|
||||
id,
|
||||
reason
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getProcessInstance(id) {
|
||||
return request({
|
||||
url: '/bpm/process-instance/get?id=' + id,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getTodoTaskPage(query) {
|
||||
return request({
|
||||
url: '/bpm/task/todo-page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getDoneTaskPage(query) {
|
||||
return request({
|
||||
url: '/bpm/task/done-page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function completeTask(data) {
|
||||
return request({
|
||||
url: '/bpm/task/complete',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function approveTask(data) {
|
||||
return request({
|
||||
url: '/bpm/task/approve',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function rejectTask(data) {
|
||||
return request({
|
||||
url: '/bpm/task/reject',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function backTask(data) {
|
||||
return request({
|
||||
url: '/bpm/task/back',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateTaskAssignee(data) {
|
||||
return request({
|
||||
url: '/bpm/task/update-assignee',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getTaskListByProcessInstanceId(processInstanceId) {
|
||||
return request({
|
||||
url: '/bpm/task/list-by-process-instance-id?processInstanceId=' + processInstanceId,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getTaskAssignRuleList(query) {
|
||||
return request({
|
||||
url: '/bpm/task-assign-rule/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createTaskAssignRule(data) {
|
||||
return request({
|
||||
url: '/bpm/task-assign-rule/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateTaskAssignRule(data) {
|
||||
return request({
|
||||
url: '/bpm/task-assign-rule/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建用户组
|
||||
export function createUserGroup(data) {
|
||||
return request({
|
||||
url: '/bpm/user-group/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新用户组
|
||||
export function updateUserGroup(data) {
|
||||
return request({
|
||||
url: '/bpm/user-group/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除用户组
|
||||
export function deleteUserGroup(id) {
|
||||
return request({
|
||||
url: '/bpm/user-group/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得用户组
|
||||
export function getUserGroup(id) {
|
||||
return request({
|
||||
url: '/bpm/user-group/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得用户组分页
|
||||
export function getUserGroupPage(query) {
|
||||
return request({
|
||||
url: '/bpm/user-group/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户组精简信息列表
|
||||
export function listSimpleUserGroups() {
|
||||
return request({
|
||||
url: '/bpm/user-group/list-all-simple',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得API 访问日志分页
|
||||
export function getApiAccessLogPage(query) {
|
||||
return request({
|
||||
url: '/infra/api-access-log/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出API 访问日志 Excel
|
||||
export function exportApiAccessLogExcel(query) {
|
||||
return request({
|
||||
url: '/infra/api-access-log/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 更新 API 错误日志的处理状态
|
||||
export function updateApiErrorLogProcess(id, processStatus) {
|
||||
return request({
|
||||
url: '/infra/api-error-log/update-status?id=' + id + '&processStatus=' + processStatus,
|
||||
method: 'put',
|
||||
})
|
||||
}
|
||||
|
||||
// 获得API 错误日志分页
|
||||
export function getApiErrorLogPage(query) {
|
||||
return request({
|
||||
url: '/infra/api-error-log/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出API 错误日志 Excel
|
||||
export function exportApiErrorLogExcel(query) {
|
||||
return request({
|
||||
url: '/infra/api-error-log/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得表定义分页
|
||||
export function getCodegenTablePage(query) {
|
||||
return request({
|
||||
url: '/infra/codegen/table/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得表和字段的明细
|
||||
export function getCodegenDetail(tableId) {
|
||||
return request({
|
||||
url: '/infra/codegen/detail?tableId=' + tableId,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 修改代码生成信息
|
||||
export function updateCodegen(data) {
|
||||
return request({
|
||||
url: '/infra/codegen/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 基于数据库的表结构,同步数据库的表和字段定义
|
||||
export function syncCodegenFromDB(tableId) {
|
||||
return request({
|
||||
url: '/infra/codegen/sync-from-db?tableId=' + tableId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 基于 SQL 建表语句,同步数据库的表和字段定义
|
||||
export function syncCodegenFromSQL(tableId, sql) {
|
||||
return request({
|
||||
url: '/infra/codegen/sync-from-sql?tableId=' + tableId,
|
||||
method: 'put',
|
||||
headers:{
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: 'tableId=' + tableId + "&sql=" + sql,
|
||||
})
|
||||
}
|
||||
|
||||
// 预览生成代码
|
||||
export function previewCodegen(tableId) {
|
||||
return request({
|
||||
url: '/infra/codegen/preview?tableId=' + tableId,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 下载生成代码
|
||||
export function downloadCodegen(tableId) {
|
||||
return request({
|
||||
url: '/infra/codegen/download?tableId=' + tableId,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得表定义分页
|
||||
export function getSchemaTableList(query) {
|
||||
return request({
|
||||
url: '/infra/codegen/db/table/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 基于数据库的表结构,创建代码生成器的表定义
|
||||
export function createCodegenList(data) {
|
||||
return request({
|
||||
url: '/infra/codegen/create-list',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除数据库的表和字段定义
|
||||
export function deleteCodegen(tableId) {
|
||||
return request({
|
||||
url: '/infra/codegen/delete?tableId=' + tableId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询参数列表
|
||||
export function listConfig(query) {
|
||||
return request({
|
||||
url: '/infra/config/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询参数详细
|
||||
export function getConfig(configId) {
|
||||
return request({
|
||||
url: '/infra/config/get?id=' + configId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 根据参数键名查询参数值
|
||||
export function getConfigKey(configKey) {
|
||||
return request({
|
||||
url: '/infra/config/get-value-by-key?key=' + configKey,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增参数配置
|
||||
export function addConfig(data) {
|
||||
return request({
|
||||
url: '/infra/config/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改参数配置
|
||||
export function updateConfig(data) {
|
||||
return request({
|
||||
url: '/infra/config/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除参数配置
|
||||
export function delConfig(configId) {
|
||||
return request({
|
||||
url: '/infra/config/delete?id=' + configId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出参数
|
||||
export function exportConfig(query) {
|
||||
return request({
|
||||
url: '/infra/config/export',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建数据源配置
|
||||
export function createDataSourceConfig(data) {
|
||||
return request({
|
||||
url: '/infra/data-source-config/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新数据源配置
|
||||
export function updateDataSourceConfig(data) {
|
||||
return request({
|
||||
url: '/infra/data-source-config/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除数据源配置
|
||||
export function deleteDataSourceConfig(id) {
|
||||
return request({
|
||||
url: '/infra/data-source-config/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得数据源配置
|
||||
export function getDataSourceConfig(id) {
|
||||
return request({
|
||||
url: '/infra/data-source-config/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得数据源配置列表
|
||||
export function getDataSourceConfigList() {
|
||||
return request({
|
||||
url: '/infra/data-source-config/list',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// 导出参数
|
||||
import request from "@/utils/request";
|
||||
|
||||
export function exportHtml() {
|
||||
return request({
|
||||
url: '/infra/db-doc/export-html',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function exportWord() {
|
||||
return request({
|
||||
url: '/infra/db-doc/export-word',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function exportMarkdown() {
|
||||
return request({
|
||||
url: '/infra/db-doc/export-markdown',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 删除文件
|
||||
export function deleteFile(id) {
|
||||
return request({
|
||||
url: '/infra/file/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得文件分页
|
||||
export function getFilePage(query) {
|
||||
return request({
|
||||
url: '/infra/file/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建文件配置
|
||||
export function createFileConfig(data) {
|
||||
return request({
|
||||
url: '/infra/file-config/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新文件配置
|
||||
export function updateFileConfig(data) {
|
||||
return request({
|
||||
url: '/infra/file-config/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新文件配置为主配置
|
||||
export function updateFileConfigMaster(id) {
|
||||
return request({
|
||||
url: '/infra/file-config/update-master?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除文件配置
|
||||
export function deleteFileConfig(id) {
|
||||
return request({
|
||||
url: '/infra/file-config/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得文件配置
|
||||
export function getFileConfig(id) {
|
||||
return request({
|
||||
url: '/infra/file-config/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得文件配置分页
|
||||
export function getFileConfigPage(query) {
|
||||
return request({
|
||||
url: '/infra/file-config/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function testFileConfig(id) {
|
||||
return request({
|
||||
url: '/infra/file-config/test?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询定时任务调度列表
|
||||
export function listJob(query) {
|
||||
return request({
|
||||
url: '/infra/job/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询定时任务调度详细
|
||||
export function getJob(jobId) {
|
||||
return request({
|
||||
url: '/infra/job/get?id=' + jobId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增定时任务调度
|
||||
export function addJob(data) {
|
||||
return request({
|
||||
url: '/infra/job/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改定时任务调度
|
||||
export function updateJob(data) {
|
||||
return request({
|
||||
url: '/infra/job/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除定时任务调度
|
||||
export function delJob(jobId) {
|
||||
return request({
|
||||
url: '/infra/job/delete?id=' + jobId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出定时任务调度
|
||||
export function exportJob(query) {
|
||||
return request({
|
||||
url: '/infra/job/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 任务状态修改
|
||||
export function updateJobStatus(jobId, status) {
|
||||
return request({
|
||||
url: '/infra/job/update-status',
|
||||
method: 'put',
|
||||
headers:{
|
||||
'Content-type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
data: 'id=' + jobId + "&status=" + status,
|
||||
})
|
||||
}
|
||||
|
||||
// 定时任务立即执行一次
|
||||
export function runJob(jobId) {
|
||||
return request({
|
||||
url: '/infra/job/trigger?id=' + jobId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得定时任务的下 n 次执行时间
|
||||
export function getJobNextTimes(jobId) {
|
||||
return request({
|
||||
url: '/infra/job/get_next_times?id=' + jobId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得定时任务
|
||||
export function getJobLog(id) {
|
||||
return request({
|
||||
url: '/infra/job-log/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得定时任务分页
|
||||
export function getJobLogPage(query) {
|
||||
return request({
|
||||
url: '/infra/job-log/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出定时任务 Excel
|
||||
export function exportJobLogExcel(query) {
|
||||
return request({
|
||||
url: '/infra/job-log/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询缓存详细
|
||||
export function getCache() {
|
||||
return request({
|
||||
url: '/infra/redis/get-monitor-info',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建字典类型
|
||||
export function createTestDemo(data) {
|
||||
return request({
|
||||
url: '/infra/test-demo/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新字典类型
|
||||
export function updateTestDemo(data) {
|
||||
return request({
|
||||
url: '/infra/test-demo/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除字典类型
|
||||
export function deleteTestDemo(id) {
|
||||
return request({
|
||||
url: '/infra/test-demo/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得字典类型
|
||||
export function getTestDemo(id) {
|
||||
return request({
|
||||
url: '/infra/test-demo/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得字典类型分页
|
||||
export function getTestDemoPage(query) {
|
||||
return request({
|
||||
url: '/infra/test-demo/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出字典类型 Excel
|
||||
export function exportTestDemoExcel(query) {
|
||||
return request({
|
||||
url: '/infra/test-demo/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建Banner
|
||||
export function createBanner(data) {
|
||||
return request({
|
||||
url: '/market/banner/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新Banner
|
||||
export function updateBanner(data) {
|
||||
return request({
|
||||
url: '/market/banner/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除Banner
|
||||
export function deleteBanner(id) {
|
||||
return request({
|
||||
url: '/market/banner/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得Banner
|
||||
export function getBanner(id) {
|
||||
return request({
|
||||
url: '/market/banner/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得Banner分页
|
||||
export function getBannerPage(query) {
|
||||
return request({
|
||||
url: '/market/banner/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出Banner Excel
|
||||
export function exportBannerExcel(query) {
|
||||
return request({
|
||||
url: '/market/banner/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建品牌
|
||||
export function createBrand(data) {
|
||||
return request({
|
||||
url: '/product/brand/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新品牌
|
||||
export function updateBrand(data) {
|
||||
return request({
|
||||
url: '/product/brand/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除品牌
|
||||
export function deleteBrand(id) {
|
||||
return request({
|
||||
url: '/product/brand/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得品牌
|
||||
export function getBrand(id) {
|
||||
return request({
|
||||
url: '/product/brand/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得品牌list
|
||||
export function getBrandList() {
|
||||
return request({
|
||||
url: '/product/brand/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 获得品牌分页
|
||||
export function getBrandPage(query) {
|
||||
return request({
|
||||
url: '/product/brand/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出品牌 Excel
|
||||
export function exportBrandExcel(query) {
|
||||
return request({
|
||||
url: '/product/brand/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建商品分类
|
||||
export function createProductCategory(data) {
|
||||
return request({
|
||||
url: '/product/category/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新商品分类
|
||||
export function updateProductCategory(data) {
|
||||
return request({
|
||||
url: '/product/category/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除商品分类
|
||||
export function deleteProductCategory(id) {
|
||||
return request({
|
||||
url: '/product/category/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品分类
|
||||
export function getProductCategory(id) {
|
||||
return request({
|
||||
url: '/product/category/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品分类列表
|
||||
export function getProductCategoryList(query) {
|
||||
return request({
|
||||
url: '/product/category/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// ------------------------ 属性项 -------------------
|
||||
|
||||
// 创建属性项
|
||||
export function createProperty(data) {
|
||||
return request({
|
||||
url: '/product/property/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新属性项
|
||||
export function updateProperty(data) {
|
||||
return request({
|
||||
url: '/product/property/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除属性项
|
||||
export function deleteProperty(id) {
|
||||
return request({
|
||||
url: '/product/property/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得属性项
|
||||
export function getProperty(id) {
|
||||
return request({
|
||||
url: '/product/property/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得属性项分页
|
||||
export function getPropertyPage(query) {
|
||||
return request({
|
||||
url: '/product/property/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得属性项列表
|
||||
export function getPropertyList(query) {
|
||||
return request({
|
||||
url: '/product/property/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得属性项列表
|
||||
export function getPropertyListAndValue(query) {
|
||||
return request({
|
||||
url: '/product/property/get-value-list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// ------------------------ 属性值 -------------------
|
||||
|
||||
// 获得属性值分页
|
||||
export function getPropertyValuePage(query) {
|
||||
return request({
|
||||
url: '/product/property/value/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得属性值
|
||||
export function getPropertyValue(id) {
|
||||
return request({
|
||||
url: '/product/property/value/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 创建属性值
|
||||
export function createPropertyValue(data) {
|
||||
return request({
|
||||
url: '/product/property/value/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新属性值
|
||||
export function updatePropertyValue(data) {
|
||||
return request({
|
||||
url: '/product/property/value/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除属性值
|
||||
export function deletePropertyValue(id) {
|
||||
return request({
|
||||
url: '/product/property/value/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export class exportPropertyExcel {
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得商品 SKU 选项的列表
|
||||
export function getSkuOptionList() {
|
||||
return request({
|
||||
url: '/product/sku/get-option-list',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建商品 SPU
|
||||
export function createSpu(data) {
|
||||
return request({
|
||||
url: '/product/spu/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新商品 SPU
|
||||
export function updateSpu(data) {
|
||||
return request({
|
||||
url: '/product/spu/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除商品 SPU
|
||||
export function deleteSpu(id) {
|
||||
return request({
|
||||
url: '/product/spu/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品 SPU 详情
|
||||
export function getSpuDetail(id) {
|
||||
return request({
|
||||
url: '/product/spu/get-detail?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品 SPU 分页
|
||||
export function getSpuPage(query) {
|
||||
return request({
|
||||
url: '/product/spu/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得商品 SPU 精简列表
|
||||
export function getSpuSimpleList() {
|
||||
return request({
|
||||
url: '/product/spu/get-simple-list',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 删除优惠劵
|
||||
export function deleteCoupon(id) {
|
||||
return request({
|
||||
url: '/promotion/coupon/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得优惠劵分页
|
||||
export function getCouponPage(query) {
|
||||
return request({
|
||||
url: '/promotion/coupon/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建优惠劵模板
|
||||
export function createCouponTemplate(data) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新优惠劵模板
|
||||
export function updateCouponTemplate(data) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新优惠劵模板的状态
|
||||
export function updateCouponTemplateStatus(id, status) {
|
||||
const data = {
|
||||
id,
|
||||
status
|
||||
}
|
||||
return request({
|
||||
url: '/promotion/coupon-template/update-status',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除优惠劵模板
|
||||
export function deleteCouponTemplate(id) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得优惠劵模板
|
||||
export function getCouponTemplate(id) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得优惠劵模板分页
|
||||
export function getCouponTemplatePage(query) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出优惠劵模板 Excel
|
||||
export function exportCouponTemplateExcel(query) {
|
||||
return request({
|
||||
url: '/promotion/coupon-template/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建限时折扣活动
|
||||
export function createDiscountActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新限时折扣活动
|
||||
export function updateDiscountActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭限时折扣活动
|
||||
export function closeDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/close?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除限时折扣活动
|
||||
export function deleteDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得限时折扣活动
|
||||
export function getDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得限时折扣活动分页
|
||||
export function getDiscountActivityPage(query) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建满减送活动
|
||||
export function createRewardActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新满减送活动
|
||||
export function updateRewardActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭满减送活动
|
||||
export function closeRewardActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/close?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除满减送活动
|
||||
export function deleteRewardActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得满减送活动
|
||||
export function getRewardActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得满减送活动分页
|
||||
export function getRewardActivityPage(query) {
|
||||
return request({
|
||||
url: '/promotion/reward-activity/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建秒杀活动
|
||||
export function createSeckillActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新秒杀活动
|
||||
export function updateSeckillActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭限时折扣活动
|
||||
export function closeSeckillActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/close?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除秒杀活动
|
||||
export function deleteSeckillActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得秒杀活动
|
||||
export function getSeckillActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得秒杀活动分页
|
||||
export function getSeckillActivityPage(query) {
|
||||
return request({
|
||||
url: '/promotion/seckill-activity/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建秒杀时段
|
||||
export function createSeckillTime(data) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新秒杀时段
|
||||
export function updateSeckillTime(data) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除秒杀时段
|
||||
export function deleteSeckillTime(id) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得秒杀时段
|
||||
export function getSeckillTime(id) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得秒杀时段分页
|
||||
export function getSeckillTimePage(query) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有的秒杀时段
|
||||
export function getSeckillTimeList() {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出秒杀时段 Excel
|
||||
export function exportSeckillTimeExcel(query) {
|
||||
return request({
|
||||
url: '/promotion/seckill-time/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得交易售后
|
||||
export function getAfterSale(id) {
|
||||
return request({
|
||||
url: '/trade/after-sale/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得交易售后分页
|
||||
export function getAfterSalePage(query) {
|
||||
return request({
|
||||
url: '/trade/after-sale/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得交易订单分页
|
||||
export function getOrderPage(query) {
|
||||
return request({
|
||||
url: '/trade/order/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得交易订单详情
|
||||
export function getOrderDetail(id) {
|
||||
return request({
|
||||
url: '/trade/order/get-detail?id=' + id,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建公众号账号
|
||||
export function createAccount(data) {
|
||||
return request({
|
||||
url: '/mp/account/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新公众号账号
|
||||
export function updateAccount(data) {
|
||||
return request({
|
||||
url: '/mp/account/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号账号
|
||||
export function deleteAccount(id) {
|
||||
return request({
|
||||
url: '/mp/account/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号账号
|
||||
export function getAccount(id) {
|
||||
return request({
|
||||
url: '/mp/account/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号账号分页
|
||||
export function getAccountPage(query) {
|
||||
return request({
|
||||
url: '/mp/account/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取公众号账号精简信息列表
|
||||
export function getSimpleAccounts() {
|
||||
return request({
|
||||
url: '/mp/account/list-all-simple',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 生成公众号二维码
|
||||
export function generateAccountQrCode(id) {
|
||||
return request({
|
||||
url: '/mp/account/generate-qr-code?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 清空公众号 API 配额
|
||||
export function clearAccountQuota(id) {
|
||||
return request({
|
||||
url: '/mp/account/clear-quota?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建公众号的自动回复
|
||||
export function createAutoReply(data) {
|
||||
return request({
|
||||
url: '/mp/auto-reply/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新公众号的自动回复
|
||||
export function updateAutoReply(data) {
|
||||
return request({
|
||||
url: '/mp/auto-reply/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号的自动回复
|
||||
export function deleteAutoReply(id) {
|
||||
return request({
|
||||
url: '/mp/auto-reply/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号的自动回复
|
||||
export function getAutoReply(id) {
|
||||
return request({
|
||||
url: '/mp/auto-reply/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号的自动回复分页
|
||||
export function getAutoReplyPage(query) {
|
||||
return request({
|
||||
url: '/mp/auto-reply/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得公众号草稿分页
|
||||
export function getDraftPage(query) {
|
||||
return request({
|
||||
url: '/mp/draft/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 创建公众号草稿
|
||||
export function createDraft(accountId, articles) {
|
||||
return request({
|
||||
url: '/mp/draft/create?accountId=' + accountId,
|
||||
method: 'post',
|
||||
data: {
|
||||
articles
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新公众号草稿
|
||||
export function updateDraft(accountId, mediaId, articles) {
|
||||
return request({
|
||||
url: '/mp/draft/update?accountId=' + accountId + '&mediaId=' + mediaId,
|
||||
method: 'put',
|
||||
data: articles
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号草稿
|
||||
export function deleteDraft(accountId, mediaId) {
|
||||
return request({
|
||||
url: '/mp/draft/delete?accountId=' + accountId + '&mediaId=' + mediaId,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得公众号素材分页
|
||||
export function getFreePublishPage(query) {
|
||||
return request({
|
||||
url: '/mp/free-publish/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号素材
|
||||
export function deleteFreePublish(accountId, articleId) {
|
||||
return request({
|
||||
url: '/mp/free-publish/delete?accountId=' + accountId + '&articleId=' + articleId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 发布公众号素材
|
||||
export function submitFreePublish(accountId, mediaId) {
|
||||
return request({
|
||||
url: '/mp/free-publish/submit?accountId=' + accountId + '&mediaId=' + mediaId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得公众号素材分页
|
||||
export function getMaterialPage(query) {
|
||||
return request({
|
||||
url: '/mp/material/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号永久素材
|
||||
export function deletePermanentMaterial(id) {
|
||||
return request({
|
||||
url: '/mp/material/delete-permanent?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得公众号菜单列表
|
||||
export function getMenuList(accountId) {
|
||||
return request({
|
||||
url: '/mp/menu/list?accountId=' + accountId,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 保存公众号菜单
|
||||
export function saveMenu(accountId, menus) {
|
||||
return request({
|
||||
url: '/mp/menu/save',
|
||||
method: 'post',
|
||||
data: {
|
||||
accountId,
|
||||
menus
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号菜单
|
||||
export function deleteMenu(accountId) {
|
||||
return request({
|
||||
url: '/mp/menu/delete?accountId=' + accountId,
|
||||
method: 'delete',
|
||||
})
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获得公众号消息分页
|
||||
export function getMessagePage(query) {
|
||||
return request({
|
||||
url: '/mp/message/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 给粉丝发送消息
|
||||
export function sendMessage(data) {
|
||||
return request({
|
||||
url: '/mp/message/send',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 更新公众号粉丝
|
||||
export function updateUser(data) {
|
||||
return request({
|
||||
url: '/mp/user/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号粉丝
|
||||
export function getUser(id) {
|
||||
return request({
|
||||
url: '/mp/user/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号粉丝分页
|
||||
export function getUserPage(query) {
|
||||
return request({
|
||||
url: '/mp/user/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 同步公众号粉丝
|
||||
export function syncUser(accountId) {
|
||||
return request({
|
||||
url: '/mp/user/sync?accountId=' + accountId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取消息发送概况数据
|
||||
export function getUpstreamMessage(query) {
|
||||
return request({
|
||||
url: '/mp/statistics/upstream-message',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 用户增减数据
|
||||
export function getUserSummary(query) {
|
||||
return request({
|
||||
url: '/mp/statistics/user-summary',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得用户累计数据
|
||||
export function getUserCumulate(query) {
|
||||
return request({
|
||||
url: '/mp/statistics/user-cumulate',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获得接口分析数据
|
||||
export function getInterfaceSummary(query) {
|
||||
return request({
|
||||
url: '/mp/statistics/interface-summary',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建公众号标签
|
||||
export function createTag(data) {
|
||||
return request({
|
||||
url: '/mp/tag/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新公众号标签
|
||||
export function updateTag(data) {
|
||||
return request({
|
||||
url: '/mp/tag/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除公众号标签
|
||||
export function deleteTag(id) {
|
||||
return request({
|
||||
url: '/mp/tag/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号标签
|
||||
export function getTag(id) {
|
||||
return request({
|
||||
url: '/mp/tag/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得公众号标签分页
|
||||
export function getTagPage(query) {
|
||||
return request({
|
||||
url: '/mp/tag/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取公众号标签精简信息列表
|
||||
export function getSimpleTags() {
|
||||
return request({
|
||||
url: '/mp/tag/list-all-simple',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 同步公众号标签
|
||||
export function syncTag(accountId) {
|
||||
return request({
|
||||
url: '/mp/tag/sync?accountId=' + accountId,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建支付应用信息
|
||||
export function createApp(data) {
|
||||
return request({
|
||||
url: '/pay/app/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新支付应用信息
|
||||
export function updateApp(data) {
|
||||
return request({
|
||||
url: '/pay/app/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 支付应用信息状态修改
|
||||
export function changeAppStatus(id, status) {
|
||||
const data = {
|
||||
id,
|
||||
status
|
||||
}
|
||||
return request({
|
||||
url: '/pay/app/update-status',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除支付应用信息
|
||||
export function deleteApp(id) {
|
||||
return request({
|
||||
url: '/pay/app/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付应用信息
|
||||
export function getApp(id) {
|
||||
return request({
|
||||
url: '/pay/app/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付应用信息分页
|
||||
export function getAppPage(query) {
|
||||
return request({
|
||||
url: '/pay/app/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出支付应用信息 Excel
|
||||
export function exportAppExcel(query) {
|
||||
return request({
|
||||
url: '/pay/app/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 根据商ID称搜索应用列表
|
||||
export function getAppListByMerchantId(merchantId) {
|
||||
return request({
|
||||
url: '/pay/app/list-merchant-id',
|
||||
params:{
|
||||
merchantId:merchantId
|
||||
},
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建支付渠道
|
||||
export function createChannel(data) {
|
||||
return request({
|
||||
url: '/pay/channel/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 更新支付渠道
|
||||
export function updateChannel(data) {
|
||||
return request({
|
||||
url: '/pay/channel/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除支付渠道
|
||||
export function deleteChannel(id) {
|
||||
return request({
|
||||
url: '/pay/channel/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付渠道
|
||||
// export function getChannel(id) {
|
||||
// return request({
|
||||
// url: '/pay/channel/get?id=' + id,
|
||||
// method: 'get'
|
||||
// })
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// 获得支付渠道分页
|
||||
export function getChannelPage(query) {
|
||||
return request({
|
||||
url: '/pay/channel/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出支付渠道Excel
|
||||
export function exportChannelExcel(query) {
|
||||
return request({
|
||||
url: '/pay/channel/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付渠道
|
||||
export function getChannel(merchantId,appId,code) {
|
||||
return request({
|
||||
url: '/pay/channel/get-channel',
|
||||
params:{
|
||||
merchantId:merchantId,
|
||||
appId:appId,
|
||||
code:code
|
||||
},
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建示例订单
|
||||
export function createDemoOrder(data) {
|
||||
return request({
|
||||
url: '/pay/demo-order/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获得示例订单
|
||||
export function getDemoOrder(id) {
|
||||
return request({
|
||||
url: '/pay/demo-order/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得示例订单分页
|
||||
export function getDemoOrderPage(query) {
|
||||
return request({
|
||||
url: '/pay/demo-order/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 退款示例订单
|
||||
export function refundDemoOrder(id) {
|
||||
return request({
|
||||
url: '/pay/demo-order/refund?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建支付商户信息
|
||||
export function createMerchant(data) {
|
||||
return request({
|
||||
url: '/pay/merchant/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新支付商户信息
|
||||
export function updateMerchant(data) {
|
||||
return request({
|
||||
url: '/pay/merchant/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 支付商户状态修改
|
||||
export function changeMerchantStatus(id, status) {
|
||||
const data = {
|
||||
id,
|
||||
status
|
||||
}
|
||||
return request({
|
||||
url: '/pay/merchant/update-status',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除支付商户信息
|
||||
export function deleteMerchant(id) {
|
||||
return request({
|
||||
url: '/pay/merchant/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付商户信息
|
||||
export function getMerchant(id) {
|
||||
return request({
|
||||
url: '/pay/merchant/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 根据商户名称搜索商户列表
|
||||
export function getMerchantListByName(name) {
|
||||
return request({
|
||||
url: '/pay/merchant/list-by-name',
|
||||
params:{
|
||||
name:name
|
||||
},
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付商户信息分页
|
||||
export function getMerchantPage(query) {
|
||||
return request({
|
||||
url: '/pay/merchant/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出支付商户信息 Excel
|
||||
export function exportMerchantExcel(query) {
|
||||
return request({
|
||||
url: '/pay/merchant/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 删除支付订单
|
||||
export function deleteOrder(id) {
|
||||
return request({
|
||||
url: '/pay/order/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付订单
|
||||
export function getOrder(id) {
|
||||
return request({
|
||||
url: '/pay/order/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付订单的明细
|
||||
export function getOrderDetail(id) {
|
||||
return request({
|
||||
url: '/pay/order/get-detail?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 提交支付订单
|
||||
export function submitOrder(data) {
|
||||
return request({
|
||||
url: '/pay/order/submit',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 获得支付订单分页
|
||||
export function getOrderPage(query) {
|
||||
return request({
|
||||
url: '/pay/order/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出支付订单 Excel
|
||||
export function exportOrderExcel(query) {
|
||||
return request({
|
||||
url: '/pay/order/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 创建退款订单
|
||||
export function createRefund(data) {
|
||||
return request({
|
||||
url: '/pay/refund/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新退款订单
|
||||
export function updateRefund(data) {
|
||||
return request({
|
||||
url: '/pay/refund/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除退款订单
|
||||
export function deleteRefund(id) {
|
||||
return request({
|
||||
url: '/pay/refund/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得退款订单
|
||||
export function getRefund(id) {
|
||||
return request({
|
||||
url: '/pay/refund/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得退款订单分页
|
||||
export function getRefundPage(query) {
|
||||
return request({
|
||||
url: '/pay/refund/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 导出退款订单 Excel
|
||||
export function exportRefundExcel(query) {
|
||||
return request({
|
||||
url: '/pay/refund/export-excel',
|
||||
method: 'get',
|
||||
params: query,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
@@ -134,8 +134,8 @@ $base1px: 0.15vh; // 1px / 1080px;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
position: relative;
|
||||
top: calc(-32 * $base1px);
|
||||
height: calc(128 * $base1px);
|
||||
top: calc(-32 * #{$base1px});
|
||||
height: calc(128 * #{$base1px});
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
|
||||
46
src/main.js
@@ -9,13 +9,12 @@ import store from './store';
|
||||
import router from './router';
|
||||
import directive from './directive'; // directive
|
||||
import plugins from './plugins'; // plugins
|
||||
import { scrollBoard } from '@jiaminghi/data-view'
|
||||
import { scrollBoard } from '@jiaminghi/data-view';
|
||||
|
||||
import './assets/icons'; // icon
|
||||
import './permission'; // permission control
|
||||
// import './tongji' // 百度统计
|
||||
import { getDicts } from '@/api/system/dict/data';
|
||||
import { getConfigKey } from '@/api/infra/config';
|
||||
import {
|
||||
parseTime,
|
||||
resetForm,
|
||||
@@ -40,7 +39,6 @@ import './theme/index.css'; // 自定义主题包 - code-brick-zj
|
||||
|
||||
// 全局方法挂载
|
||||
Vue.prototype.getDicts = getDicts;
|
||||
Vue.prototype.getConfigKey = getConfigKey;
|
||||
Vue.prototype.parseTime = parseTime;
|
||||
Vue.prototype.resetForm = resetForm;
|
||||
Vue.prototype.getDictDatas = getDictDatas;
|
||||
@@ -50,16 +48,19 @@ Vue.prototype.DICT_TYPE = DICT_TYPE;
|
||||
Vue.prototype.handleTree = handleTree;
|
||||
Vue.prototype.addBeginAndEndTime = addBeginAndEndTime;
|
||||
Vue.prototype.divide = divide;
|
||||
Vue.prototype.tableHeight = function(n) {
|
||||
return window.innerHeight - n
|
||||
}
|
||||
Vue.prototype.searchBarWidth = function(name, num) {
|
||||
if (document.getElementById(name) && document.getElementById(name).offsetWidth < num) {
|
||||
return true
|
||||
Vue.prototype.tableHeight = function (n) {
|
||||
return window.innerHeight - n;
|
||||
};
|
||||
Vue.prototype.searchBarWidth = function (name, num) {
|
||||
if (
|
||||
document.getElementById(name) &&
|
||||
document.getElementById(name).offsetWidth < num
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 全局组件挂载
|
||||
Vue.component('DictTag', DictTag);
|
||||
@@ -72,29 +73,18 @@ import DocAlert from '@/components/DocAlert';
|
||||
// 头部标签插件
|
||||
import VueMeta from 'vue-meta';
|
||||
import CodeBrickZj from 'code-brick-zj';
|
||||
import { hiPrintPlugin,disAutoConnect } from 'vue-plugin-hiprint'
|
||||
import { hiPrintPlugin, disAutoConnect } from 'vue-plugin-hiprint';
|
||||
disAutoConnect();
|
||||
Vue.use(hiPrintPlugin)
|
||||
Vue.use(CodeBrickZj)
|
||||
Vue.use(hiPrintPlugin);
|
||||
Vue.use(CodeBrickZj);
|
||||
Vue.use(directive);
|
||||
Vue.use(plugins);
|
||||
Vue.use(VueMeta);
|
||||
Vue.use(scrollBoard)
|
||||
Vue.use(scrollBoard);
|
||||
// Vue.use(hljs.vuePlugin);
|
||||
import scroll from 'vue-seamless-scroll'
|
||||
Vue.use(scroll)
|
||||
// bpmnProcessDesigner 需要引入
|
||||
import MyPD from '@/components/bpmnProcessDesigner/package/index.js';
|
||||
Vue.use(MyPD);
|
||||
import '@/components/bpmnProcessDesigner/package/theme/index.scss';
|
||||
import 'bpmn-js/dist/assets/diagram-js.css';
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
|
||||
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
|
||||
import scroll from 'vue-seamless-scroll';
|
||||
Vue.use(scroll);
|
||||
|
||||
// Form Generator 组件需要使用到 tinymce
|
||||
import Tinymce from '@/components/tinymce/index.vue';
|
||||
Vue.component('tinymce', Tinymce);
|
||||
import '@/assets/icons';
|
||||
import request from '@/utils/request'; // 实现 form generator 使用自己定义的 axios request 对象
|
||||
// console.log(request);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
/* Layout */
|
||||
import Layout from '@/layout'
|
||||
import Layout from '@/layout';
|
||||
|
||||
Vue.use(Router)
|
||||
Vue.use(Router);
|
||||
|
||||
/**
|
||||
* Note: 路由配置项
|
||||
@@ -124,12 +124,12 @@ export const constantRoutes = [
|
||||
// 防止连续点击多次路由报错
|
||||
let routerPush = Router.prototype.push;
|
||||
Router.prototype.push = function push(location) {
|
||||
return routerPush.call(this, location).catch(err => err)
|
||||
}
|
||||
return routerPush.call(this, location).catch((err) => err);
|
||||
};
|
||||
|
||||
export default new Router({
|
||||
base: process.env.VUE_APP_APP_NAME ? process.env.VUE_APP_APP_NAME : "/",
|
||||
mode: 'hash', // 去掉url中的#
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes
|
||||
})
|
||||
base: process.env.VUE_APP_APP_NAME ? process.env.VUE_APP_APP_NAME : '/',
|
||||
mode: 'hash', // 去掉url中的#
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes,
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -1,21 +0,0 @@
|
||||
// Baidu 统计 integration
|
||||
import router from './router'
|
||||
|
||||
window._hmt = window._hmt || []; // 用于 router push
|
||||
const HM_ID = process.env.VUE_APP_BAIDU_CODE || ''; // 有值的时候,才开启
|
||||
(function() {
|
||||
if (!HM_ID) {
|
||||
return;
|
||||
}
|
||||
const hm = document.createElement("script")
|
||||
hm.src = "https://hm.baidu.com/hm.js?" + HM_ID
|
||||
const s = document.getElementsByTagName("script")[0]
|
||||
s.parentNode.insertBefore(hm, s)
|
||||
})()
|
||||
|
||||
router.afterEach(function (to) {
|
||||
if (!HM_ID) {
|
||||
return;
|
||||
}
|
||||
_hmt.push(['_trackPageview', to.fullPath])
|
||||
})
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* 将服务端返回的 fields 字符串数组,解析成 JSON 数组
|
||||
* 如果指定了 variables 参数可对表单进行初始化
|
||||
*
|
||||
* @param fields JSON 字符串数组
|
||||
* @param variables Object 表单初始值
|
||||
* @returns {*[]} JSON 数组
|
||||
*/
|
||||
export function decodeFields(fields, variables) {
|
||||
const drawingList = (fields || []).map(json => {
|
||||
const item = JSON.parse(json)
|
||||
|
||||
if (typeof variables === 'undefined' ) return item
|
||||
|
||||
const setDefault = (item, variables) => {
|
||||
if (typeof variables[item.__vModel__] !== 'undefined') {
|
||||
item.__config__.defaultValue = variables[item.__vModel__]
|
||||
}
|
||||
if (item.__config__.children && item.__config__.children.length) {
|
||||
item.__config__.children.forEach(child => {
|
||||
setDefault(child, variables)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
setDefault(item, variables)
|
||||
|
||||
return item
|
||||
})
|
||||
|
||||
return drawingList
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import loadScript from './loadScript'
|
||||
import ELEMENT from 'element-ui'
|
||||
import pluginsConfig from './pluginsConfig'
|
||||
|
||||
let beautifierObj
|
||||
|
||||
export default function loadBeautifier(cb) {
|
||||
const { beautifierUrl } = pluginsConfig
|
||||
if (beautifierObj) {
|
||||
cb(beautifierObj)
|
||||
return
|
||||
}
|
||||
|
||||
const loading = ELEMENT.Loading.service({
|
||||
fullscreen: true,
|
||||
lock: true,
|
||||
text: '格式化资源加载中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(255, 255, 255, 0.5)'
|
||||
})
|
||||
|
||||
loadScript(beautifierUrl, () => {
|
||||
loading.close()
|
||||
// eslint-disable-next-line no-undef
|
||||
beautifierObj = beautifier
|
||||
cb(beautifierObj)
|
||||
})
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import loadScript from './loadScript'
|
||||
import ELEMENT from 'element-ui'
|
||||
import pluginsConfig from './pluginsConfig'
|
||||
|
||||
// monaco-editor单例
|
||||
let monacoEidtor
|
||||
|
||||
/**
|
||||
* 动态加载monaco-editor cdn资源
|
||||
* @param {Function} cb 回调,必填
|
||||
*/
|
||||
export default function loadMonaco(cb) {
|
||||
if (monacoEidtor) {
|
||||
cb(monacoEidtor)
|
||||
return
|
||||
}
|
||||
|
||||
const { monacoEditorUrl: vs } = pluginsConfig
|
||||
|
||||
// 使用element ui实现加载提示
|
||||
const loading = ELEMENT.Loading.service({
|
||||
fullscreen: true,
|
||||
lock: true,
|
||||
text: '编辑器资源初始化中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(255, 255, 255, 0.5)'
|
||||
})
|
||||
|
||||
!window.require && (window.require = {})
|
||||
!window.require.paths && (window.require.paths = {})
|
||||
window.require.paths.vs = vs
|
||||
|
||||
loadScript(`${vs}/loader.js`, () => {
|
||||
window.require(['vs/editor/editor.main'], () => {
|
||||
loading.close()
|
||||
monacoEidtor = window.monaco
|
||||
cb(monacoEidtor)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
const callbacks = {}
|
||||
|
||||
/**
|
||||
* 加载一个远程脚本
|
||||
* @param {String} src 一个远程脚本
|
||||
* @param {Function} callback 回调
|
||||
*/
|
||||
function loadScript(src, callback) {
|
||||
const existingScript = document.getElementById(src)
|
||||
const cb = callback || (() => {})
|
||||
if (!existingScript) {
|
||||
callbacks[src] = []
|
||||
const $script = document.createElement('script')
|
||||
$script.src = src
|
||||
$script.id = src
|
||||
$script.async = 1
|
||||
document.body.appendChild($script)
|
||||
const onEnd = 'onload' in $script ? stdOnEnd.bind($script) : ieOnEnd.bind($script)
|
||||
onEnd($script)
|
||||
}
|
||||
|
||||
callbacks[src].push(cb)
|
||||
|
||||
function stdOnEnd(script) {
|
||||
script.onload = () => {
|
||||
this.onerror = this.onload = null
|
||||
callbacks[src].forEach(item => {
|
||||
item(null, script)
|
||||
})
|
||||
delete callbacks[src]
|
||||
}
|
||||
script.onerror = () => {
|
||||
this.onerror = this.onload = null
|
||||
cb(new Error(`Failed to load ${src}`), script)
|
||||
}
|
||||
}
|
||||
|
||||
function ieOnEnd(script) {
|
||||
script.onreadystatechange = () => {
|
||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
||||
this.onreadystatechange = null
|
||||
callbacks[src].forEach(item => {
|
||||
item(null, script)
|
||||
})
|
||||
delete callbacks[src]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序加载一组远程脚本
|
||||
* @param {Array} list 一组远程脚本
|
||||
* @param {Function} cb 回调
|
||||
*/
|
||||
export function loadScriptQueue(list, cb) {
|
||||
const first = list.shift()
|
||||
list.length ? loadScript(first, () => loadScriptQueue(list, cb)) : loadScript(first, cb)
|
||||
}
|
||||
|
||||
export default loadScript
|
||||
@@ -1,29 +0,0 @@
|
||||
import loadScript from './loadScript'
|
||||
import ELEMENT from 'element-ui'
|
||||
import pluginsConfig from './pluginsConfig'
|
||||
|
||||
let tinymceObj
|
||||
|
||||
export default function loadTinymce(cb) {
|
||||
const { tinymceUrl } = pluginsConfig
|
||||
|
||||
if (tinymceObj) {
|
||||
cb(tinymceObj)
|
||||
return
|
||||
}
|
||||
|
||||
const loading = ELEMENT.Loading.service({
|
||||
fullscreen: true,
|
||||
lock: true,
|
||||
text: '富文本资源加载中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(255, 255, 255, 0.5)'
|
||||
})
|
||||
|
||||
loadScript(tinymceUrl, () => {
|
||||
loading.close()
|
||||
// eslint-disable-next-line no-undef
|
||||
tinymceObj = tinymce
|
||||
cb(tinymceObj)
|
||||
})
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
const CDN = 'https://lib.baomitu.com/' // CDN Homepage: https://cdn.baomitu.com/
|
||||
const publicPath = process.env.BASE_URL
|
||||
|
||||
function splicingPluginUrl(PluginName, version, fileName) {
|
||||
return `${CDN}${PluginName}/${version}/${fileName}`
|
||||
}
|
||||
|
||||
export default {
|
||||
beautifierUrl: splicingPluginUrl('js-beautify', '1.13.5', 'beautifier.min.js'),
|
||||
// monacoEditorUrl: splicingPluginUrl('monaco-editor', '0.19.3', 'min/vs'), // 使用 monaco-editor CDN 链接
|
||||
monacoEditorUrl: `${publicPath}libs/monaco-editor/vs`, // 使用 monaco-editor 本地代码
|
||||
tinymceUrl: splicingPluginUrl('tinymce', '5.7.0', 'tinymce.min.js')
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
|
||||