Merge branch 'projects/mesxc-test' into projects/mesxc-zjl
@@ -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,7 +1,7 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: zhp
 | 
			
		||||
 * @Date: 2024-01-29 16:50:26
 | 
			
		||||
 * @LastEditTime: 2024-03-26 16:30:12
 | 
			
		||||
 * @LastEditTime: 2024-03-26 18:00:34
 | 
			
		||||
 * @LastEditors: zhp
 | 
			
		||||
 * @Description:
 | 
			
		||||
-->
 | 
			
		||||
@@ -381,12 +381,12 @@ export default {
 | 
			
		||||
          })
 | 
			
		||||
          this.$refs['ISRAChart'].updateChart(chartData)
 | 
			
		||||
        } else if (this.SJGWsData.type === 'equipment') {
 | 
			
		||||
          this.realEqList = this.SJGWsData.detData.map((ele, index) => [
 | 
			
		||||
          this.realEqList = this.SJGWsData.detData.map((item, index) => [
 | 
			
		||||
            // console.log(item)
 | 
			
		||||
            `<span style="color:rgba(255,255,255,0.5)" >${index + 1 || ''}
 | 
			
		||||
            </span>`,
 | 
			
		||||
            `<span style="color:rgba(255,255,255,0.5)">${ele.name || ''}</span>`,
 | 
			
		||||
            `<span style="color:rgba(255,255,255,0.5)">${ele.run || ''}</span>`,
 | 
			
		||||
            `<span style="color:rgba(255,255,255,0.5)">${item.name || ''}</span>`,
 | 
			
		||||
            `<span style="color:rgba(255,255,255,0.5)">${item.run || ''}</span>`,
 | 
			
		||||
          ])
 | 
			
		||||
        }
 | 
			
		||||
        this.realEqConfig.data = this.realEqList
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * @Author: zwq
 | 
			
		||||
 * @Date: 2021-07-19 15:18:30
 | 
			
		||||
 * @LastEditors: zhp
 | 
			
		||||
 * @LastEditTime: 2024-03-26 15:43:27
 | 
			
		||||
 * @LastEditTime: 2024-03-26 17:57:44
 | 
			
		||||
 * @Description:
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
@@ -448,7 +448,7 @@ export default {
 | 
			
		||||
        // console.log('22222', this.wsData.data)
 | 
			
		||||
        if (this.SJGWsData.type === 'order') {
 | 
			
		||||
          this.orderList = this.SJGWsData.detData.map((ele, index) => {
 | 
			
		||||
            if (ele.progressRate != 1) {
 | 
			
		||||
            if (ele.progressRate && ele.progressRate != 1) {
 | 
			
		||||
              return {
 | 
			
		||||
                id: ele.id,
 | 
			
		||||
                name: ele.name,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,3 @@
 | 
			
		||||
/*
 | 
			
		||||
 * @Author: zhp
 | 
			
		||||
 * @Date: 2024-01-29 17:05:25
 | 
			
		||||
 * @LastEditTime: 2024-01-29 17:05:25
 | 
			
		||||
 * @LastEditors: zhp
 | 
			
		||||
 * @Description:
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * 发起websocket请求函数
 | 
			
		||||
 * @param {string} url ws连接地址
 | 
			
		||||
@@ -49,7 +42,7 @@ export function WsConnect(url, agentData, successCallback, errCallback) {
 | 
			
		||||
      this.lockReconnect = true;
 | 
			
		||||
      this.wsCreateHandler && clearTimeout(this.wsCreateHandler);
 | 
			
		||||
      // 关闭心跳检查
 | 
			
		||||
      // heartCheck.stop();
 | 
			
		||||
      heartCheck.stop();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  const initWsEventHandle = () => {
 | 
			
		||||
@@ -57,13 +50,13 @@ export function WsConnect(url, agentData, successCallback, errCallback) {
 | 
			
		||||
      // 连接成功
 | 
			
		||||
      this.wsObj.onopen = (event) => {
 | 
			
		||||
        onWsOpen(event);
 | 
			
		||||
        // heartCheck.start();
 | 
			
		||||
        heartCheck.start();
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // 监听服务器端返回的信息
 | 
			
		||||
      this.wsObj.onmessage = (event) => {
 | 
			
		||||
        onWsMessage(event);
 | 
			
		||||
        // heartCheck.start();
 | 
			
		||||
        heartCheck.start();
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      this.wsObj.onclose = (event) => {
 | 
			
		||||
@@ -130,7 +123,7 @@ export function WsConnect(url, agentData, successCallback, errCallback) {
 | 
			
		||||
    if (this.lockReconnect) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    writeToScreen("3秒后重连");
 | 
			
		||||
    writeToScreen("5秒后重连");
 | 
			
		||||
    this.lockReconnect = true;
 | 
			
		||||
    // 没连接上会一直重连,设置延迟避免请求过多
 | 
			
		||||
    this.wsCreateHandler && clearTimeout(this.wsCreateHandler);
 | 
			
		||||
@@ -139,10 +132,40 @@ export function WsConnect(url, agentData, successCallback, errCallback) {
 | 
			
		||||
      this.createWebSoket();
 | 
			
		||||
      this.lockReconnect = false;
 | 
			
		||||
      writeToScreen("重连完成");
 | 
			
		||||
    }, 3000);
 | 
			
		||||
    }, 5000);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // 心跳检查(看看websocket是否还在正常连接中)
 | 
			
		||||
  // 心跳检查(看看websocket是否还在正常连接中,不需要服务端返回,单向的)
 | 
			
		||||
  let _this = this
 | 
			
		||||
  let heartCheck = {
 | 
			
		||||
    timeout: 55000,
 | 
			
		||||
    timeoutObj: null,
 | 
			
		||||
    // 重启
 | 
			
		||||
    reset() {
 | 
			
		||||
      clearTimeout(this.timeoutObj);
 | 
			
		||||
      this.start();
 | 
			
		||||
    },
 | 
			
		||||
    // 停止
 | 
			
		||||
    stop() {
 | 
			
		||||
      clearTimeout(this.timeoutObj);
 | 
			
		||||
    },
 | 
			
		||||
    // 开启定时器
 | 
			
		||||
    start() {
 | 
			
		||||
      this.timeoutObj && clearTimeout(this.timeoutObj);
 | 
			
		||||
      this.timeoutObj = setTimeout(() => {
 | 
			
		||||
        writeToScreen("心跳检查,发送ping到后台");
 | 
			
		||||
        try {
 | 
			
		||||
          const datas = { ping: true };
 | 
			
		||||
          _this.wsObj.send(JSON.stringify(datas));
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
          writeToScreen("发送ping异常");
 | 
			
		||||
        }
 | 
			
		||||
      }, this.timeout);
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // 心跳检查(看看websocket是否还在正常连接中,和服务端通信,双向的)
 | 
			
		||||
  // let heartCheck = {
 | 
			
		||||
  //   timeout: 15000,
 | 
			
		||||
  //   timeoutObj: null,
 | 
			
		||||
@@ -167,7 +190,7 @@ export function WsConnect(url, agentData, successCallback, errCallback) {
 | 
			
		||||
  //       writeToScreen("心跳检查,发送ping到后台");
 | 
			
		||||
  //       try {
 | 
			
		||||
  //         const datas = { ping: true };
 | 
			
		||||
  //         this.wsObj.send(JSON.stringify(datas));
 | 
			
		||||
  //         _this.wsObj.send(JSON.stringify(datas));
 | 
			
		||||
  //       } catch (err) {
 | 
			
		||||
  //         writeToScreen("发送ping异常");
 | 
			
		||||
  //       }
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: zhp
 | 
			
		||||
 * @Date: 2024-01-24 15:15:24
 | 
			
		||||
 * @LastEditTime: 2024-03-26 09:34:12
 | 
			
		||||
 * @LastEditTime: 2024-03-27 09:27:23
 | 
			
		||||
 * @LastEditors: zhp
 | 
			
		||||
 * @Description:
 | 
			
		||||
-->
 | 
			
		||||
@@ -16,9 +16,9 @@
 | 
			
		||||
          </el-date-picker>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
        <el-form-item>
 | 
			
		||||
          <el-button v-if="this.$auth.hasPermi('report:glass-month:query')" type="primary" size="small"
 | 
			
		||||
          <el-button v-if="this.$auth.hasPermi('base:report-auto-original-glass:query')" type="primary" size="small"
 | 
			
		||||
            @click="getDataList">查询</el-button>
 | 
			
		||||
          <el-button v-if="this.$auth.hasPermi('report:glass-month:export')" type="primary" size="small" plain
 | 
			
		||||
          <el-button v-if="this.$auth.hasPermi('report:glass-day:export')" type="primary" size="small" plain
 | 
			
		||||
            @click="handleExport">导出</el-button>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
      </el-form>
 | 
			
		||||
@@ -187,8 +187,8 @@ export default {
 | 
			
		||||
        this.endTimeStamp = this.format(val.setHours(7, 0, 0)) //+ ' 00:00:00' //new Date(this.startTimeStamp + ' 00:00:00').getTime() / 1000
 | 
			
		||||
        this.startTimeStamp  = this.format(val.setHours(7, 0, 1) - 24 * 60 * 60 * 1000) //+ ' 23:59:59' //new Date(this.endTimeStamp + ' 23:59:59').getTime() / 1000
 | 
			
		||||
        // console.log(this.listQuery.reportTime);
 | 
			
		||||
        this.listQuery.reportTime[1] = this.format(val.setHours(7, 0, 1)) //+ ' 00:00:00' //new Date(this.startTimeStamp + ' 00:00:00').getTime() / 1000
 | 
			
		||||
        this.listQuery.reportTime[0] = this.format(val.setHours(7, 0, 0) + 24 * 60 * 60 * 1000) //+ ' 23:59:59' //new Date(this.endTimeStamp + ' 23:59:59').getTime() / 1000
 | 
			
		||||
        this.listQuery.reportTime[0] = this.format(val.setHours(7, 0, 1)) //+ ' 00:00:00' //new Date(this.startTimeStamp + ' 00:00:00').getTime() / 1000
 | 
			
		||||
        this.listQuery.reportTime[1] = this.format(val.setHours(7, 0, 0) + 24 * 60 * 60 * 1000) //+ ' 23:59:59' //new Date(this.endTimeStamp + ' 23:59:59').getTime() / 1000
 | 
			
		||||
        console.log(this.listQuery.reportTime);
 | 
			
		||||
			} else {
 | 
			
		||||
					this.listQuery.reportTime = []
 | 
			
		||||
 
 | 
			
		||||