...
14
src/.env
Normal file
@@ -0,0 +1,14 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_PREVIEW=false
|
||||
|
||||
; <!-- // 水感应大数据分析审核系统环境测试 -->
|
||||
|
||||
#VUE_APP_API_BASE_URL=https://admin.shuzijingji.org.cn/agent
|
||||
; VUE_APP_API_BASE_URL=http://api.goodsright.shangkelian.cn/agent
|
||||
; VUE_APP_CHAIN_RPC_URL=https://chain-api.shuzijingji.org.cn
|
||||
|
||||
; <!-- // 水感应大数据分析审核系统正式测试 -->
|
||||
|
||||
#VUE_APP_API_BASE_URL=https://admin.shuzijingji.org.cn/agent
|
||||
VUE_APP_API_BASE_URL=https://gz-api.lianshang.vip/agent
|
||||
VUE_APP_CHAIN_RPC_URL=https://chain-api.shuzijingji.org.cn
|
||||
34
src/App.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
<template>
|
||||
<a-config-provider :locale="locale">
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { domTitle, setDocumentTitle } from '@/utils/domUtil'
|
||||
import { i18nRender } from '@/locales'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
locale () {
|
||||
// 只是为了切换语言时,更新标题
|
||||
const { title } = this.$route.meta
|
||||
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
|
||||
|
||||
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ml8 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
102
src/api/address.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
addressList: '/staff/addresses',
|
||||
addressAllList: '/staff/addresses/all',
|
||||
addressExpress: '/orders/{order}/express',
|
||||
addressCreate: '/staff/addresses',
|
||||
addressDetail: '/staff/addresses/{addressId}',
|
||||
updateAddress: '/staff/addresses/{addressId}',
|
||||
deleteAddress: '/staff/addresses/{addressId}',
|
||||
defaultAddress: '/staff/addresses/{addressId}/default'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地址列表
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function getAddrList (parameter) {
|
||||
return request({
|
||||
url: api.addressList,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有地址
|
||||
export function getAllAddrList () {
|
||||
return request({
|
||||
url: api.addressAllList,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 指派邮寄地址
|
||||
export function addressExpress (order, parameter) {
|
||||
return request({
|
||||
url: api.addressExpress.replace('{order}', order),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增地址
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function createAddr (parameter) {
|
||||
return request({
|
||||
url: api.addressCreate,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地址详情
|
||||
* @param addressId
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function getAddr (addressId) {
|
||||
return request({
|
||||
url: api.addressDetail.replace('{addressId}', addressId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑地址
|
||||
* @param addressId
|
||||
*/
|
||||
export function updateAddr (addressId, parameter) {
|
||||
return request({
|
||||
url: api.updateAddress.replace('{addressId}', addressId),
|
||||
method: 'put',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除地址
|
||||
* @param addressId
|
||||
*/
|
||||
export function deleteAddr (addressId) {
|
||||
return request({
|
||||
url: api.deleteAddress.replace('{addressId}', addressId),
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认地址
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function defaultAddress (addressId) {
|
||||
return request({
|
||||
url: api.defaultAddress.replace('{addressId}', addressId),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
112
src/api/express.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
expressCommonList: '/mall/orders/{orderId}/deliver',
|
||||
expressList: '/store/expresses',
|
||||
createExpress: '/store/expresses',
|
||||
editExpress: '/store/expresses/{expressId}/edit',
|
||||
updateExpress: '/store/expresses/{expressId}',
|
||||
deleteExpress: '/store/expresses/{expressId}',
|
||||
getExpressDrow: '/staff/expresses',
|
||||
signInDrow: '/orders/{orderId}/outlineexpress'
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存物流信息时候用的接口
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function getExpressCommonList (orderId) {
|
||||
return request({
|
||||
url: api.expressCommonList.replace('{orderId}', orderId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 物流列表
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function getExpressList (parameter) {
|
||||
return request({
|
||||
url: api.expressList,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
* @param data
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function storeExpress (data) {
|
||||
return request({
|
||||
url: api.createExpress,
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param expressId
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function editExpress (expressId) {
|
||||
return request({
|
||||
url: api.editExpress.replace('{expressId}', expressId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
* @param expressId
|
||||
* @param data
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function updateExpress (expressId, data) {
|
||||
return request({
|
||||
url: api.updateExpress.replace('{expressId}', expressId),
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除物流
|
||||
* @param expressId
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function deleteExpress (expressId) {
|
||||
return request({
|
||||
url: api.deleteExpress.replace('{expressId}', expressId),
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 线下签收信息前置
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function getExpressDrow (parameter) {
|
||||
return request({
|
||||
url: api.getExpressDrow,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 线下签收
|
||||
* @param parameter
|
||||
* @returns {AxiosPromise}
|
||||
*/
|
||||
export function signInDrow (orderId, parameter) {
|
||||
return request({
|
||||
url: api.signInDrow.replace('{orderId}', orderId),
|
||||
method: 'POST',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
87
src/api/login.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const userApi = {
|
||||
SendSms: '/staff/verify',
|
||||
Login: '/auth/sms',
|
||||
Logout: '/auth/logout',
|
||||
CommonLogin: '/staff/login',
|
||||
forgetPassword: '/staff/forget/password',
|
||||
password: '/staff/password',
|
||||
// get my info
|
||||
UserPermission: '/staff',
|
||||
getScanCode: '/staff/scan_code',
|
||||
getVerifyScanCode: '/staff/verify_subscribe'
|
||||
}
|
||||
|
||||
export function login (parameter) {
|
||||
return request({
|
||||
url: userApi.Login,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用账号密码登录
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function commonLogin (parameter) {
|
||||
parameter.redirectUrl = window.location.href
|
||||
return request({
|
||||
url: userApi.CommonLogin,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function forgetPassword (parameter) {
|
||||
return request({
|
||||
url: userApi.forgetPassword,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function password (parameter) {
|
||||
return request({
|
||||
url: userApi.password,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getSmsCaptcha (parameter) {
|
||||
return request({
|
||||
url: userApi.SendSms,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getPermission () {
|
||||
return request({
|
||||
url: userApi.UserPermission,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function logout () {
|
||||
return request({
|
||||
url: userApi.Logout,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
// 获取关注二维码
|
||||
export function getScanCode () {
|
||||
return request({
|
||||
url: userApi.getScanCode
|
||||
})
|
||||
}
|
||||
|
||||
// 判断用户是否关注二维码
|
||||
export function getVerifyScanCode () {
|
||||
return request({
|
||||
url: userApi.getVerifyScanCode
|
||||
})
|
||||
}
|
||||
54
src/api/notice.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
unreadCount: '/notifies/unread_count',
|
||||
notifies: '/notifies',
|
||||
readNotice: '/notifies/mark_as_read/{noticeId}',
|
||||
readAllNotices: '/notifies/mark_as_read_all',
|
||||
sendMessage: '/notifies/send/{orderId}'
|
||||
}
|
||||
// 未读消息总数 6s 一轮回
|
||||
export function getUnreadCount () {
|
||||
return request({
|
||||
url: api.unreadCount,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 消息列表
|
||||
export function getNoticeList (parameter) {
|
||||
return request({
|
||||
url: api.notifies,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 消息已读
|
||||
export function readNotice (noticeId) {
|
||||
return request({
|
||||
url: api.readNotice.replace('{noticeId}', noticeId),
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
|
||||
// 消息全部已读
|
||||
export function readAllNotice (noticeId) {
|
||||
return request({
|
||||
url: api.readAllNotices,
|
||||
method: 'POST'
|
||||
})
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
|
||||
export function sendMessage (orderId, type, itemId) {
|
||||
return request({
|
||||
url: api.sendMessage.replace('{orderId}', orderId),
|
||||
method: 'POST',
|
||||
params: {
|
||||
type: type,
|
||||
item_id: itemId
|
||||
}
|
||||
})
|
||||
}
|
||||
247
src/api/order.js
Normal file
@@ -0,0 +1,247 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
list: '/orders',
|
||||
info: '/orders/{orderId}',
|
||||
base: '/orders/{orderId}/base',
|
||||
items: '/orders/{orderId}/items',
|
||||
services: '/orders/{orderId}/services',
|
||||
check: '/orders/{orderId}/check',
|
||||
updateOrderInfo: '/orders/{orderId}/update',
|
||||
pass: '/orders/{orderId}/check/pass',
|
||||
repass: '/orders/{orderId}/repass',
|
||||
diffp: '/orders/{orderId}/diffprice',
|
||||
diffs: '/orders/{orderId}/diffs',
|
||||
diffBack: '/orders/{orderId}/diffprice/{diff}',
|
||||
firstpass: 'orders/{orderId}/firstpass',
|
||||
teachermakesure: 'orders/{orderId}/teachermakesure',
|
||||
getExpressesList: 'orders/{orderId}/expresses',
|
||||
logistic: 'orders/{express}/logistic',
|
||||
signInLogistic: 'orders/{orderId}/sign/{express}',
|
||||
doLogs: 'orders/{orderId}/dologs',
|
||||
doLogsList: 'orders/{orderId}/dologs',
|
||||
delLog: 'orders/{orderId}/dologs/{logId}',
|
||||
getSchemes: 'orders/{orderId}/schemes/{itemId}',
|
||||
institutionEdit: 'institutions/{itemId}/institution', // 修改机构名称 主要做备注用换了机构
|
||||
getOrdersCount: 'orders/count',
|
||||
changeBankCount: 'orders/{orderId}/items/{itemId}/price',
|
||||
getChangeBankCountLog: 'orders/{orderId}/items/{itemId}/price_log',
|
||||
getAllBanks: 'orders/{orderId}/all_items' // 获得所有机构信息
|
||||
}
|
||||
// 订单列表
|
||||
export function getOrderList (parameter) {
|
||||
return request({
|
||||
url: api.list,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 根据订单id获取订单详情
|
||||
export function orderInfo (orderId) {
|
||||
return request({
|
||||
url: api.info.replace('{orderId}', orderId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 根据订单id获取下单用户的真实信息
|
||||
export function realName (orderId) {
|
||||
return request({
|
||||
url: api.base.replace('{orderId}', orderId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 根据订单 id 获取下单申请机构列表
|
||||
export function getBankItem (orderId, parameter) {
|
||||
return request({
|
||||
url: api.items.replace('{orderId}', orderId),
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 根据id 展示服务包
|
||||
export function getServices (orderId, parameter) {
|
||||
return request({
|
||||
url: api.services.replace('{orderId}', orderId),
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 订单信息修改
|
||||
export function updateOrderInfo (orderId, parameter) {
|
||||
return request({
|
||||
url: api.updateOrderInfo.replace('{orderId}', orderId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 驳回用户基本信息和机构信息 type 1. 用户信息 2. 机构信息
|
||||
export function checkInfo (orderId, parameter) {
|
||||
return request({
|
||||
url: api.check.replace('{orderId}', orderId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 用户信息驳回通过/orders/1/check/pass
|
||||
export function passInfo (orderId, parameter) {
|
||||
return request({
|
||||
url: api.pass.replace('{orderId}', orderId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 用户服务包补差价
|
||||
export function diffPrice (orderId, parameter) {
|
||||
return request({
|
||||
url: api.diffp.replace('{orderId}', orderId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 用户服务包补差价记录
|
||||
export function diffPayList (orderId) {
|
||||
return request({
|
||||
url: api.diffs.replace('{orderId}', orderId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 撤回补差价
|
||||
export function diffBack (orderId, diff) {
|
||||
return request({
|
||||
url: api.diffBack.replace('{orderId}', orderId).replace('{diff}', diff),
|
||||
method: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
// 初审通过orders/{order}/firstpass
|
||||
export function firstPass (orderId) {
|
||||
return request({
|
||||
url: api.firstpass.replace('{orderId}', orderId),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 复审
|
||||
export function secondPass (orderId) {
|
||||
return request({
|
||||
url: api.repass.replace('{orderId}', orderId),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 待老师确认通过审核按钮
|
||||
export function teachermakesure (orderId) {
|
||||
return request({
|
||||
url: api.teachermakesure.replace('{orderId}', orderId),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 查看邮寄材料列表
|
||||
export function getExpressesList (orderId, parameter) {
|
||||
return request({
|
||||
url: api.getExpressesList.replace('{orderId}', orderId),
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 查看邮寄材料物流信息
|
||||
export function getLogistic (express) {
|
||||
return request({
|
||||
url: api.logistic.replace('{express}', express)
|
||||
})
|
||||
}
|
||||
|
||||
// 确认签收
|
||||
export function signInLogistic (orderId, express) {
|
||||
return request({
|
||||
url: api.signInLogistic.replace('{orderId}', orderId).replace('{express}', express),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 添加记录 itemid 有就是给机构添加的记录 没有就是给订单加的记录信息
|
||||
export function doLogs (orderId, parameter) {
|
||||
return request({
|
||||
url: api.doLogs.replace('{orderId}', orderId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 记录列表 itemid 代表查机构的记录列表 不带itemid 就是查全部的记录列表
|
||||
export function doLogsList (orderId, parameter) {
|
||||
return request({
|
||||
url: api.doLogsList.replace('{orderId}', orderId),
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 删除记录delLog
|
||||
export function delLog (orderId, logId) {
|
||||
return request({
|
||||
url: api.delLog.replace('{orderId}', orderId).replace('{logId}', logId),
|
||||
method: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取确认方案信息
|
||||
export function getSchemes (orderId, itemId) {
|
||||
return request({
|
||||
url: api.getSchemes.replace('{orderId}', orderId).replace('{itemId}', itemId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 修改机构名称(备注使用换了机构)
|
||||
export function institutionEdit (itemId, parameter) {
|
||||
return request({
|
||||
url: api.institutionEdit.replace('{itemId}', itemId),
|
||||
method: 'POST',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 提交确认方案
|
||||
export function addSchemes (orderId, itemId, parameter) {
|
||||
return request({
|
||||
url: api.getSchemes.replace('{orderId}', orderId).replace('{itemId}', itemId),
|
||||
method: 'post',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 修改机构金额
|
||||
export function changeBankCount (orderId, itemId, parameter) {
|
||||
return request({
|
||||
url: api.changeBankCount.replace('{orderId}', orderId).replace('{itemId}', itemId),
|
||||
method: 'PUT',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// 机构修改金额记录getChangeBankCount
|
||||
export function getChangeBankCountLog (orderId, itemId) {
|
||||
return request({
|
||||
url: api.getChangeBankCountLog.replace('{orderId}', orderId).replace('{itemId}', itemId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 获取订单数量
|
||||
export function getOrdersCount (parameter) {
|
||||
return request({
|
||||
url: api.getOrdersCount,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 获得所有机构信息
|
||||
export function getAllBanks (orderId) {
|
||||
return request({
|
||||
url: api.getAllBanks.replace('{orderId}', orderId),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
90
src/api/organization.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* @Author: Aimee~
|
||||
* @Date: 2023-05-11 12:02:45
|
||||
* @LastEditTime: 2023-06-27 13:10:40
|
||||
* @LastEditors: Aimee
|
||||
* @FilePath: /douhuo-agent/src/api/organization.js
|
||||
* @Description:
|
||||
*/
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
list: '/institutions', // 机构列表
|
||||
init: '/institutions/init', // 筛选前置
|
||||
info: '/institutions/{item}/show', // 机构详情接口
|
||||
changeStatus: '/institutions/{item}/status', // 修改机构状态
|
||||
service: 'institutions/{item}/service', // 修改服务包信息
|
||||
remark: 'institutions/{item}/remark', // 修改机构备注信息
|
||||
canExport: 'institutions/can_export', // 机构是否能导出
|
||||
changeStatusTwo: 'institutions/{item}/status_two' // 更改机构状态2
|
||||
}
|
||||
// 机构列表
|
||||
export function getList (parameter) {
|
||||
return request({
|
||||
url: api.list,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
// 筛选前置
|
||||
export function init () {
|
||||
return request({
|
||||
url: api.init
|
||||
})
|
||||
}
|
||||
|
||||
// 获取机构详情接口
|
||||
export function getOriganizationInfo (item) {
|
||||
return request({
|
||||
url: api.info.replace('{item}', item),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 修改结构状态
|
||||
export function changeStatus (item, params) {
|
||||
return request({
|
||||
url: api.changeStatus.replace('{item}', item),
|
||||
method: 'post',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
// 修改服务包信息
|
||||
export function editServiceInfo (item, params) {
|
||||
console.log(item, params)
|
||||
return request({
|
||||
url: api.service.replace('{item}', item),
|
||||
method: 'post',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
// 修改机构备注消息
|
||||
export function remark (item, params) {
|
||||
console.log(item, params)
|
||||
return request({
|
||||
url: api.remark.replace('{item}', item),
|
||||
method: 'post',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
// 机构列表是否能导出
|
||||
export function canExport (userid) {
|
||||
return request({
|
||||
url: api.canExport,
|
||||
method: 'get',
|
||||
params: {
|
||||
user_id: userid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更改机构状态2
|
||||
export function changeStatusTwo (item, params) {
|
||||
return request({
|
||||
url: api.changeStatusTwo.replace('{item}', item),
|
||||
method: 'post',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
113
src/api/promissions.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
staffCan: '/staff/can',
|
||||
staffDeparts: '/staff/departs',
|
||||
staffDepartsUser: '/staff/users',
|
||||
addPreDepartUser: '/staff/users/create',
|
||||
addDepartsUser: '/staff/users',
|
||||
editDepartsUser: '/staff/users/{staff_id}',
|
||||
delDepartsUser: '/staff/users/{staff_id}',
|
||||
getDepartsUser: '/staff/users',
|
||||
getDepartsOrder: '/staff/addresses',
|
||||
getDefaultUserInfo: '/staff/users/{staff_id}/edit'
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 判断是否能查看订单与权限
|
||||
*/
|
||||
export function staffCan () {
|
||||
return request({
|
||||
url: api.staffCan
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 用户组织架构
|
||||
*/
|
||||
export function staffDeparts () {
|
||||
return request({
|
||||
url: api.staffDeparts
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 我的组织列表
|
||||
*/
|
||||
export function staffDepartsUser () {
|
||||
return request({
|
||||
url: api.staffDepartsUser
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 组织下用户列表
|
||||
*/
|
||||
export function getDepartsUser (parameter) {
|
||||
return request({
|
||||
url: api.getDepartsUser,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @returns 组织下待指派订单列表
|
||||
*/
|
||||
export function getDepartsOrder (parameter) {
|
||||
return request({
|
||||
url: api.getDepartsOrder,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 我的用户新增前置获取下级身份
|
||||
*/
|
||||
export function addPreDepartUser (parameter) {
|
||||
return request({
|
||||
url: api.addPreDepartUser,
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 组织下增加用户操作
|
||||
*/
|
||||
export function addDepartsUser (parameter) {
|
||||
return request({
|
||||
url: api.addDepartsUser,
|
||||
method: 'POST',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 组织下修改用户操作
|
||||
*/
|
||||
export function editDepartsUser (staffId, parameter) {
|
||||
return request({
|
||||
url: api.editDepartsUser.replace('{staff_id}', staffId),
|
||||
method: 'PUT',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 组织下删除用户操作
|
||||
*/
|
||||
export function delDepartsUser (staffId) {
|
||||
return request({
|
||||
url: api.delDepartsUser.replace('{staff_id}', staffId),
|
||||
method: 'DELETE'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns 组织下用户修改前置
|
||||
*/
|
||||
export function getDefaultUserInfo (staffId) {
|
||||
return request({
|
||||
url: api.getDefaultUserInfo.replace('{staff_id}', staffId)
|
||||
})
|
||||
}
|
||||
15
src/api/statistical.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getStatistical () {
|
||||
return request({
|
||||
url: '/data/index',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getHomeUserInfo () {
|
||||
return request({
|
||||
url: '/data/user',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
25
src/api/storage.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
const api = {
|
||||
stsAuth: '/storage/sts',
|
||||
storageUpload: '/storage/upload',
|
||||
storageDownload: '/orders/exports', // 订单导出
|
||||
institutionsExports: '/institutions/exports' // 订单导出
|
||||
}
|
||||
|
||||
export function getStsAssumeRole () {
|
||||
return request({
|
||||
url: api.stsAuth,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getStorageUploadUrl () {
|
||||
return process.env.VUE_APP_API_BASE_URL + api.storageUpload
|
||||
}
|
||||
export function getStorageDownUrl () {
|
||||
return process.env.VUE_APP_API_BASE_URL + api.storageDownload
|
||||
}
|
||||
export function institutionsExports () {
|
||||
return process.env.VUE_APP_API_BASE_URL + api.institutionsExports
|
||||
}
|
||||
69
src/assets/background.svg
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 21</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
|
||||
<g id="Group-21" transform="translate(77.000000, 73.000000)">
|
||||
<g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
|
||||
<ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
|
||||
<ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
|
||||
<path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
|
||||
<path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
|
||||
<path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
|
||||
<g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
|
||||
<ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
|
||||
<path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
|
||||
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
|
||||
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
|
||||
<ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
|
||||
<ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
|
||||
<path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
|
||||
<g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
|
||||
<ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
|
||||
<path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
|
||||
</g>
|
||||
<ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
|
||||
<ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
|
||||
<ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
|
||||
<path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
|
||||
</g>
|
||||
<g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
|
||||
<ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
|
||||
<g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
|
||||
<ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
|
||||
<path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
|
||||
</g>
|
||||
<path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
|
||||
<ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
|
||||
<ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
|
||||
<path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
|
||||
</g>
|
||||
<g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
|
||||
<g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
|
||||
<circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
|
||||
<path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
|
||||
</g>
|
||||
<circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
|
||||
<path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||
<path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||
<polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
|
||||
<path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
|
||||
<path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
|
||||
<path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
|
||||
<circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
|
||||
<circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
|
||||
<circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
|
||||
<circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
|
||||
<circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.7 KiB |
1
src/assets/icons/bx-analyse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1551058675966" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7872" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M85.333333 512h85.333334a340.736 340.736 0 0 1 99.712-241.621333 337.493333 337.493333 0 0 1 108.458666-72.96 346.453333 346.453333 0 0 1 261.546667-1.749334A106.154667 106.154667 0 0 0 746.666667 298.666667C805.802667 298.666667 853.333333 251.136 853.333333 192S805.802667 85.333333 746.666667 85.333333c-29.397333 0-55.978667 11.776-75.221334 30.933334-103.722667-41.514667-222.848-40.874667-325.76 2.517333a423.594667 423.594667 0 0 0-135.68 91.264 423.253333 423.253333 0 0 0-91.306666 135.637333A426.88 426.88 0 0 0 85.333333 512z m741.248 133.205333c-17.109333 40.618667-41.685333 77.141333-72.96 108.416s-67.797333 55.850667-108.458666 72.96a346.453333 346.453333 0 0 1-261.546667 1.749334A106.154667 106.154667 0 0 0 277.333333 725.333333C218.197333 725.333333 170.666667 772.864 170.666667 832S218.197333 938.666667 277.333333 938.666667c29.397333 0 55.978667-11.776 75.221334-30.933334A425.173333 425.173333 0 0 0 512 938.666667a425.941333 425.941333 0 0 0 393.258667-260.352A426.325333 426.325333 0 0 0 938.666667 512h-85.333334a341.034667 341.034667 0 0 1-26.752 133.205333z" p-id="7873"></path><path d="M512 318.378667c-106.752 0-193.621333 86.869333-193.621333 193.621333S405.248 705.621333 512 705.621333s193.621333-86.869333 193.621333-193.621333S618.752 318.378667 512 318.378667z m0 301.909333c-59.690667 0-108.288-48.597333-108.288-108.288S452.309333 403.712 512 403.712s108.288 48.597333 108.288 108.288-48.597333 108.288-108.288 108.288z" p-id="7874"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/assets/images/team-1.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
src/assets/images/team-2.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
src/assets/images/team-3.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
src/assets/images/team-4.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
src/assets/images/team-5.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
src/assets/login_top.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/logo_bg.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
src/assets/logo_bg_1.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
src/assets/scan_top_bg.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
src/assets/平安.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
10697
src/components/AddressSelect/areadata.json
Normal file
57
src/components/AddressSelect/index.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<a-cascader
|
||||
:fieldNames="{ label: 'name', value: 'code', children: 'children' }"
|
||||
:options="areaData"
|
||||
:placeholder="placeholder"
|
||||
v-model="selectedValues"
|
||||
@change="onChange"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import areaData from './areadata'
|
||||
export default {
|
||||
name: 'AreaSelect',
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择省市区'
|
||||
},
|
||||
defaultValue: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 地区数据
|
||||
areaData,
|
||||
// 选择的数据
|
||||
selectedValues: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.defaultValue.length) {
|
||||
this.selectedValues = [...this.defaultValue]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultValue (newValue) {
|
||||
if (newValue.length) {
|
||||
this.selectedValues = newValue
|
||||
} else {
|
||||
this.selectedValues = []
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 选择好之后的回调
|
||||
onChange (value) {
|
||||
this.$emit('change', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
82
src/components/ArticleListContent/ArticleListContent.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="antd-pro-components-article-list-content-index-listContent">
|
||||
<div class="description">
|
||||
<slot>
|
||||
{{ description }}
|
||||
</slot>
|
||||
</div>
|
||||
<div class="extra">
|
||||
<a-avatar :src="avatar" size="small" />
|
||||
{{ owner }} 发布于
|
||||
<em>{{ updateAt | moment }}</em>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ArticleListContent',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'antd-pro-components-article-list-content-index-listContent'
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
owner: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
updateAt: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '../index.less';
|
||||
|
||||
.antd-pro-components-article-list-content-index-listContent {
|
||||
.description {
|
||||
max-width: 720px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.extra {
|
||||
margin-top: 16px;
|
||||
color: @text-color-secondary;
|
||||
line-height: 22px;
|
||||
|
||||
& /deep/ .ant-avatar {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
& > em {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-xs) {
|
||||
.antd-pro-components-article-list-content-index-listContent {
|
||||
.extra {
|
||||
& > em {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
3
src/components/ArticleListContent/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import ArticleListContent from './ArticleListContent'
|
||||
|
||||
export default ArticleListContent
|
||||
24
src/components/AvatarList/Item.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
import { Tooltip, Avatar } from 'ant-design-vue'
|
||||
import { getSlotOptions } from 'ant-design-vue/lib/_util/props-util'
|
||||
import { warning } from 'ant-design-vue/lib/vc-util/warning'
|
||||
|
||||
export const AvatarListItemProps = {
|
||||
tips: PropTypes.string.def(null),
|
||||
src: PropTypes.string.def('')
|
||||
}
|
||||
|
||||
const Item = {
|
||||
__ANT_AVATAR_CHILDREN: true,
|
||||
name: 'AvatarListItem',
|
||||
props: AvatarListItemProps,
|
||||
created () {
|
||||
warning(getSlotOptions(this.$parent).__ANT_AVATAR_LIST, 'AvatarListItem must be a subcomponent of AvatarList')
|
||||
},
|
||||
render () {
|
||||
const AvatarDom = <Avatar size={this.$parent.size} src={this.src} />
|
||||
return this.tips && <Tooltip title={this.tips}>{AvatarDom}</Tooltip> || <AvatarDom />
|
||||
}
|
||||
}
|
||||
|
||||
export default Item
|
||||
72
src/components/AvatarList/List.jsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import './index.less'
|
||||
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
import Avatar from 'ant-design-vue/es/avatar'
|
||||
import Item from './Item.jsx'
|
||||
import { filterEmpty } from '@/components/_util/util'
|
||||
|
||||
/**
|
||||
* size: `number`、 `large`、`small`、`default` 默认值: default
|
||||
* maxLength: number
|
||||
* excessItemsStyle: CSSProperties
|
||||
*/
|
||||
const AvatarListProps = {
|
||||
prefixCls: PropTypes.string.def('ant-pro-avatar-list'),
|
||||
size: {
|
||||
validator: val => {
|
||||
return typeof val === 'number' || ['small', 'large', 'default'].includes(val)
|
||||
},
|
||||
default: 'default'
|
||||
},
|
||||
maxLength: PropTypes.number.def(0),
|
||||
excessItemsStyle: PropTypes.object.def({
|
||||
color: '#f56a00',
|
||||
backgroundColor: '#fde3cf'
|
||||
})
|
||||
}
|
||||
|
||||
const AvatarList = {
|
||||
__ANT_AVATAR_LIST: true,
|
||||
Item,
|
||||
name: 'AvatarList',
|
||||
props: AvatarListProps,
|
||||
render (h) {
|
||||
const { prefixCls, size } = this.$props
|
||||
const className = {
|
||||
[`${prefixCls}`]: true,
|
||||
[`${size}`]: true
|
||||
}
|
||||
const items = filterEmpty(this.$slots.default)
|
||||
const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{this.getItems(items)}</ul> : null
|
||||
|
||||
return (
|
||||
<div class={className}>
|
||||
{itemsDom}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
getItems (items) {
|
||||
const className = {
|
||||
[`${this.prefixCls}-item`]: true,
|
||||
[`${this.size}`]: true
|
||||
}
|
||||
const totalSize = items.length
|
||||
|
||||
if (this.maxLength > 0) {
|
||||
items = items.slice(0, this.maxLength)
|
||||
items.push((<Avatar size={this.size} style={this.excessItemsStyle}>{`+${totalSize - this.maxLength}`}</Avatar>))
|
||||
}
|
||||
return items.map((item) => (
|
||||
<li class={className}>{item}</li>
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvatarList.install = function (Vue) {
|
||||
Vue.component(AvatarList.name, AvatarList)
|
||||
Vue.component(AvatarList.Item.name, AvatarList.Item)
|
||||
}
|
||||
|
||||
export default AvatarList
|
||||
9
src/components/AvatarList/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import AvatarList from './List'
|
||||
import Item from './Item'
|
||||
|
||||
export {
|
||||
AvatarList,
|
||||
Item as AvatarListItem
|
||||
}
|
||||
|
||||
export default AvatarList
|
||||
60
src/components/AvatarList/index.less
Normal file
@@ -0,0 +1,60 @@
|
||||
@import "../index";
|
||||
|
||||
@avatar-list-prefix-cls: ~"@{ant-pro-prefix}-avatar-list";
|
||||
@avatar-list-item-prefix-cls: ~"@{ant-pro-prefix}-avatar-list-item";
|
||||
|
||||
.@{avatar-list-prefix-cls} {
|
||||
display: inline-block;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0 0 0 8px;
|
||||
font-size: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.@{avatar-list-item-prefix-cls} {
|
||||
display: inline-block;
|
||||
font-size: @font-size-base;
|
||||
margin-left: -8px;
|
||||
width: @avatar-size-base;
|
||||
height: @avatar-size-base;
|
||||
|
||||
:global {
|
||||
.ant-avatar {
|
||||
border: 1px solid #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.large {
|
||||
width: @avatar-size-lg;
|
||||
height: @avatar-size-lg;
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: @avatar-size-sm;
|
||||
height: @avatar-size-sm;
|
||||
}
|
||||
|
||||
&.mini {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
:global {
|
||||
.ant-avatar {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
|
||||
.ant-avatar-string {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
64
src/components/AvatarList/index.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# AvatarList 用户头像列表
|
||||
|
||||
|
||||
一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。
|
||||
|
||||
|
||||
|
||||
引用方式:
|
||||
|
||||
```javascript
|
||||
import AvatarList from '@/components/AvatarList'
|
||||
const AvatarListItem = AvatarList.Item
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AvatarList,
|
||||
AvatarListItem
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 代码演示 [demo](https://pro.loacg.com/test/home)
|
||||
|
||||
```html
|
||||
<avatar-list size="mini">
|
||||
<avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
|
||||
<avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
</avatar-list>
|
||||
```
|
||||
或
|
||||
```html
|
||||
<avatar-list :max-length="3">
|
||||
<avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
|
||||
<avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
|
||||
</avatar-list>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### AvatarList
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ---------------- | -------- | ---------------------------------- | --------- |
|
||||
| size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` |
|
||||
| maxLength | 要显示的最大项目 | number | - |
|
||||
| excessItemsStyle | 多余的项目风格 | CSSProperties | - |
|
||||
|
||||
### AvatarList.Item
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ---- | ------ | --------- | --- |
|
||||
| tips | 头像展示文案 | string | - |
|
||||
| src | 头像图片连接 | string | - |
|
||||
|
||||
62
src/components/Charts/Bar.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div :style="{ padding: '0 0 32px 32px' }">
|
||||
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
||||
<v-chart
|
||||
height="254"
|
||||
:data="data"
|
||||
:forceFit="true"
|
||||
:padding="['auto', 'auto', '40', '50']">
|
||||
<v-tooltip />
|
||||
<v-axis />
|
||||
<v-bar position="x*y"/>
|
||||
</v-chart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Bar',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
scale: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [{
|
||||
dataKey: 'x',
|
||||
min: 2
|
||||
}, {
|
||||
dataKey: 'y',
|
||||
title: '时间',
|
||||
min: 1,
|
||||
max: 22
|
||||
}]
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [
|
||||
'x*y',
|
||||
(x, y) => ({
|
||||
name: x,
|
||||
value: y
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
120
src/components/Charts/ChartCard.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
|
||||
<div class="chart-card-header">
|
||||
<div class="meta">
|
||||
<span class="chart-card-title">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
</slot>
|
||||
</span>
|
||||
<span class="chart-card-action">
|
||||
<slot name="action"></slot>
|
||||
</span>
|
||||
</div>
|
||||
<div class="total">
|
||||
<slot name="total">
|
||||
<span>{{ typeof total === 'function' && total() || total }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-card-content">
|
||||
<div class="content-fix">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-card-footer">
|
||||
<div class="field">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ChartCard',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
total: {
|
||||
type: [Function, Number, String],
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-card-header {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
.meta {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
color: rgba(0, 0, 0, .45);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card-action {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.chart-card-footer {
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding-top: 9px;
|
||||
margin-top: 8px;
|
||||
|
||||
> * {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.field {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card-content {
|
||||
margin-bottom: 12px;
|
||||
position: relative;
|
||||
height: 46px;
|
||||
width: 100%;
|
||||
|
||||
.content-fix {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.total {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
color: #000;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 0;
|
||||
font-size: 30px;
|
||||
line-height: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
67
src/components/Charts/Liquid.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-chart
|
||||
:forceFit="true"
|
||||
:height="height"
|
||||
:width="width"
|
||||
:data="data"
|
||||
:scale="scale"
|
||||
:padding="0">
|
||||
<v-tooltip />
|
||||
<v-interval
|
||||
:shape="['liquid-fill-gauge']"
|
||||
position="transfer*value"
|
||||
color=""
|
||||
:v-style="{
|
||||
lineWidth: 10,
|
||||
opacity: 0.75
|
||||
}"
|
||||
:tooltip="[
|
||||
'transfer*value',
|
||||
(transfer, value) => {
|
||||
return {
|
||||
name: transfer,
|
||||
value,
|
||||
};
|
||||
},
|
||||
]"
|
||||
></v-interval>
|
||||
<v-guide
|
||||
v-for="(row, index) in data"
|
||||
:key="index"
|
||||
type="text"
|
||||
:top="true"
|
||||
:position="{
|
||||
gender: row.transfer,
|
||||
value: 45
|
||||
}"
|
||||
:content="row.value + '%'"
|
||||
:v-style="{
|
||||
fontSize: 100,
|
||||
textAlign: 'center',
|
||||
opacity: 0.75,
|
||||
}"
|
||||
/>
|
||||
</v-chart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Liquid',
|
||||
props: {
|
||||
height: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
64
src/components/Charts/MiniArea.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="antv-chart-mini">
|
||||
<div class="chart-wrapper" :style="{ height: 46 }">
|
||||
<v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 0, 18, 0]">
|
||||
<v-tooltip />
|
||||
<v-smooth-area position="x*y" />
|
||||
</v-chart>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import moment from 'moment'
|
||||
// const data = []
|
||||
// const beginDay = new Date().getTime()
|
||||
|
||||
// for (let i = 0; i < 10; i++) {
|
||||
// data.push({
|
||||
// x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
||||
// y: Math.round(Math.random() * 10)
|
||||
// })
|
||||
// }
|
||||
|
||||
const tooltip = [
|
||||
'x*y',
|
||||
(x, y) => ({
|
||||
name: x,
|
||||
value: y
|
||||
})
|
||||
]
|
||||
const scale = [{
|
||||
dataKey: 'x',
|
||||
min: 2
|
||||
}, {
|
||||
dataKey: 'y',
|
||||
title: '时间',
|
||||
min: 1,
|
||||
max: 22
|
||||
}]
|
||||
|
||||
export default {
|
||||
name: 'MiniArea',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// data,
|
||||
tooltip,
|
||||
scale,
|
||||
height: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "chart";
|
||||
</style>
|
||||
64
src/components/Charts/MiniBar.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="antv-chart-mini">
|
||||
<div class="chart-wrapper" :style="{ height: 46 }">
|
||||
<v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 5, 18, 5]">
|
||||
<v-tooltip />
|
||||
<v-bar position="x*y" />
|
||||
</v-chart>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import moment from 'moment'
|
||||
// const data = []
|
||||
// const beginDay = new Date().getTime()
|
||||
|
||||
// for (let i = 0; i < 10; i++) {
|
||||
// data.push({
|
||||
// x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
|
||||
// y: Math.round(Math.random() * 10)
|
||||
// })
|
||||
// }
|
||||
|
||||
const tooltip = [
|
||||
'x*y',
|
||||
(x, y) => ({
|
||||
name: x,
|
||||
value: y
|
||||
})
|
||||
]
|
||||
|
||||
const scale = [{
|
||||
dataKey: 'x',
|
||||
min: 2
|
||||
}, {
|
||||
dataKey: 'y',
|
||||
title: '时间',
|
||||
min: 1,
|
||||
max: 30
|
||||
}]
|
||||
|
||||
export default {
|
||||
name: 'MiniBar',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tooltip,
|
||||
scale,
|
||||
height: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "chart";
|
||||
</style>
|
||||
75
src/components/Charts/MiniProgress.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div class="chart-mini-progress">
|
||||
<div class="target" :style="{ left: target + '%'}">
|
||||
<span :style="{ backgroundColor: color }" />
|
||||
<span :style="{ backgroundColor: color }"/>
|
||||
</div>
|
||||
<div class="progress-wrapper">
|
||||
<div class="progress" :style="{ backgroundColor: color, width: percentage + '%', height: height }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MiniProgress',
|
||||
props: {
|
||||
target: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '10px'
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#13C2C2'
|
||||
},
|
||||
percentage: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-mini-progress {
|
||||
padding: 5px 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.target {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
span {
|
||||
border-radius: 100px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 4px;
|
||||
width: 2px;
|
||||
|
||||
&:last-child {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.progress-wrapper {
|
||||
background-color: #f5f5f5;
|
||||
position: relative;
|
||||
|
||||
.progress {
|
||||
transition: all .4s cubic-bezier(.08,.82,.17,1) 0s;
|
||||
border-radius: 1px 0 0 1px;
|
||||
background-color: #1890ff;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
40
src/components/Charts/MiniSmoothArea.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="chart-wrapper" :style="{ height: 46 }">
|
||||
<v-chart :force-fit="true" :height="100" :data="dataSource" :scale="scale" :padding="[36, 0, 18, 0]">
|
||||
<v-tooltip />
|
||||
<v-smooth-line position="x*y" :size="2" />
|
||||
<v-smooth-area position="x*y" />
|
||||
</v-chart>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MiniSmoothArea',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-smooth-area'
|
||||
},
|
||||
scale: {
|
||||
type: [Object, Array],
|
||||
required: true
|
||||
},
|
||||
dataSource: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
height: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "smooth.area.less";
|
||||
</style>
|
||||
68
src/components/Charts/Radar.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<v-chart :forceFit="true" height="400" :data="data" :padding="[20, 20, 95, 20]" :scale="scale">
|
||||
<v-tooltip></v-tooltip>
|
||||
<v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
|
||||
<v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
|
||||
<v-legend dataKey="user" marker="circle" :offset="30" />
|
||||
<v-coord type="polar" radius="0.8" />
|
||||
<v-line position="item*score" color="user" :size="2" />
|
||||
<v-point position="item*score" color="user" :size="4" shape="circle" />
|
||||
</v-chart>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const axis1Opts = {
|
||||
dataKey: 'item',
|
||||
line: null,
|
||||
tickLine: null,
|
||||
grid: {
|
||||
lineStyle: {
|
||||
lineDash: null
|
||||
},
|
||||
hideFirstLine: false
|
||||
}
|
||||
}
|
||||
const axis2Opts = {
|
||||
dataKey: 'score',
|
||||
line: null,
|
||||
tickLine: null,
|
||||
grid: {
|
||||
type: 'polygon',
|
||||
lineStyle: {
|
||||
lineDash: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const scale = [
|
||||
{
|
||||
dataKey: 'score',
|
||||
min: 0,
|
||||
max: 80
|
||||
}, {
|
||||
dataKey: 'user',
|
||||
alias: '类型'
|
||||
}
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'Radar',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
axis1Opts,
|
||||
axis2Opts,
|
||||
scale
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
77
src/components/Charts/RankList.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="rank">
|
||||
<h4 class="title">{{ title }}</h4>
|
||||
<ul class="list">
|
||||
<li :key="index" v-for="(item, index) in list">
|
||||
<span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
|
||||
<span>{{ item.name }}</span>
|
||||
<span>{{ item.total }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RankList',
|
||||
// ['title', 'list']
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.rank {
|
||||
padding: 0 32px 32px 72px;
|
||||
|
||||
.list {
|
||||
margin: 25px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
margin-top: 16px;
|
||||
|
||||
span {
|
||||
color: rgba(0, 0, 0, .65);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
&:first-child {
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 20px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-right: 24px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
&.active {
|
||||
background-color: #314659;
|
||||
color: #fff;
|
||||
}
|
||||
&:last-child {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile .rank {
|
||||
padding: 0 32px 32px 32px;
|
||||
}
|
||||
|
||||
</style>
|
||||
113
src/components/Charts/TagCloud.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<v-chart :width="width" :height="height" :padding="[0]" :data="data" :scale="scale">
|
||||
<v-tooltip :show-title="false" />
|
||||
<v-coord type="rect" direction="TL" />
|
||||
<v-point position="x*y" color="category" shape="cloud" tooltip="value*category" />
|
||||
</v-chart>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { registerShape } from 'viser-vue'
|
||||
const DataSet = require('@antv/data-set')
|
||||
|
||||
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'
|
||||
|
||||
const scale = [
|
||||
{ dataKey: 'x', nice: false },
|
||||
{ dataKey: 'y', nice: false }
|
||||
]
|
||||
|
||||
registerShape('point', 'cloud', {
|
||||
draw (cfg, container) {
|
||||
return container.addShape('text', {
|
||||
attrs: {
|
||||
fillOpacity: cfg.opacity,
|
||||
fontSize: cfg.origin._origin.size,
|
||||
rotate: cfg.origin._origin.rotate,
|
||||
text: cfg.origin._origin.text,
|
||||
textAlign: 'center',
|
||||
fontFamily: cfg.origin._origin.font,
|
||||
fill: cfg.color,
|
||||
textBaseline: 'Alphabetic',
|
||||
...cfg.style,
|
||||
x: cfg.x,
|
||||
y: cfg.y
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'TagCloud',
|
||||
props: {
|
||||
tagList: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 400
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 640
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: [],
|
||||
scale
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tagList: function (val) {
|
||||
if (val.length > 0) {
|
||||
this.initTagCloud(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.tagList.length > 0) {
|
||||
this.initTagCloud(this.tagList)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTagCloud (dataSource) {
|
||||
const { height, width } = this
|
||||
|
||||
const dv = new DataSet.View().source(dataSource)
|
||||
const range = dv.range('value')
|
||||
const min = range[0]
|
||||
const max = range[1]
|
||||
const imageMask = new Image()
|
||||
imageMask.crossOrigin = ''
|
||||
imageMask.src = imgUrl
|
||||
imageMask.onload = () => {
|
||||
dv.transform({
|
||||
type: 'tag-cloud',
|
||||
fields: ['name', 'value'],
|
||||
size: [width, height],
|
||||
imageMask,
|
||||
font: 'Verdana',
|
||||
padding: 0,
|
||||
timeInterval: 5000, // max execute time
|
||||
rotate () {
|
||||
let random = ~~(Math.random() * 4) % 4
|
||||
if (random === 2) {
|
||||
random = 0
|
||||
}
|
||||
return random * 90 // 0, 90, 270
|
||||
},
|
||||
fontSize (d) {
|
||||
if (d.value) {
|
||||
return ((d.value - min) / (max - min)) * (32 - 8) + 8
|
||||
}
|
||||
return 0
|
||||
}
|
||||
})
|
||||
this.data = dv.rows
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
64
src/components/Charts/TransferBar.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div :style="{ padding: '0 0 32px 32px' }">
|
||||
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
|
||||
<v-chart
|
||||
height="254"
|
||||
:data="data"
|
||||
:scale="scale"
|
||||
:forceFit="true"
|
||||
:padding="['auto', 'auto', '40', '50']">
|
||||
<v-tooltip />
|
||||
<v-axis />
|
||||
<v-bar position="x*y"/>
|
||||
</v-chart>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const tooltip = [
|
||||
'x*y',
|
||||
(x, y) => ({
|
||||
name: x,
|
||||
value: y
|
||||
})
|
||||
]
|
||||
const scale = [{
|
||||
dataKey: 'x',
|
||||
title: '日期(天)',
|
||||
alias: '日期(天)',
|
||||
min: 2
|
||||
}, {
|
||||
dataKey: 'y',
|
||||
title: '流量(Gb)',
|
||||
alias: '流量(Gb)',
|
||||
min: 1
|
||||
}]
|
||||
|
||||
export default {
|
||||
name: 'Bar',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: [],
|
||||
scale,
|
||||
tooltip
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getMonthBar()
|
||||
},
|
||||
methods: {
|
||||
getMonthBar () {
|
||||
this.$http.get('/analysis/month-bar')
|
||||
.then(res => {
|
||||
this.data = res.result
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
82
src/components/Charts/Trend.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="chart-trend">
|
||||
{{ term }}
|
||||
<span>{{ rate }}%</span>
|
||||
<span :class="['trend-icon', trend]"><a-icon :type="'caret-' + trend"/></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Trend',
|
||||
props: {
|
||||
term: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
percentage: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
type: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
},
|
||||
target: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
fixed: {
|
||||
type: Number,
|
||||
default: 2
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
trend: this.type && 'up' || 'down',
|
||||
rate: this.percentage
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const type = this.type === null ? this.value >= this.target : this.type
|
||||
this.trend = type ? 'up' : 'down'
|
||||
this.rate = (this.percentage === null ? Math.abs(this.value - this.target) * 100 / this.target : this.percentage).toFixed(this.fixed)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-trend {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
.trend-icon {
|
||||
font-size: 12px;
|
||||
|
||||
&.up, &.down {
|
||||
margin-left: 4px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
transform: scale(.83);
|
||||
}
|
||||
}
|
||||
|
||||
&.up {
|
||||
color: #f5222d;
|
||||
}
|
||||
&.down {
|
||||
color: #52c41a;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
src/components/Charts/chart.less
Normal file
@@ -0,0 +1,13 @@
|
||||
.antv-chart-mini {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.chart-wrapper {
|
||||
position: absolute;
|
||||
bottom: -28px;
|
||||
width: 100%;
|
||||
|
||||
/* margin: 0 -5px;
|
||||
overflow: hidden; */
|
||||
}
|
||||
}
|
||||
14
src/components/Charts/smooth.area.less
Normal file
@@ -0,0 +1,14 @@
|
||||
@import '../index';
|
||||
|
||||
@smoothArea-prefix-cls: ~"@{ant-pro-prefix}-smooth-area";
|
||||
|
||||
.@{smoothArea-prefix-cls} {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.chart-wrapper {
|
||||
position: absolute;
|
||||
bottom: -28px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
113
src/components/Dialog.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import Modal from 'ant-design-vue/es/modal'
|
||||
export default (Vue) => {
|
||||
function dialog (component, componentProps, modalProps) {
|
||||
const _vm = this
|
||||
modalProps = modalProps || {}
|
||||
if (!_vm || !_vm._isVue) {
|
||||
return
|
||||
}
|
||||
let dialogDiv = document.querySelector('body>div[type=dialog]')
|
||||
if (!dialogDiv) {
|
||||
dialogDiv = document.createElement('div')
|
||||
dialogDiv.setAttribute('type', 'dialog')
|
||||
document.body.appendChild(dialogDiv)
|
||||
}
|
||||
|
||||
const handle = function (checkFunction, afterHandel) {
|
||||
if (checkFunction instanceof Function) {
|
||||
const res = checkFunction()
|
||||
if (res instanceof Promise) {
|
||||
res.then(c => {
|
||||
c && afterHandel()
|
||||
})
|
||||
} else {
|
||||
res && afterHandel()
|
||||
}
|
||||
} else {
|
||||
// checkFunction && afterHandel()
|
||||
checkFunction || afterHandel()
|
||||
}
|
||||
}
|
||||
|
||||
const dialogInstance = new Vue({
|
||||
data () {
|
||||
return {
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
router: _vm.$router,
|
||||
store: _vm.$store,
|
||||
mounted () {
|
||||
this.$on('close', (v) => {
|
||||
this.handleClose()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleClose () {
|
||||
handle(this.$refs._component.onCancel, () => {
|
||||
this.visible = false
|
||||
this.$refs._component.$emit('close')
|
||||
this.$refs._component.$emit('cancel')
|
||||
dialogInstance.$destroy()
|
||||
})
|
||||
},
|
||||
handleOk () {
|
||||
handle(this.$refs._component.onOK || this.$refs._component.onOk, () => {
|
||||
this.visible = false
|
||||
this.$refs._component.$emit('close')
|
||||
this.$refs._component.$emit('ok')
|
||||
dialogInstance.$destroy()
|
||||
})
|
||||
}
|
||||
},
|
||||
render: function (h) {
|
||||
const that = this
|
||||
const modalModel = modalProps && modalProps.model
|
||||
if (modalModel) {
|
||||
delete modalProps.model
|
||||
}
|
||||
const ModalProps = Object.assign({}, modalModel && { model: modalModel } || {}, {
|
||||
attrs: Object.assign({}, {
|
||||
...(modalProps.attrs || modalProps)
|
||||
}, {
|
||||
visible: this.visible
|
||||
}),
|
||||
on: Object.assign({}, {
|
||||
...(modalProps.on || modalProps)
|
||||
}, {
|
||||
ok: () => {
|
||||
that.handleOk()
|
||||
},
|
||||
cancel: () => {
|
||||
that.handleClose()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const componentModel = componentProps && componentProps.model
|
||||
if (componentModel) {
|
||||
delete componentProps.model
|
||||
}
|
||||
const ComponentProps = Object.assign({}, componentModel && { model: componentModel } || {}, {
|
||||
ref: '_component',
|
||||
attrs: Object.assign({}, {
|
||||
...((componentProps && componentProps.attrs) || componentProps)
|
||||
}),
|
||||
on: Object.assign({}, {
|
||||
...((componentProps && componentProps.on) || componentProps)
|
||||
})
|
||||
})
|
||||
|
||||
return h(Modal, ModalProps, [h(component, ComponentProps)])
|
||||
}
|
||||
}).$mount(dialogDiv)
|
||||
}
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$dialog', {
|
||||
get: () => {
|
||||
return function () {
|
||||
dialog.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
334
src/components/DragVerify/DragVerify.vue
Normal file
@@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<div
|
||||
ref="dragVerify"
|
||||
:style="dragVerifyStyle"
|
||||
class="drag_verify"
|
||||
@mouseleave="dragFinish"
|
||||
@mousemove="dragMoving"
|
||||
@mouseup="dragFinish"
|
||||
@touchend="dragFinish"
|
||||
@touchmove="dragMoving"
|
||||
>
|
||||
|
||||
<div
|
||||
ref="progressBar"
|
||||
:class="{goFirst2:isOk}"
|
||||
:style="progressBarStyle"
|
||||
class="dv_progress_bar"
|
||||
>
|
||||
|
||||
</div>
|
||||
<div
|
||||
ref="message"
|
||||
:style="textStyle"
|
||||
class="dv_text"
|
||||
>
|
||||
<slot
|
||||
v-if="$slots.textBefore"
|
||||
name="textBefore"
|
||||
></slot>
|
||||
{{ message }}
|
||||
<slot
|
||||
v-if="$slots.textAfter"
|
||||
name="textAfter"
|
||||
></slot>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref="handler"
|
||||
:class="{goFirst:isOk}"
|
||||
:style="handlerStyle"
|
||||
class="dv_handler dv_handler_bg"
|
||||
@mousedown="dragStart"
|
||||
@touchstart="dragStart"
|
||||
>
|
||||
<a-icon type="double-right" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DragVerify',
|
||||
props: {
|
||||
isPassing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 250
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: 'swiping to the right side'
|
||||
},
|
||||
successText: {
|
||||
type: String,
|
||||
default: 'success'
|
||||
},
|
||||
background: {
|
||||
type: String,
|
||||
default: '#eee'
|
||||
},
|
||||
progressBarBg: {
|
||||
type: String,
|
||||
default: '#76c61d'
|
||||
},
|
||||
completedBg: {
|
||||
type: String,
|
||||
default: '#76c61d'
|
||||
},
|
||||
circle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
radius: {
|
||||
type: String,
|
||||
default: '4px'
|
||||
},
|
||||
handlerIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
successIcon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
handlerBg: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
textSize: {
|
||||
type: String,
|
||||
default: '14px'
|
||||
},
|
||||
textColor: {
|
||||
type: String,
|
||||
default: '#333'
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
const dragEl = this.$refs.dragVerify
|
||||
dragEl.style.setProperty('--textColor', this.textColor)
|
||||
dragEl.style.setProperty('--width', Math.floor(this.width / 2) + 'px')
|
||||
dragEl.style.setProperty('--pwidth', -Math.floor(this.width / 2) + 'px')
|
||||
},
|
||||
computed: {
|
||||
handlerStyle: function () {
|
||||
return {
|
||||
left: '0px',
|
||||
width: this.height + 'px',
|
||||
height: this.height + 'px',
|
||||
background: this.handlerBg
|
||||
}
|
||||
},
|
||||
message: function () {
|
||||
return this.isPassing ? this.successText : this.text
|
||||
},
|
||||
dragVerifyStyle: function () {
|
||||
return {
|
||||
width: this.width + 'px',
|
||||
height: this.height + 'px',
|
||||
lineHeight: this.height + 'px',
|
||||
background: this.background,
|
||||
borderRadius: this.circle ? this.height / 2 + 'px' : this.radius
|
||||
}
|
||||
},
|
||||
progressBarStyle: function () {
|
||||
return {
|
||||
background: this.progressBarBg,
|
||||
height: this.height + 'px',
|
||||
borderRadius: this.circle
|
||||
? this.height / 2 + 'px 0 0 ' + this.height / 2 + 'px'
|
||||
: this.radius
|
||||
}
|
||||
},
|
||||
textStyle: function () {
|
||||
return {
|
||||
height: this.height + 'px',
|
||||
width: this.width + 'px',
|
||||
fontSize: this.textSize
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isMoving: false,
|
||||
x: 0,
|
||||
isOk: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dragStart: function (e) {
|
||||
if (!this.isPassing) {
|
||||
this.isMoving = true
|
||||
var handler = this.$refs.handler
|
||||
this.x =
|
||||
(e.pageX || e.touches[0].pageX) -
|
||||
parseInt(handler.style.left.replace('px', ''), 10)
|
||||
}
|
||||
this.$emit('handlerMove')
|
||||
},
|
||||
dragMoving: function (e) {
|
||||
if (this.isMoving && !this.isPassing) {
|
||||
var _x = (e.pageX || e.touches[0].pageX) - this.x
|
||||
var handler = this.$refs.handler
|
||||
if (_x > 0 && _x <= this.width - this.height) {
|
||||
handler.style.left = _x + 'px'
|
||||
this.$refs.progressBar.style.width = _x + this.height / 2 + 'px'
|
||||
} else if (_x > this.width - this.height) {
|
||||
handler.style.left = this.width - this.height + 'px'
|
||||
this.$refs.progressBar.style.width =
|
||||
this.width - this.height / 2 + 'px'
|
||||
this.passVerify()
|
||||
}
|
||||
}
|
||||
},
|
||||
dragFinish: function (e) {
|
||||
if (this.isMoving && !this.isPassing) {
|
||||
var _x = (e.pageX || e.changedTouches[0].pageX) - this.x
|
||||
if (_x < this.width - this.height) {
|
||||
this.isOk = true
|
||||
var that = this
|
||||
setTimeout(function () {
|
||||
that.$refs.handler.style.left = '0'
|
||||
that.$refs.progressBar.style.width = '0'
|
||||
that.isOk = false
|
||||
}, 500)
|
||||
this.$emit('passfail')
|
||||
} else {
|
||||
var handler = this.$refs.handler
|
||||
handler.style.left = this.width - this.height + 'px'
|
||||
this.$refs.progressBar.style.width =
|
||||
this.width - this.height / 2 + 'px'
|
||||
this.passVerify()
|
||||
}
|
||||
this.isMoving = false
|
||||
}
|
||||
},
|
||||
passVerify: function () {
|
||||
this.$emit('update:isPassing', true)
|
||||
this.isMoving = false
|
||||
var handler = this.$refs.handler
|
||||
handler.children[0].className = this.successIcon
|
||||
this.$refs.progressBar.style.background = this.completedBg
|
||||
this.$refs.message.style['-webkit-text-fill-color'] = 'unset'
|
||||
this.$refs.message.style.animation = 'slidetounlock2 3s infinite'
|
||||
this.$refs.message.style.color = '#fff'
|
||||
this.$emit('passCallback')
|
||||
},
|
||||
reset: function () {
|
||||
const oriData = this.$options.data()
|
||||
for (const key in oriData) {
|
||||
if (Object.prototype.hasOwnProperty.call(oriData, key)) {
|
||||
this.$set(this, key, oriData[key])
|
||||
}
|
||||
}
|
||||
var handler = this.$refs.handler
|
||||
var message = this.$refs.message
|
||||
handler.style.left = '0'
|
||||
this.$refs.progressBar.style.width = '0'
|
||||
handler.children[0].className = this.handlerIcon
|
||||
message.style['-webkit-text-fill-color'] = 'transparent'
|
||||
message.style.animation = 'slidetounlock 3s infinite'
|
||||
message.style.color = this.background
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.drag_verify {
|
||||
position: relative;
|
||||
background-color: #e8e8e8;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.drag_verify .dv_handler {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.drag_verify .dv_handler i {
|
||||
color: #666;
|
||||
padding-left: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.drag_verify .dv_handler .el-icon-circle-check {
|
||||
color: #6c6;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
.drag_verify .dv_progress_bar {
|
||||
position: absolute;
|
||||
height: 34px;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.drag_verify .dv_text {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
color: transparent;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-o-user-select: none;
|
||||
-ms-user-select: none;
|
||||
background: -webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
right top,
|
||||
color-stop(0, var(--textColor)),
|
||||
color-stop(0.4, var(--textColor)),
|
||||
color-stop(0.5, #fff),
|
||||
color-stop(0.6, var(--textColor)),
|
||||
color-stop(1, var(--textColor))
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-text-size-adjust: none;
|
||||
animation: slidetounlock 3s infinite;
|
||||
}
|
||||
|
||||
.drag_verify .dv_text * {
|
||||
-webkit-text-fill-color: var(--textColor);
|
||||
}
|
||||
|
||||
.goFirst {
|
||||
left: 0px !important;
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.goFirst2 {
|
||||
width: 0px !important;
|
||||
transition: width 0.5s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes slidetounlock {
|
||||
0% {
|
||||
background-position: var(--pwidth) 0;
|
||||
}
|
||||
100% {
|
||||
background-position: var(--width) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes slidetounlock2 {
|
||||
0% {
|
||||
background-position: var(--pwidth) 0;
|
||||
}
|
||||
100% {
|
||||
background-position: var(--pwidth) 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
83
src/components/Editor/QuillEditor.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<quill-editor
|
||||
v-model="content"
|
||||
ref="myQuillEditor"
|
||||
:options="editorOption"
|
||||
@blur="onEditorBlur($event)"
|
||||
@focus="onEditorFocus($event)"
|
||||
@ready="onEditorReady($event)"
|
||||
@change="onEditorChange($event)">
|
||||
</quill-editor>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
|
||||
export default {
|
||||
name: 'QuillEditor',
|
||||
components: {
|
||||
quillEditor
|
||||
},
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-editor-quill'
|
||||
},
|
||||
// 表单校验用字段
|
||||
// eslint-disable-next-line
|
||||
value: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
content: null,
|
||||
editorOption: {
|
||||
// some quill options
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onEditorBlur (quill) {
|
||||
// console.log('editor blur!', quill)
|
||||
},
|
||||
onEditorFocus (quill) {
|
||||
// console.log('editor focus!', quill)
|
||||
},
|
||||
onEditorReady (quill) {
|
||||
// console.log('editor ready!', quill)
|
||||
},
|
||||
onEditorChange ({ quill, html, text }) {
|
||||
// console.log('editor change!', quill, html, text)
|
||||
this.$emit('change', html)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (val) {
|
||||
this.content = val
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import url('../index.less');
|
||||
|
||||
/* 覆盖 quill 默认边框圆角为 ant 默认圆角,用于统一 ant 组件风格 */
|
||||
.ant-editor-quill {
|
||||
line-height: initial;
|
||||
/deep/ .ql-toolbar.ql-snow {
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
/deep/ .ql-container.ql-snow {
|
||||
border-radius: 0 0 @border-radius-base @border-radius-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
148
src/components/Editor/WangEditor.vue
Normal file
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<a-spin :spinning="spinning">
|
||||
<div ref="editor" class="editor-wrapper"></div>
|
||||
<a-progress
|
||||
v-if="spinning && percent > 0"
|
||||
:stroke-color="{
|
||||
'0%': '#108ee9',
|
||||
'100%': '#87d068',
|
||||
}"
|
||||
:percent="percent"
|
||||
/>
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WEditor from 'wangeditor'
|
||||
import { getStsAssumeRole } from '@/api/storage'
|
||||
import moment from 'moment'
|
||||
|
||||
const OSS = require('ali-oss')
|
||||
const md5 = require('md5')
|
||||
|
||||
export default {
|
||||
name: 'WangEditor',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-editor-wang'
|
||||
},
|
||||
// eslint-disable-next-line
|
||||
value: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null,
|
||||
editorContent: null,
|
||||
store: null,
|
||||
spinning: false,
|
||||
percent: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (val) {
|
||||
this.editorContent = val
|
||||
this.editor.txt.html(val)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initEditor()
|
||||
getStsAssumeRole().then(res => {
|
||||
this.store = new OSS(res)
|
||||
}).catch(() => {
|
||||
this.$message.error('OSS 初始化失败,图片无法上传')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
computeFileMd5 (file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader()
|
||||
fileReader.readAsArrayBuffer(file)
|
||||
|
||||
fileReader.onload = (e) => {
|
||||
resolve(md5(new Uint8Array(e.target.result)))
|
||||
}
|
||||
|
||||
fileReader.onerror = (e) => {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
initEditor () {
|
||||
this.editor = new WEditor(this.$refs.editor)
|
||||
// this.editor.onchangeTimeout = 200
|
||||
this.editor.config.onchange = (html) => {
|
||||
this.editorContent = html
|
||||
this.$emit('change', this.editorContent)
|
||||
}
|
||||
this.editor.config.zIndex = 500
|
||||
this.editor.config.pasteIgnoreImg = true
|
||||
this.editor.config.pasteFilterStyle = true
|
||||
this.editor.config.customUploadImg = (files, insertImgFn) => {
|
||||
this.spinning = true
|
||||
|
||||
files.map(async file => {
|
||||
const fileMd5 = await this.computeFileMd5(file)
|
||||
const fileName = 'front' + moment().format('/YYYY/MM/DD/') + fileMd5 + '.' + file.type.replace('image/', '')
|
||||
|
||||
this.store.put(fileName, file).then(res => {
|
||||
insertImgFn(res.url)
|
||||
}).catch(err => {
|
||||
this.$message.error(err.message)
|
||||
}).finally(() => {
|
||||
this.spinning = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.editor.config.customUploadVideo = (files, insertVideoFn) => {
|
||||
this.spinning = true
|
||||
|
||||
files.map(async file => {
|
||||
const fileMd5 = await this.computeFileMd5(file)
|
||||
const fileName = 'front' + moment().format('/YYYY/MM/DD/') + fileMd5 + '.' + file.type.replace('image/', '')
|
||||
|
||||
this.store.multipartUpload(fileName, file, {
|
||||
progress: (e) => {
|
||||
this.percent = Math.round(e * 100)
|
||||
},
|
||||
partSize: 200 * 1024
|
||||
}).then(res => {
|
||||
let fileUrl = ''
|
||||
|
||||
const result = res.res.requestUrls
|
||||
if (result[0].indexOf('?') !== -1) {
|
||||
fileUrl = result[0].slice(0, result[0].indexOf('?'))
|
||||
} else {
|
||||
fileUrl = result[0]
|
||||
}
|
||||
insertVideoFn(fileUrl)
|
||||
}).catch(err => {
|
||||
this.$message.error(err.message)
|
||||
}).finally(() => {
|
||||
this.percent = 0
|
||||
this.spinning = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.editor.create()
|
||||
},
|
||||
getContent: function () {
|
||||
return this.editorContent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-editor-wang {
|
||||
.editor-wrapper {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
64
src/components/Ellipsis/Ellipsis.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script>
|
||||
import Tooltip from 'ant-design-vue/es/tooltip'
|
||||
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/util'
|
||||
/*
|
||||
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
|
||||
|
||||
const TooltipOverlayStyle = {
|
||||
overflowWrap: 'break-word',
|
||||
wordWrap: 'break-word',
|
||||
};
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'Ellipsis',
|
||||
components: {
|
||||
Tooltip
|
||||
},
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-ellipsis'
|
||||
},
|
||||
tooltip: {
|
||||
type: Boolean
|
||||
},
|
||||
length: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
lines: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
fullWidthRecognition: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getStrDom (str, fullLength) {
|
||||
return (
|
||||
<span>{ cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '') }</span>
|
||||
)
|
||||
},
|
||||
getTooltip (fullStr, fullLength) {
|
||||
return (
|
||||
<Tooltip>
|
||||
<template slot="title">{ fullStr }</template>
|
||||
{ this.getStrDom(fullStr, fullLength) }
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { tooltip, length } = this.$props
|
||||
const str = this.$slots.default.map(vNode => vNode.text).join('')
|
||||
const fullLength = getStrFullLength(str)
|
||||
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
|
||||
return (
|
||||
strDom
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
3
src/components/Ellipsis/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Ellipsis from './Ellipsis'
|
||||
|
||||
export default Ellipsis
|
||||
38
src/components/Ellipsis/index.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Ellipsis 文本自动省略号
|
||||
|
||||
文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
|
||||
|
||||
|
||||
|
||||
引用方式:
|
||||
|
||||
```javascript
|
||||
import Ellipsis from '@/components/Ellipsis'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ellipsis
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 代码演示 [demo](https://pro.loacg.com/test/home)
|
||||
|
||||
```html
|
||||
<ellipsis :length="100" tooltip>
|
||||
There were injuries alleged in three cases in 2015, and a
|
||||
fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.
|
||||
</ellipsis>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
|
||||
参数 | 说明 | 类型 | 默认值
|
||||
----|------|-----|------
|
||||
tooltip | 移动到文本展示完整内容的提示 | boolean | -
|
||||
length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -
|
||||
49
src/components/FooterToolBar/FooterToolBar.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div :class="prefixCls" :style="{ width: barWidth, transition: '0.3s all' }">
|
||||
<div style="float: left">
|
||||
<slot name="extra">{{ extra }}</slot>
|
||||
</div>
|
||||
<div style="float: right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FooterToolBar',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-footer-toolbar'
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
siderWidth: {
|
||||
type: Number,
|
||||
default: undefined
|
||||
},
|
||||
extra: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
barWidth () {
|
||||
return this.isMobile ? undefined : `calc(100% - ${this.collapsed ? 80 : this.siderWidth || 256}px)`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-pro-footer-toolbar {
|
||||
z-index: 1001;
|
||||
}
|
||||
</style>
|
||||
4
src/components/FooterToolBar/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import FooterToolBar from './FooterToolBar'
|
||||
import './index.less'
|
||||
|
||||
export default FooterToolBar
|
||||
23
src/components/FooterToolBar/index.less
Normal file
@@ -0,0 +1,23 @@
|
||||
@import "../index";
|
||||
|
||||
@footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar";
|
||||
|
||||
.@{footer-toolbar-prefix-cls} {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
|
||||
background: #fff;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 0 24px;
|
||||
z-index: 9;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
48
src/components/FooterToolBar/index.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# FooterToolbar 底部工具栏
|
||||
|
||||
固定在底部的工具栏。
|
||||
|
||||
|
||||
|
||||
## 何时使用
|
||||
|
||||
固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。
|
||||
|
||||
|
||||
|
||||
引用方式:
|
||||
|
||||
```javascript
|
||||
import FooterToolBar from '@/components/FooterToolBar'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FooterToolBar
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 代码演示
|
||||
|
||||
```html
|
||||
<footer-tool-bar>
|
||||
<a-button type="primary" @click="validate" :loading="loading">提交</a-button>
|
||||
</footer-tool-bar>
|
||||
```
|
||||
或
|
||||
```html
|
||||
<footer-tool-bar extra="扩展信息提示">
|
||||
<a-button type="primary" @click="validate" :loading="loading">提交</a-button>
|
||||
</footer-tool-bar>
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
参数 | 说明 | 类型 | 默认值
|
||||
----|------|-----|------
|
||||
children (slot) | 工具栏内容,向右对齐 | - | -
|
||||
extra | 额外信息,向左对齐 | String, Object | -
|
||||
|
||||
22
src/components/GlobalFooter/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<global-footer class="footer custom-render">
|
||||
<template v-slot:links>
|
||||
<a href="https://www.github.com/vueComponent/pro-layout" target="_blank">Pro Layout</a>
|
||||
<a href="https://www.github.com/vueComponent/ant-design-vue-pro" target="_blank">Github</a>
|
||||
</template>
|
||||
<template v-slot:copyright>
|
||||
<a href="https://www.cnskl.com" target="_blank">Uz.Tech © 2021</a>
|
||||
</template>
|
||||
</global-footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GlobalFooter } from '@ant-design-vue/pro-layout'
|
||||
|
||||
export default {
|
||||
name: 'ProGlobalFooter',
|
||||
components: {
|
||||
GlobalFooter
|
||||
}
|
||||
}
|
||||
</script>
|
||||
165
src/components/GlobalHeader/AvatarDropdown.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-dropdown v-if="currentUser && currentUser.name" placement="bottomRight">
|
||||
<span class="ant-pro-account-avatar">
|
||||
<a-avatar v-if="currentUser.avatar" :src="currentUser.avatar" class="antd-pro-global-header-index-avatar" size="small" />
|
||||
<a-avatar v-else src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" class="antd-pro-global-header-index-avatar" size="small" />
|
||||
<!-- <img class="avatar" src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> -->
|
||||
<!-- <a-avatar v-else style="color: #f56a00; backgroundColor: #fde3cf" class="antd-pro-global-header-index-avatar" size="small">U</a-avatar> -->
|
||||
<span>{{ currentUser.name }} ({{ currentUser.type }})</span>
|
||||
</span>
|
||||
<template v-slot:overlay>
|
||||
<a-menu :selected-keys="[]" class="ant-pro-drop-down menu">
|
||||
<a-menu-item key="changePwd" @click="changePassword">
|
||||
<a-icon type="lock" />
|
||||
修改密码
|
||||
</a-menu-item>
|
||||
<!-- <a-menu-item key="permission" @click="goPermission">
|
||||
<a-icon type="user" />
|
||||
组织结构(权限管理)
|
||||
</a-menu-item> -->
|
||||
<a-menu-item key="logout" @click="handleLogout">
|
||||
<a-icon type="logout" />
|
||||
退出登录
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<span v-else>
|
||||
<a-spin :style="{ marginLeft: 8, marginRight: 8 }" size="small" />
|
||||
</span>
|
||||
<a-modal v-model="visible" title="修改密码" on-ok="handleOk">
|
||||
<a-form-item>
|
||||
<a-input
|
||||
placeholder="请输入密码"
|
||||
size="large"
|
||||
type="password"
|
||||
oninput="value=value.replace(/[, ]/g,'')"
|
||||
onkeyup="value=value.replace(/[, ]/g,'')"
|
||||
onblur="value=value.replace(/\s+/g,'')"
|
||||
v-model="postData.passWord">
|
||||
<template v-slot:prefix>
|
||||
<a-icon :style="{ color: 'rgba(0,0,0,.25)' }" type="lock" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-input
|
||||
placeholder="请再次输入密码"
|
||||
size="large"
|
||||
type="password"
|
||||
oninput="value=value.replace(/[, ]/g,'')"
|
||||
onkeyup="value=value.replace(/[, ]/g,'')"
|
||||
onblur="value=value.replace(/\s+/g,'')"
|
||||
v-model="postData.passWordAgain">
|
||||
<template v-slot:prefix>
|
||||
<a-icon :style="{ color: 'rgba(0,0,0,.25)' }" type="lock" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<template slot="footer">
|
||||
<a-button key="back" @click="visible = false">
|
||||
取消
|
||||
</a-button>
|
||||
<a-button key="submit" type="primary" :loading="loading" @click="handleOk">
|
||||
确认
|
||||
</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Modal } from 'ant-design-vue'
|
||||
import { password } from '@/api/login'
|
||||
|
||||
export default {
|
||||
name: 'AvatarDropdown',
|
||||
props: {
|
||||
currentUser: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
},
|
||||
menu: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
visible: false,
|
||||
postData: {
|
||||
passWord: '',
|
||||
passWordAgain: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goPermission () {
|
||||
if (this.$route.name !== 'PermissionsIndex') {
|
||||
this.$router.push({ name: 'PermissionsIndex' })
|
||||
}
|
||||
},
|
||||
handleToCenter () {
|
||||
if (this.$route.name !== 'UserCenter') {
|
||||
this.$router.push({ name: 'UserCenter' })
|
||||
}
|
||||
},
|
||||
handleToSettings () {
|
||||
if (this.$route.name !== 'SecuritySettings') {
|
||||
this.$router.push({ name: 'SecuritySettings' })
|
||||
}
|
||||
},
|
||||
handleLogout (e) {
|
||||
Modal.confirm({
|
||||
title: this.$t('layouts.usermenu.dialog.title'),
|
||||
content: this.$t('layouts.usermenu.dialog.content'),
|
||||
onOk: () => {
|
||||
return this.$store.dispatch('Logout').then(() => {
|
||||
this.$router.replace({ name: 'login' })
|
||||
})
|
||||
},
|
||||
onCancel () {
|
||||
}
|
||||
})
|
||||
},
|
||||
changePassword () {
|
||||
this.visible = true
|
||||
},
|
||||
handleOk () {
|
||||
this.loading = true
|
||||
password({
|
||||
password: this.postData.passWord,
|
||||
password_confirmation: this.postData.passWordAgain
|
||||
}).then(res => {
|
||||
this.loading = false
|
||||
this.visible = false
|
||||
this.postData.passWord = ''
|
||||
this.postData.passWordAgain = ''
|
||||
this.$notification.success({
|
||||
message: res
|
||||
})
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
this.visible = true
|
||||
this.$notification.error({
|
||||
message: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-pro-drop-down {
|
||||
/deep/ .action {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/deep/ .ant-dropdown-menu-item {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
60
src/components/GlobalHeader/RightContent.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div :class="wrpCls">
|
||||
<notice-icon />
|
||||
<avatar-dropdown :class="prefixCls" :current-user="currentUser" :menu="showMenu" />
|
||||
<!-- <select-lang :class="prefixCls" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AvatarDropdown from './AvatarDropdown'
|
||||
import SelectLang from '@/components/SelectLang'
|
||||
import NoticeIcon from '../NoticeIcon'
|
||||
|
||||
export default {
|
||||
name: 'RightContent',
|
||||
components: {
|
||||
AvatarDropdown,
|
||||
SelectLang,
|
||||
NoticeIcon
|
||||
},
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-global-header-index-action'
|
||||
},
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
topMenu: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showMenu: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
wrpCls () {
|
||||
return {
|
||||
'ant-pro-global-header-index-right': true,
|
||||
[`ant-pro-global-header-index-${(this.isMobile || !this.topMenu) ? 'light' : this.theme}`]: true
|
||||
}
|
||||
},
|
||||
currentUser () {
|
||||
return {
|
||||
name: this.$store.getters.nickname,
|
||||
avatar: this.$store.getters.avatar,
|
||||
type: this.$store.getters.userInfo.type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
86
src/components/IconSelector/IconSelector.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<a-tabs v-model="currentTab" @change="handleTabChange">
|
||||
<a-tab-pane v-for="v in icons" :tab="v.title" :key="v.key">
|
||||
<ul>
|
||||
<li v-for="(icon, key) in v.icons" :key="`${v.key}-${key}`" :class="{ 'active': selectedIcon==icon }" @click="handleSelectedIcon(icon)" >
|
||||
<a-icon :type="icon" :style="{ fontSize: '36px' }" />
|
||||
</li>
|
||||
</ul>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './icons'
|
||||
|
||||
export default {
|
||||
name: 'IconSelect',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-icon-selector'
|
||||
},
|
||||
// eslint-disable-next-line
|
||||
value: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selectedIcon: this.value || '',
|
||||
currentTab: 'directional',
|
||||
icons
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value (val) {
|
||||
this.selectedIcon = val
|
||||
this.autoSwitchTab()
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.value) {
|
||||
this.autoSwitchTab()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSelectedIcon (icon) {
|
||||
this.selectedIcon = icon
|
||||
this.$emit('change', icon)
|
||||
},
|
||||
handleTabChange (activeKey) {
|
||||
this.currentTab = activeKey
|
||||
},
|
||||
autoSwitchTab () {
|
||||
icons.some(item => item.icons.some(icon => icon === this.value) && (this.currentTab = item.key))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "../index.less";
|
||||
|
||||
ul{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
overflow-y: scroll;
|
||||
height: 250px;
|
||||
|
||||
li{
|
||||
display: inline-block;
|
||||
padding: @padding-sm;
|
||||
margin: 3px 0;
|
||||
border-radius: @border-radius-base;
|
||||
|
||||
&:hover, &.active{
|
||||
// box-shadow: 0px 0px 5px 2px @primary-color;
|
||||
cursor: pointer;
|
||||
color: @white;
|
||||
background-color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
48
src/components/IconSelector/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
IconSelector
|
||||
====
|
||||
|
||||
> 图标选择组件,常用于为某一个数据设定一个图标时使用
|
||||
> eg: 设定菜单列表时,为每个菜单设定一个图标
|
||||
|
||||
该组件由 [@Saraka](https://github.com/saraka-tsukai) 封装
|
||||
|
||||
|
||||
|
||||
### 使用方式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<icon-selector @change="handleIconChange"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IconSelector from '@/components/IconSelector'
|
||||
|
||||
export default {
|
||||
name: 'YourView',
|
||||
components: {
|
||||
IconSelector
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleIconChange (icon) {
|
||||
// console.log('change Icon', icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 事件
|
||||
|
||||
|
||||
| 名称 | 说明 | 类型 | 默认值 |
|
||||
| ------ | -------------------------- | ------ | ------ |
|
||||
| change | 当改变了 `icon` 选中项触发 | String | - |
|
||||
36
src/components/IconSelector/icons.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 增加新的图标时,请遵循以下数据结构
|
||||
* Adding new icon please follow the data structure below
|
||||
*/
|
||||
export default [
|
||||
{
|
||||
key: 'directional',
|
||||
title: '方向性图标',
|
||||
icons: ['step-backward', 'step-forward', 'fast-backward', 'fast-forward', 'shrink', 'arrows-alt', 'down', 'up', 'left', 'right', 'caret-up', 'caret-down', 'caret-left', 'caret-right', 'up-circle', 'down-circle', 'left-circle', 'right-circle', 'double-right', 'double-left', 'vertical-left', 'vertical-right', 'forward', 'backward', 'rollback', 'enter', 'retweet', 'swap', 'swap-left', 'swap-right', 'arrow-up', 'arrow-down', 'arrow-left', 'arrow-right', 'play-circle', 'up-square', 'down-square', 'left-square', 'right-square', 'login', 'logout', 'menu-fold', 'menu-unfold', 'border-bottom', 'border-horizontal', 'border-inner', 'border-left', 'border-right', 'border-top', 'border-verticle', 'pic-center', 'pic-left', 'pic-right', 'radius-bottomleft', 'radius-bottomright', 'radius-upleft', 'fullscreen', 'fullscreen-exit']
|
||||
},
|
||||
{
|
||||
key: 'suggested',
|
||||
title: '提示建议性图标',
|
||||
icons: ['question', 'question-circle', 'plus', 'plus-circle', 'pause', 'pause-circle', 'minus', 'minus-circle', 'plus-square', 'minus-square', 'info', 'info-circle', 'exclamation', 'exclamation-circle', 'close', 'close-circle', 'close-square', 'check', 'check-circle', 'check-square', 'clock-circle', 'warning', 'issues-close', 'stop']
|
||||
},
|
||||
{
|
||||
key: 'editor',
|
||||
title: '编辑类图标',
|
||||
icons: ['edit', 'form', 'copy', 'scissor', 'delete', 'snippets', 'diff', 'highlight', 'align-center', 'align-left', 'align-right', 'bg-colors', 'bold', 'italic', 'underline', 'strikethrough', 'redo', 'undo', 'zoom-in', 'zoom-out', 'font-colors', 'font-size', 'line-height', 'colum-height', 'dash', 'small-dash', 'sort-ascending', 'sort-descending', 'drag', 'ordered-list', 'radius-setting']
|
||||
},
|
||||
{
|
||||
key: 'data',
|
||||
title: '数据类图标',
|
||||
icons: ['area-chart', 'pie-chart', 'bar-chart', 'dot-chart', 'line-chart', 'radar-chart', 'heat-map', 'fall', 'rise', 'stock', 'box-plot', 'fund', 'sliders']
|
||||
},
|
||||
{
|
||||
key: 'brand_logo',
|
||||
title: '网站通用图标',
|
||||
icons: ['lock', 'unlock', 'bars', 'book', 'calendar', 'cloud', 'cloud-download', 'code', 'copy', 'credit-card', 'delete', 'desktop', 'download', 'ellipsis', 'file', 'file-text', 'file-unknown', 'file-pdf', 'file-word', 'file-excel', 'file-jpg', 'file-ppt', 'file-markdown', 'file-add', 'folder', 'folder-open', 'folder-add', 'hdd', 'frown', 'meh', 'smile', 'inbox', 'laptop', 'appstore', 'link', 'mail', 'mobile', 'notification', 'paper-clip', 'picture', 'poweroff', 'reload', 'search', 'setting', 'share-alt', 'shopping-cart', 'tablet', 'tag', 'tags', 'to-top', 'upload', 'user', 'video-camera', 'home', 'loading', 'loading-3-quarters', 'cloud-upload', 'star', 'heart', 'environment', 'eye', 'camera', 'save', 'team', 'solution', 'phone', 'filter', 'exception', 'export', 'customer-service', 'qrcode', 'scan', 'like', 'dislike', 'message', 'pay-circle', 'calculator', 'pushpin', 'bulb', 'select', 'switcher', 'rocket', 'bell', 'disconnect', 'database', 'compass', 'barcode', 'hourglass', 'key', 'flag', 'layout', 'printer', 'sound', 'usb', 'skin', 'tool', 'sync', 'wifi', 'car', 'schedule', 'auth-add', 'auth-delete', 'usergroup-add', 'usergroup-delete', 'man', 'woman', 'shop', 'gift', 'idcard', 'medicine-box', 'red-envelope', 'coffee', 'copyright', 'trademark', 'safety', 'wallet', 'bank', 'trophy', 'contacts', 'global', 'shake', 'api', 'fork', 'home', 'table', 'profile', 'alert', 'audit', 'branches', 'build', 'border', 'crown', 'experiment', 'fire', 'money-collect', 'property-safety', 'read', 'reconciliation', 'rest', 'security-scan', 'insurance', 'interation', 'safety-certificate', 'project', 'thunderbolt', 'block', 'cluster', 'deployment-unit', 'dollar', 'euro', 'pound', 'file-done', 'file-exclamation', 'file-protect', 'file-search', 'file-sync', 'gateway', 'gold', 'robot', 'shopping']
|
||||
},
|
||||
{
|
||||
key: 'application',
|
||||
title: '品牌和标识',
|
||||
icons: ['android', 'apple', 'windows', 'ie', 'chrome', 'github', 'aliwangwang', 'dingding', 'weibo-square', 'weibo-circle', 'taobao-circle', 'html5', 'weibo', 'twitter', 'wechat', 'youtube', 'alipay-circle', 'taobao', 'skype', 'qq', 'medium-workmark', 'gitlab', 'medium', 'linkedin', 'google-plus', 'dropbox', 'facebook', 'codepen', 'code-sandbox', 'amazon', 'google', 'codepen-circle', 'alipay', 'ant-design', 'aliyun', 'zhihu', 'slack', 'slack-square', 'behance', 'behance-square', 'dribbble', 'dribbble-square', 'instagram', 'yuque', 'alibaba', 'yahoo']
|
||||
}
|
||||
]
|
||||
2
src/components/IconSelector/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import IconSelector from './IconSelector'
|
||||
export default IconSelector
|
||||
29
src/components/Image/Image.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div>
|
||||
<img
|
||||
:style="{ backgroundImage: 'url(' + src + ')',paddingTop: '100%' }"
|
||||
class="jason-image"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Image',
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.jason-image {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
2
src/components/Image/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import Image from './Image'
|
||||
export default Image
|
||||
76
src/components/NProgress/nprogress.less
Normal file
@@ -0,0 +1,76 @@
|
||||
@import url('../index.less');
|
||||
|
||||
/* Make clicks pass-through */
|
||||
#nprogress {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#nprogress .bar {
|
||||
background: @primary-color;
|
||||
|
||||
position: fixed;
|
||||
z-index: 1031;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/* Fancy blur effect */
|
||||
#nprogress .peg {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color;
|
||||
opacity: 1.0;
|
||||
|
||||
-webkit-transform: rotate(3deg) translate(0px, -4px);
|
||||
-ms-transform: rotate(3deg) translate(0px, -4px);
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
}
|
||||
|
||||
/* Remove these to get rid of the spinner */
|
||||
#nprogress .spinner {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 1031;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
#nprogress .spinner-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
box-sizing: border-box;
|
||||
|
||||
border: solid 2px transparent;
|
||||
border-top-color: @primary-color;
|
||||
border-left-color: @primary-color;
|
||||
border-radius: 50%;
|
||||
|
||||
-webkit-animation: nprogress-spinner 400ms linear infinite;
|
||||
animation: nprogress-spinner 400ms linear infinite;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nprogress-custom-parent #nprogress .spinner,
|
||||
.nprogress-custom-parent #nprogress .bar {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@-webkit-keyframes nprogress-spinner {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(360deg); }
|
||||
}
|
||||
@keyframes nprogress-spinner {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
128
src/components/NoticeIcon/NoticeIcon.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<a-popover
|
||||
v-model="visible"
|
||||
:arrowPointAtCenter="true"
|
||||
:autoAdjustOverflow="true"
|
||||
:getPopupContainer="() => $refs.noticeRef.parentElement"
|
||||
placement="bottomRight"
|
||||
trigger="click"
|
||||
>
|
||||
<template slot="content">
|
||||
<a-spin :spinning="loading">
|
||||
<a-tabs>
|
||||
<a-tab-pane key="1" tab="消息通知">
|
||||
<a-list>
|
||||
<a-list-item @click="goNewList">
|
||||
<a-list-item-meta :title="noticeCount>0?'您有'+ noticeCount +'份未读消息通知':'您的消息通知列表'">
|
||||
<a-avatar
|
||||
slot="avatar"
|
||||
src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"
|
||||
style="background-color: white" />
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</template>
|
||||
<span ref="noticeRef" class="header-notice" @click="fetchNotice">
|
||||
<a-badge :count="noticeCount">
|
||||
<a-icon type="bell" />
|
||||
</a-badge>
|
||||
<div style="margin: 10px;display: none;">
|
||||
<audio controls="controls" style="width: 100%;" id="yx_player">
|
||||
<source src="./notice.mp3">
|
||||
</audio>
|
||||
</div>
|
||||
</span>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import SettingItemVue from '../SettingDrawer/SettingItem.vue'
|
||||
import storage from 'store'
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||
import { getUnreadCount } from '@/api/notice'
|
||||
export default {
|
||||
name: 'HeaderNotice',
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
visible: false,
|
||||
timer: '',
|
||||
noticeCount: 0
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
created () {
|
||||
// console.log('created..noticeIcon...notifies/unread_count')
|
||||
const token = storage.get(ACCESS_TOKEN)
|
||||
this.getNoticeCount()
|
||||
if (token) {
|
||||
this.timer = setInterval(() => {
|
||||
this.getNoticeCount()
|
||||
}, 6000)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNoticeCount () {
|
||||
getUnreadCount().then(res => {
|
||||
if (res.count > this.noticeCount && this.noticeCount !== 0) {
|
||||
const plr = document.getElementById('yx_player')
|
||||
plr.play()
|
||||
setTimeout(() => {
|
||||
plr.play()
|
||||
}, 1500)
|
||||
}
|
||||
this.noticeCount = res.count
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
goNewList () {
|
||||
if (this.$route.path === '/noticeList') {
|
||||
this.getNoticeCount()
|
||||
} else {
|
||||
this.$router.push({ name: 'NoticeList', params: {} })
|
||||
}
|
||||
this.visible = !this.visible
|
||||
},
|
||||
fetchNotice () {
|
||||
if (!this.visible) {
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 1000)
|
||||
} else {
|
||||
this.loading = false
|
||||
}
|
||||
this.visible = !this.visible
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "~ant-design-vue/lib/style/index";
|
||||
|
||||
.header-notice {
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
padding: 0 20px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
|
||||
.anticon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
110
src/components/NoticeIcon/NoticeList.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<a-card title="消息列表">
|
||||
<div class="extra" slot="extra" href="#" @click="readAll">全部已读</div>
|
||||
<a-list class="demo-loadmore-list" :loading="loading" item-layout="horizontal" :data-source="data">
|
||||
<div v-if="showLoadingMore" slot="loadMore" :style="{ textAlign: 'center', marginTop: '12px', height: '32px', lineHeight: '32px' }">
|
||||
<a-spin v-if="loadingMore" />
|
||||
<a-button v-else @click="onLoadMore"> 获取更多 </a-button>
|
||||
</div>
|
||||
<a-list-item slot="renderItem" slot-scope="item,index">
|
||||
<a slot="actions" :class="['title', item.read_at !== '' ? 'active' : '']" @click="readed(item,index)">设置已读</a>
|
||||
<a-list-item-meta :description="item.content">
|
||||
<a slot="title" :class="['title', item.read_at !== '' ? 'active' : '']" >{{ item.title }} <span style="font-size:90%;padding-left: 10px;">{{ item.created_at }}</span></a>
|
||||
<a-avatar v-if="item.read_at === ''" icon="sound" slot="avatar" style="color: #FFF; backgroundColor: #1890FF"></a-avatar>
|
||||
<a-avatar v-else slot="avatar" icon="sound"></a-avatar>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getNoticeList,
|
||||
readNotice,
|
||||
readAllNotice
|
||||
} from '@/api/notice'
|
||||
export default {
|
||||
name: 'NoticeList',
|
||||
data () {
|
||||
return {
|
||||
loading: false, //
|
||||
loadingMore: false,
|
||||
showLoadingMore: true,
|
||||
data: [],
|
||||
page: 1
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
watch: {
|
||||
$route (to, from) {
|
||||
if (to.name === 'NoticeList') {
|
||||
this.data = []
|
||||
this.page = 1
|
||||
this.showLoadingMore = true
|
||||
this.loadingMore = false
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取消息列表
|
||||
getList () {
|
||||
getNoticeList({ page: this.page }).then(res => {
|
||||
this.data = this.data.concat(res.data)
|
||||
this.loadingMore = false
|
||||
this.showLoadingMore = res.page.has_more
|
||||
this.$nextTick(() => {
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$$notification.error(err)
|
||||
})
|
||||
},
|
||||
// 获取更多
|
||||
onLoadMore () {
|
||||
if (this.showLoadingMore) {
|
||||
this.page = this.page + 1
|
||||
this.loadingMore = true
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
// 消息已读
|
||||
readed (item, index) {
|
||||
readNotice(item.notification_id).then(res => {
|
||||
this.$notification.success({ message: '已读消息' })
|
||||
this.data[index].read_at = '----'
|
||||
}).catch(err => {
|
||||
this.$notification.error(err)
|
||||
})
|
||||
},
|
||||
// 消息全部已读
|
||||
readAll () {
|
||||
readAllNotice().then(res => {
|
||||
this.$notification.success({ message: '已读全部消息' })
|
||||
this.page = 1
|
||||
this.data = []
|
||||
this.showLoadingMore = true
|
||||
this.getList()
|
||||
}).catch(err => {
|
||||
this.$notification.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import '~ant-design-vue/lib/style/index';
|
||||
.demo-loadmore-list {
|
||||
min-height: 500px;
|
||||
}
|
||||
.active {
|
||||
color: rgba(6, 6, 6, 0.45) !important;
|
||||
}
|
||||
.extra{
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
2
src/components/NoticeIcon/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import NoticeIcon from './NoticeIcon'
|
||||
export default NoticeIcon
|
||||
BIN
src/components/NoticeIcon/notice.mp3
Normal file
54
src/components/NumberInfo/NumberInfo.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div :class="[prefixCls]">
|
||||
<slot name="subtitle">
|
||||
<div :class="[`${prefixCls}-subtitle`]">{{ typeof subTitle === 'string' ? subTitle : subTitle() }}</div>
|
||||
</slot>
|
||||
<div class="number-info-value">
|
||||
<span>{{ total }}</span>
|
||||
<span class="sub-total">
|
||||
{{ subTotal }}
|
||||
<icon :type="`caret-${status}`" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Icon from 'ant-design-vue/es/icon'
|
||||
|
||||
export default {
|
||||
name: 'NumberInfo',
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-number-info'
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
subTotal: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
subTitle: {
|
||||
type: [String, Function],
|
||||
default: ''
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
default: 'up'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Icon
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// @import "index";
|
||||
</style>
|
||||
3
src/components/NumberInfo/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import NumberInfo from './NumberInfo'
|
||||
|
||||
export default NumberInfo
|
||||
55
src/components/NumberInfo/index.less
Normal file
@@ -0,0 +1,55 @@
|
||||
@import "../index";
|
||||
|
||||
@numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info";
|
||||
|
||||
.@{numberInfo-prefix-cls} {
|
||||
|
||||
.ant-pro-number-info-subtitle {
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-base;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.number-info-value {
|
||||
margin-top: 4px;
|
||||
font-size: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
|
||||
& > span {
|
||||
color: @heading-color;
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
font-size: 24px;
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.sub-total {
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-lg;
|
||||
vertical-align: top;
|
||||
margin-right: 0;
|
||||
i {
|
||||
font-size: 12px;
|
||||
transform: scale(0.82);
|
||||
margin-left: 4px;
|
||||
}
|
||||
:global {
|
||||
.anticon-caret-up {
|
||||
color: @red-6;
|
||||
}
|
||||
.anticon-caret-down {
|
||||
color: @green-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/components/NumberInfo/index.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# NumberInfo 数据文本
|
||||
|
||||
常用在数据卡片中,用于突出展示某个业务数据。
|
||||
|
||||
|
||||
|
||||
引用方式:
|
||||
|
||||
```javascript
|
||||
import NumberInfo from '@/components/NumberInfo'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NumberInfo
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 代码演示 [demo](https://pro.loacg.com/test/home)
|
||||
|
||||
```html
|
||||
<number-info
|
||||
:sub-title="() => { return 'Visits this week' }"
|
||||
:total="12321"
|
||||
status="up"
|
||||
:sub-total="17.1"></number-info>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
参数 | 说明 | 类型 | 默认值
|
||||
----|------|-----|------
|
||||
title | 标题 | ReactNode\|string | -
|
||||
subTitle | 子标题 | ReactNode\|string | -
|
||||
total | 总量 | ReactNode\|string | -
|
||||
subTotal | 子总量 | ReactNode\|string | -
|
||||
status | 增加状态 | 'up \| down' | -
|
||||
theme | 状态样式 | string | 'light'
|
||||
gap | 设置数字和描述之间的间距(像素)| number | 8
|
||||
115
src/components/OrderDetailInfo/BankItem.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="bank-item">
|
||||
<a-card :title="record.institution + ' ' +record.business +' ' +record.business_type">
|
||||
<template #extra>
|
||||
<a class="active" @click="rejectEdit = !rejectEdit, resetEdit = true" v-if="can.check">
|
||||
<a-icon :type="rejectEdit ? 'undo' : 'undo'" color="green" />
|
||||
{{ rejectEdit ? '驳回信息' : '取消驳回' }}
|
||||
</a>
|
||||
<a @click="resetEdit = !resetEdit, rejectEdit = true" v-if="can.update">
|
||||
<a-divider type="vertical" />
|
||||
<span style="margin-left:20px;padding-right:20px;"><a-icon :type="resetEdit ? 'edit' : 'edit'"/>
|
||||
{{ resetEdit ? '修改信息' : '取消修改' }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<!-- 完善信息之后展示 -->
|
||||
<a-descriptions title="机构详细信息" layout="horizontal" bordered :column="{ xxl: 3, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }">
|
||||
<a-descriptions-item
|
||||
v-for="item in (can.params?record.params:record.bank)"
|
||||
:key="item.key"
|
||||
:label="item.key =='family_difficulties'?'家庭困难情况' :item.key =='overdue_reasons' ?'逾期原因' :item.title"
|
||||
>
|
||||
<template v-slot:label>
|
||||
<div>{{ item.title }}</div>
|
||||
</template>
|
||||
<div class="row jc_sb wrodbreak" >
|
||||
{{ item.key =='price' || item.key == 'base_price' || item.key =='usable_amount' || item.key == 'now_amount' || item.key == 'card_amount' || item.key == 'debt_amount'?'¥':'' }}
|
||||
{{ item.value_text || '--' }}
|
||||
{{ item.key == 'overdue_day' && item.value_text>0 ?'天':'' }}
|
||||
<ItemPopover :rejectEdit="rejectEdit" :resetEdit="resetEdit" type="bank" :id="{'item_id':record.order_item_id,'order_id':orderId}" :item="item" />
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<br/>
|
||||
<a-descriptions title="预估方案" layout="horizontal" bordered :column="{ xxl: 4, xl: 3, lg:2, md: 1, sm: 1, xs: 1 }" v-if="(record.schemes.length>0)">
|
||||
<a-descriptions-item
|
||||
v-for="item in record.schemes[0].params"
|
||||
:key="item.key"
|
||||
:label="item.title"
|
||||
:span="2"
|
||||
>
|
||||
{{ item.key =='price' || item.key == 'base_price'?'¥':'' }}
|
||||
{{ item.value || '--' }}
|
||||
{{ item.key == 'overdue_day' && item.value>0 ?'天':'' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
|
||||
export default {
|
||||
name: 'BankItem',
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
props: {
|
||||
record: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
rejectEdit: true,
|
||||
resetEdit: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.wrodbreak{
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
298
src/components/OrderDetailInfo/BankList.vue
Normal file
@@ -0,0 +1,298 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-card :bordered="true" style="margin-top: 24px" title="申请机构列表">
|
||||
<a slot="extra" v-if="(count>0)">
|
||||
<span style="margin-right:20px;">
|
||||
<span style="color:#ff4d4f;">共{{ count }}条驳回待审</span>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
有信息被驳回,请先审核通过!
|
||||
</template>
|
||||
<a-icon type="info-circle" :style="{ fontSize: '16px', color: '#ff4d4f',padding:'0 0 0 10px' }" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</a>
|
||||
<s-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowKey="(row) => row.order_item_id"
|
||||
showPagination="auto"
|
||||
size="default"
|
||||
:expandRowByClick="true"
|
||||
>
|
||||
<span slot="action" slot-scope="text, record" href="javascript:;">
|
||||
<!-- <span>
|
||||
<a style="margin-right:10px;" type="primary" @click.stop="seedMessage(record)" >导出表格</a>
|
||||
</span> -->
|
||||
<span v-if="record.can.send">
|
||||
<a-divider type="vertical" />
|
||||
<a style="margin-right:10px;" type="primary" @click.stop="seedMessage(record)" >发送通知</a>
|
||||
<a-divider type="vertical" />
|
||||
</span>
|
||||
<span v-if="(record.log_count>0)">(<span style="color:#ff4d4f;">{{ record.log_count }}条待修改</span>、<span style="color:#faad14;">{{ record.log_make_count }}条待确认)</span></span>
|
||||
<a-divider type="vertical" v-if="record.can && record.can.logs" />
|
||||
<a v-if="record.can && record.can.logs" @click.stop="checkOperation(record.order_item_id)"> {{ record.can.logAdd ? '添加记录':'查看记录' }}</a>
|
||||
<!-- <a-icon @click.stop="addOperation(record)" type="plus" :style="{ fontSize: '14px', color: '#1890ff',padding:'6px' }" /> -->
|
||||
<a-divider type="vertical"/>
|
||||
<a @click.stop="surePlan(record.order_item_id)">结案方案</a>
|
||||
</span>
|
||||
<span slot="price" slot-scope="text, record">
|
||||
<a @click.stop="moneyChangeDetail(record)">¥{{ record.price }} <a-icon type="edit" v-if="can.update_price" @click.stop="moneyChange(record)" color="#1890ff" /></a>
|
||||
</span>
|
||||
<div slot="expandedRowRender" slot-scope="record">
|
||||
<BankItem :record="record" :orderId="id+''" :can="can" />
|
||||
</div>
|
||||
</s-table>
|
||||
<!-- 记录展示 -->
|
||||
<div v-if="logsList.length>0" class="logs" >
|
||||
<a-descriptions title="记录列表(订单记录、机构记录)"></a-descriptions>
|
||||
<a class="seeMore" v-if="logsList.length>1" >
|
||||
<a class="more" @click="showAll = !showAll">{{ !showAll?'更多':'收起' }}
|
||||
<a-icon :type="!showAll?'down':'up'" color="#1890ff" />
|
||||
</a>
|
||||
</a>
|
||||
<a-timeline v-if="showAll">
|
||||
<a-timeline-item v-for="item in logsList" :key="item.log_id">
|
||||
{{ item.operate.name }}({{ item.operate.type }})
|
||||
<span>添加了
|
||||
<a v-if="item.item" @click="checkOperation(item.item_id)">「{{ item.item }}」机构记录</a>
|
||||
<a v-else>「订单记录」</a>
|
||||
</span>
|
||||
<div>记录内容: {{ item.description }}</div>
|
||||
<div>{{ item.do_at }}</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
<a-timeline v-else>
|
||||
<a-timeline-item>
|
||||
{{ logsList[0].operate.name }}({{ logsList[0].operate.type }})
|
||||
<span>添加了
|
||||
<a v-if="logsList[0].item" @click="checkOperation(logsList[0].item_id)">「{{ logsList[0].item }}」机构记录</a>
|
||||
<a v-else>「订单记录」</a>
|
||||
</span>
|
||||
<div>记录内容: {{ logsList[0].description }}</div>
|
||||
<div>{{ logsList[0].do_at }}</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</a-card>
|
||||
<a-drawer width="640" placement="right" :closable="false" :visible="changeVisible" @close="onClose">
|
||||
<template v-if="changeBankLog.length>0">
|
||||
<a-descriptions :title="`第${index}次修改`" v-for="(item , index ) in changeBankLog" :key="index">
|
||||
<a-descriptions-item label="修改机构" span="1">{{ item.item }}</a-descriptions-item>
|
||||
<a-descriptions-item label="修改前金额">¥{{ item.pre_price }}</a-descriptions-item>
|
||||
<a-descriptions-item label="修改后金额"><span style="color:red;">¥{{ item.price }}</span></a-descriptions-item>
|
||||
<a-descriptions-item label="操作人" span="1">{{ item.user.name }}({{ item.user.job }})</a-descriptions-item>
|
||||
<a-descriptions-item label="操作时间" span="2">{{ item.created_at }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注原因" span="3">{{ item.reason }}</a-descriptions-item>
|
||||
<a-descriptions-item><br /></a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</template>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getBankItem,
|
||||
doLogsList,
|
||||
getChangeBankCountLog
|
||||
} from '@/api/order'
|
||||
import { sendMessage } from '@/api/notice'
|
||||
import { STable } from '@/components'
|
||||
import BankItem from './BankItem.vue'
|
||||
import MoneyChange from '@/components/OrderDetailInfo/modules/MoneyChange.vue'
|
||||
|
||||
const columns = [
|
||||
{ title: '申请机构', dataIndex: 'institution', key: 'institution' },
|
||||
{ title: '业务名称', dataIndex: 'business', key: 'business' },
|
||||
{ title: '业务类型', dataIndex: 'business_type', key: 'business_type' },
|
||||
{ title: '欠款金额', dataIndex: 'price', key: 'price', scopedSlots: { customRender: 'price' } },
|
||||
{ title: '状态', dataIndex: 'check_status', key: 'check_status' },
|
||||
{ title: '操作', dataIndex: '', key: 'x', scopedSlots: { customRender: 'action' } }
|
||||
]
|
||||
export default {
|
||||
name: 'BankList',
|
||||
components: {
|
||||
STable, BankItem, MoneyChange
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns,
|
||||
queryParam: {},
|
||||
loadData: parameter => {
|
||||
const requestParameters = Object.assign({}, parameter, this.queryParam)
|
||||
return getBankItem(this.id, requestParameters)
|
||||
},
|
||||
logsList: [],
|
||||
changeBankLog: [], // 银行修改金额记录
|
||||
changeVisible: false,
|
||||
showAll: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getInfo()
|
||||
},
|
||||
activated () {
|
||||
this.$refs.table.loadData()
|
||||
this.getInfo()
|
||||
|
||||
// 接受传参
|
||||
this.eventBus.$on('editBank', (res) => {
|
||||
this.$refs.table.loadData()
|
||||
this.getInfo()
|
||||
})
|
||||
},
|
||||
deactivated () {
|
||||
this.eventBus.$off('editBank')
|
||||
},
|
||||
methods: {
|
||||
getInfo () {
|
||||
doLogsList(this.id, { item_id: '' }).then(
|
||||
res => {
|
||||
console.log(res)
|
||||
this.logsList = res
|
||||
}).catch(
|
||||
err => {
|
||||
this.$notification.error(err)
|
||||
}
|
||||
)
|
||||
},
|
||||
surePlan (itemId) {
|
||||
this.$router.push({
|
||||
name: 'ConfirmPlan',
|
||||
params: {
|
||||
itemId: itemId,
|
||||
orderId: this.id
|
||||
}
|
||||
})
|
||||
},
|
||||
checkOperation (itemId) {
|
||||
this.$router.push({
|
||||
name: 'OperationList',
|
||||
params: {
|
||||
itemId: itemId,
|
||||
orderId: this.id
|
||||
}
|
||||
})
|
||||
},
|
||||
// 修改金额
|
||||
moneyChange (item) {
|
||||
console.log(item)
|
||||
const order = {
|
||||
item: item,
|
||||
orderId: this.id
|
||||
}
|
||||
this.$dialog(MoneyChange,
|
||||
{
|
||||
order,
|
||||
on: {
|
||||
ok: () => {
|
||||
this.$refs.table.loadData()
|
||||
this.getInfo()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '修改当前机构的欠款金额',
|
||||
width: 500,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认修改',
|
||||
cancelText: '取消'
|
||||
}
|
||||
)
|
||||
},
|
||||
// 查看欠款金额修改详情
|
||||
moneyChangeDetail (item) {
|
||||
getChangeBankCountLog(this.id, item.order_item_id).then(res => {
|
||||
this.changeBankLog = res
|
||||
if (res.length > 0) {
|
||||
this.changeVisible = true
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: '提醒',
|
||||
description: '没有修改过该机构的欠款金额!'
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
this.$notification.error(err)
|
||||
})
|
||||
},
|
||||
onClose () {
|
||||
this.changeVisible = false
|
||||
},
|
||||
// 发送信息
|
||||
seedMessage (item) {
|
||||
sendMessage(this.id, 2, item.order_item_id).then(res => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '发送消息成功!'
|
||||
})
|
||||
this.getInfo()
|
||||
this.$refs.table.loadData()
|
||||
}).catch(err => {
|
||||
this.$notification.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.logs{
|
||||
margin:40px 20px 0 20px;
|
||||
position: relative;
|
||||
.seeMore{
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top:4px;
|
||||
.addOperation{
|
||||
margin-right: 10px;
|
||||
}
|
||||
.more{
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
45
src/components/OrderDetailInfo/DeriveButton.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<a-button class="derive" type="dashed" shape="round" icon="download" @click="downLoad" />
|
||||
</template>
|
||||
<script>
|
||||
import storage from 'store'
|
||||
import { getStorageDownUrl } from '@/api/storage'
|
||||
export default {
|
||||
name: 'DeriveButton',
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
props: {
|
||||
queryParam: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
listCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
downLoad () {
|
||||
if (this.listCount > 0) {
|
||||
const queryParam = this.queryParam
|
||||
let downUrl = getStorageDownUrl() + '?user_id=' + storage.get('userid')
|
||||
for (const key in queryParam) {
|
||||
downUrl = downUrl + '&' + key + '=' + queryParam[key]
|
||||
}
|
||||
window.open(downUrl)
|
||||
} else {
|
||||
this.$notification.error({
|
||||
message: '温馨提醒',
|
||||
description: '数据为空不能下载!'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.derive {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
79
src/components/OrderDetailInfo/OrderSteps.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 用户实名信息 -->
|
||||
<a-card :bordered="false" style="margin-top: 24px" title="流程进度">
|
||||
<a-steps :direction="isMobile && 'vertical' || 'horizontal'" :current="stepsCount" progressDot>
|
||||
<a-step v-for="item in steps" :key="item.key">
|
||||
<template v-slot:title>
|
||||
<span>{{ item.name }}</span>
|
||||
</template>
|
||||
<template v-slot:description>
|
||||
<div class="antd-pro-pages-profile-advanced-style-stepDescription">
|
||||
{{ item.user }}<br/>
|
||||
<div style="display:inline;font-size: 12px;">{{ item.created_at }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-step>
|
||||
</a-steps>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { baseMixin } from '@/store/app-mixin'
|
||||
export default {
|
||||
name: 'Steps',
|
||||
mixins: [baseMixin],
|
||||
props: {
|
||||
stepsCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
steps: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
},
|
||||
deactivated () {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
</style>
|
||||
169
src/components/OrderDetailInfo/OrganizationBankInfo.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<!-- 用户实名信息 -->
|
||||
<a-card :title="`机构信息 (${institution.business} ${institution.business_type})`" style="margin-top:24px;">
|
||||
<a-card-meta style="padding-bottom: 20px;">
|
||||
<template slot="title">
|
||||
<div class="flex-sb">
|
||||
<div v-if="institution.institution_name">机构名称2:<span style="font-size:16px;color:#1890ff;">{{ `${institution.institution_name}` }}</span></div>
|
||||
<div>机构名称:{{ `${institution.institution}` }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-card-meta>
|
||||
<template #extra>
|
||||
<a class="active" v-if="can.institution_name" style="margin-left:10px;padding-right:10px;" @click="visible = true; changeOrgName = institution.institution_name || ''">
|
||||
<span style="margin-left:20px;"><a-icon :type="resetEdit ? 'edit' : 'edit'" />变更机构</span>
|
||||
</a>
|
||||
<a-divider type="vertical" v-if="can.institution_name" />
|
||||
<a @click="resetEdit = !resetEdit, rejectEdit = true" v-if="can.institution" >
|
||||
<span style="margin-left:20px;"><a-icon :type="resetEdit ? 'edit' : 'edit'" />{{ resetEdit ? '修改信息' : '取消修改' }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<a-descriptions
|
||||
layout="horizontal"
|
||||
size="middle"
|
||||
:bordered="true"
|
||||
:column="{ xxl: 4, xl: 4, lg: 4, md: 1, sm: 1, xs: 1 }">
|
||||
<a-descriptions-item
|
||||
v-for="item in institution.bank"
|
||||
:key="item.key"
|
||||
:label="item.title"
|
||||
:span="2">
|
||||
<!-- 其他类 -->
|
||||
<div class="row jc_sb">
|
||||
{{ item.value_text || '--' }}
|
||||
<ItemPopover
|
||||
:rejectEdit="rejectEdit"
|
||||
:resetEdit="resetEdit"
|
||||
type="bank"
|
||||
:id="{ 'item_id': itemId, 'order_id': orderId }"
|
||||
:item="item" />
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<a-modal
|
||||
v-model="visible"
|
||||
title="变更结构名称"
|
||||
@ok="handleOk"
|
||||
>
|
||||
<a-textarea placeholder="修改机构名称" :rows="4" v-model="changeOrgName" />
|
||||
</a-modal>
|
||||
</a-card>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
import { institutionEdit } from '@/api/order'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'OrganizationBankInfo',
|
||||
props: {
|
||||
institution: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
IdCardVisible: false,
|
||||
idCardType: 'zheng',
|
||||
idCardImageValue: '',
|
||||
loaded: {},
|
||||
rejectEdit: true,
|
||||
resetEdit: true,
|
||||
info: {
|
||||
value: {}
|
||||
},
|
||||
canSend: false,
|
||||
visible: false, // 展示弹窗修改机构名称
|
||||
changeOrgName: ''// (更改后机构名称)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 修改机构名称
|
||||
handleOk () {
|
||||
institutionEdit(this.itemId, { institution_name: this.changeOrgName }).then(res => {
|
||||
this.visible = false
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
.flex-sb{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
color:#666;
|
||||
}
|
||||
</style>
|
||||
224
src/components/OrderDetailInfo/OrganizationInfoFollow.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 用户实名信息 -->
|
||||
<a-card :bordered="false" style="margin-top: 24px" title="机构跟进记录">
|
||||
<template #extra>
|
||||
<a @click="addOpreation()" v-if="can.log" ><span>添加记录<a-icon type="plus" color="#1890ff" /></span></a>
|
||||
<a @click="addOpreation()" v-else ><span>查看记录</span></a>
|
||||
<a-divider style="margin-left:20px;" type="vertical" v-if="systemLogs.length > 1 || userLogs.length > 1" />
|
||||
<a class="seeMore" style="margin-left:20px;" v-if="systemLogs.length > 1 || userLogs.length>1" >
|
||||
<a class="more" @click="showAll = !showAll">{{ !showAll ? '展开' : '收起' }}<a-icon :type="!showAll ? 'down' : 'up'" color="#1890ff" /></a>
|
||||
</a>
|
||||
</template>
|
||||
<div class="logsContent" >
|
||||
<div class="logsContentTitle"><div class="logs-item-title">客户展示</div><div class="logs-item-title">系统展示</div></div>
|
||||
<!-- 展示多条 -->
|
||||
<div v-if="showAll" class="logs" :style="!showAll ? 'height:100px;' : 'max-height:500px;'">
|
||||
<a-timeline class="logsItem" v-if="userLogs.length>0">
|
||||
<a-timeline-item v-for="item in userLogs" :key="item.log_id">
|
||||
<div class="title">{{ item.description }}
|
||||
<div class="create-time"> {{ item.operate.name }} ({{ item.operate.type }}) {{ item.created_at }}</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
<div class="logsItem" v-else>暂无数据~</div>
|
||||
<a-timeline class="logsItem" v-if="systemLogs.length > 0">
|
||||
<a-timeline-item v-for="item in systemLogs" :key="item.log_id">
|
||||
<div class="title">{{ item.description }}
|
||||
<div class="create-time">{{ item.operate.name }} ({{ item.operate.type }}) {{ item.created_at }}</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
<div class="logsItem" v-else>暂无数据~</div>
|
||||
</div>
|
||||
<!-- 只展示一条 -->
|
||||
<div class="logsContent" v-if="!showAll">
|
||||
<div class="logs" :style="!showAll ? 'height:100px;' : 'max-height:500px;'">
|
||||
<a-timeline class="logsItem">
|
||||
<a-timeline-item v-if="userLogs.length > 0">
|
||||
<div class="title"> {{ userLogs[0].description }}
|
||||
<div class="create-time">{{ userLogs[0].operate.name }} ({{ userLogs[0].operate.type }}) {{ userLogs[0].created_at }}</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
<div class="logsItem" v-else>暂无数据~</div>
|
||||
</a-timeline>
|
||||
<a-timeline class="logsItem">
|
||||
<a-timeline-item v-if="systemLogs.length > 0">
|
||||
<div class="title">{{ systemLogs[0].description }}
|
||||
<div class="create-time">{{ systemLogs[0].operate.name }} ({{ systemLogs[0].operate.type }}) {{ systemLogs[0].created_at }}</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
<div class="logsItem" v-else>暂无数据~</div>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</div>
|
||||
<div class="logsseeMore" v-if="userLogs.length > 1 || systemLogs.length>1" >
|
||||
<a class="more" @click="showAll = !showAll">{{ !showAll ? '展开' : '收起' }}<a-icon :type="!showAll ? 'down' : 'up'" color="#1890ff" /></a>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'OrganizationInfoFollow',
|
||||
props: {
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
systemLogs: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
userLogs: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showAll: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 新增记录
|
||||
addOpreation () {
|
||||
this.$router.push({
|
||||
name: 'OperationList',
|
||||
params: {
|
||||
itemId: this.itemId,
|
||||
orderId: this.orderId
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
.seeMore{
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.logsseeMore{
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
bottom:-20px;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.logsContent{
|
||||
position: relative;
|
||||
.logsContentTitle{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.logs-item-title{
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
color:#222;
|
||||
padding-bottom: 10px;
|
||||
&:nth-child(2){
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.logs{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
overflow-y:scroll;
|
||||
overflow:scroll;
|
||||
padding-top: 20px;
|
||||
|
||||
.logs-item{
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
&:nth-child(2){
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
.logsItem{
|
||||
flex: 50%;
|
||||
&:nth-child(2){
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.title{
|
||||
width: 100%;
|
||||
}
|
||||
.create-time{
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
151
src/components/OrderDetailInfo/OrganizationRealNames.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 用户实名信息 -->
|
||||
<a-card :bordered="false" style="margin-top: 24px" title="用户基础信息">
|
||||
<template #extra>
|
||||
<!-- v-if="can.check" -->
|
||||
<!-- <a class="active" @click="rejectEdit = !rejectEdit,resetEdit = true" >
|
||||
<a-icon :type="rejectEdit ? 'undo' : 'undo'" color="green" />
|
||||
{{ rejectEdit ? '驳回信息' : '取消驳回' }}
|
||||
</a> -->
|
||||
<a @click="resetEdit = !resetEdit, rejectEdit= true" v-if="can.userbase" >
|
||||
<a-divider type="vertical" />
|
||||
<span style="margin-left:20px;padding-right:20px;"><a-icon :type="resetEdit ? 'edit' : 'edit'"/>
|
||||
{{ resetEdit ? '修改信息' : '取消修改' }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<a-descriptions
|
||||
layout="horizontal"
|
||||
size="middle"
|
||||
:bordered="true"
|
||||
:column="{ xxl: 4, xl: 4, lg: 4, md: 1, sm: 1, xs: 1 }"
|
||||
>
|
||||
<a-descriptions-item
|
||||
v-for="item in info.value"
|
||||
:key="item.key"
|
||||
:label="item.title"
|
||||
:span="2"
|
||||
>
|
||||
<!-- 图片展示 -->
|
||||
<div class="row jc_sb" v-if="item.key == 'front_card' || item.key == 'back_card'">
|
||||
<span href="" @click="seeImg(item.key == 'front_card' ? 'zheng' : 'fan', item.value)">查看</span>
|
||||
<ItemPopover
|
||||
type="user"
|
||||
:item="item"
|
||||
:resetEdit="resetEdit"
|
||||
:rejectEdit="rejectEdit"
|
||||
:id="{'item_id':info.business_order_user_id,'order_id': orderId }" />
|
||||
</div>
|
||||
<!-- 其他类 -->
|
||||
<div v-else class="row jc_sb">
|
||||
{{ item.value_text || '--' }}
|
||||
<ItemPopover
|
||||
type="user"
|
||||
:item="item"
|
||||
:resetEdit="resetEdit"
|
||||
:rejectEdit="rejectEdit"
|
||||
:id="{'item_id':info.business_order_user_id,'order_id': orderId }" />
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
<!-- 展示身份证 -->
|
||||
<a-modal
|
||||
:title="idCardType === 'zheng' ? '身份证正面展示' : '身份证反面展示'"
|
||||
@cancel="IdCardVisible = false"
|
||||
:visible="IdCardVisible"
|
||||
@ok="IdCardVisible = false"
|
||||
:maskClosable="true"
|
||||
>
|
||||
<div v-if="idCardImageValue">
|
||||
<img :src="idCardImageValue" style="width: 100%" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'OrganizationRealName',
|
||||
props: {
|
||||
info: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
IdCardVisible: false,
|
||||
idCardType: 'zheng',
|
||||
idCardImageValue: '',
|
||||
rejectEdit: true,
|
||||
resetEdit: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 预览图片
|
||||
seeImg (type, item) {
|
||||
this.IdCardVisible = true
|
||||
this.idCardType = type
|
||||
this.idCardImageValue = item
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
139
src/components/OrderDetailInfo/OrganizationSchemes.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<!--
|
||||
* @Author: Aimee~
|
||||
* @Date: 2023-05-11 12:02:45
|
||||
* @LastEditTime: 2023-07-05 10:04:59
|
||||
* @LastEditors: Aimee
|
||||
* @FilePath: /douhuo-agent/src/components/OrderDetailInfo/OrganizationSchemes.vue
|
||||
* @Description:预估方案和结案方案一同处理
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<a-card :bordered="false" v-if="schemes[0]" style="margin-top: 24px" :title="`预估方案 (${schemes[0].business_type.title})`">
|
||||
<template #extra v-if="closeScheme == '{}'">
|
||||
<a @click.stop="surePlan"><span>新增结案方案</span></a>
|
||||
</template>
|
||||
<a-descriptions
|
||||
layout="horizontal"
|
||||
size="middle"
|
||||
:bordered="true"
|
||||
:column="{ xxl: 4, xl: 4, lg: 4, md: 1, sm: 1, xs: 1 }"
|
||||
>
|
||||
<a-descriptions-item
|
||||
v-for="item in schemes[0].params"
|
||||
:key="item.key"
|
||||
:label="item.title"
|
||||
:span="2"
|
||||
>
|
||||
<div class="row jc_sb">{{ item.value || '--' }}</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
<a-card :bordered="false" v-if="closeScheme != '{}'&& closeScheme.status" style="margin-top: 24px" :title="`结案方案 (${closeScheme.status.text})`">
|
||||
<template #extra >
|
||||
<a @click.stop="surePlan"><span>查看结案方案</span></a>
|
||||
</template>
|
||||
<a-descriptions
|
||||
layout="horizontal"
|
||||
size="middle"
|
||||
:bordered="true"
|
||||
:column="{ xxl: 4, xl: 4, lg: 4, md: 1, sm: 1, xs: 1 }"
|
||||
>
|
||||
<a-descriptions-item
|
||||
v-for="item in closeScheme.params"
|
||||
:key="item.key"
|
||||
:label="item.title"
|
||||
:span="2"
|
||||
>
|
||||
<div class="row jc_sb">{{ item.value || '--' }}</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'OrganizationSchemes',
|
||||
props: {
|
||||
schemes: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
closeScheme: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
surePlan () {
|
||||
this.$router.push({
|
||||
name: 'ConfirmPlan',
|
||||
params: {
|
||||
itemId: this.itemId,
|
||||
orderId: this.orderId
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
629
src/components/OrderDetailInfo/OrganizationServiceInfo.vue
Normal file
@@ -0,0 +1,629 @@
|
||||
<template>
|
||||
<div v-if="services">
|
||||
<!-- 服务包信息 -->
|
||||
<a-card
|
||||
:bordered="false"
|
||||
style="margin-top: 24px"
|
||||
:title="`服务包信息 下单时间:(${ services.paid_at })`"
|
||||
>
|
||||
<template #extra>
|
||||
<a
|
||||
@click="refresh"
|
||||
style="margin-right:20px;margin-left:20px;"
|
||||
><a-icon type="sync" /></a>
|
||||
<span v-if="(base.unpay > 0)">
|
||||
<span style="color:#ff4d4f;">共1条待补差价 </span>
|
||||
<a-tooltip>
|
||||
<template slot="title">发起了补差价,等待用户完成补差价操作才可以处理其他事项!</template>
|
||||
<a-icon
|
||||
type="info-circle"
|
||||
:style="{ fontSize: '16px', color: '#ff4d4f', padding: '0 0 0 10px' }"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a
|
||||
class="active"
|
||||
@click="payDiff({ id: itemId })"
|
||||
v-if="can.diff && (base.unpay == 0)"
|
||||
><a-icon
|
||||
type="red-envelope"
|
||||
color="green"
|
||||
/>补差价</a>
|
||||
</template>
|
||||
<a-descriptions>
|
||||
<a-descriptions-item label="归属工作室">{{ services.center || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="顾问">{{ services.parent }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<!-- 服务包信息 -->
|
||||
<a-table
|
||||
:rowKey="(record, index) => index"
|
||||
:bordered="true"
|
||||
size="middle"
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 1500, y: 400 }"
|
||||
:data-source="services.data"
|
||||
>
|
||||
<!-- 订单编号 -->
|
||||
<span slot="order_no">{{ services.order_no }}</span>
|
||||
<!-- 服务包总金额 -->
|
||||
<span slot="amount" slot-scope="text, record">¥{{ record.amount || '0.00' }}</span>
|
||||
|
||||
<!-- 机构2名称 -->
|
||||
<span slot="institution_title" slot-scope="text, record">{{ record.institution_title || '-' }}</span>
|
||||
|
||||
<!-- 状态2名称 -->
|
||||
<span slot="status_two_text" slot-scope="text, record">{{ record.status_two_text || '-' }}</span>
|
||||
|
||||
<!-- 退款金额 -->
|
||||
<span
|
||||
slot="refund_total"
|
||||
slot-scope="text, record"
|
||||
>
|
||||
<!-- 可编辑 -->
|
||||
<a-input
|
||||
v-if="record.editable && services.can_price"
|
||||
prefix="¥"
|
||||
v-model="editValue.refund_total"
|
||||
/>
|
||||
<!-- 不编辑 -->
|
||||
<span v-else>¥{{ record.refund_total || '0.00' }}</span>
|
||||
</span>
|
||||
<!-- 欠款金额 -->
|
||||
<span
|
||||
slot="price"
|
||||
slot-scope="text, record"
|
||||
>
|
||||
<!-- 可编辑 -->
|
||||
<a-input
|
||||
v-if="record.editable && services.can_price"
|
||||
prefix="¥"
|
||||
v-model="editValue.price"
|
||||
/>
|
||||
<!-- 不编辑 -->
|
||||
<span v-else>¥{{ record.price || '0.00' }}</span>
|
||||
</span>
|
||||
<!-- 匹配额度 -->
|
||||
<span
|
||||
slot="allocation"
|
||||
slot-scope="text, record"
|
||||
>
|
||||
<!-- 可编辑 -->
|
||||
<a-input
|
||||
v-if="record.editable && services.can_price"
|
||||
prefix="¥"
|
||||
v-model="editValue.allocation"
|
||||
/>
|
||||
<!-- 不编辑 -->
|
||||
<span v-else>¥{{ record.allocation || '0.00' }}</span>
|
||||
</span>
|
||||
<!-- 时效 -->
|
||||
<span
|
||||
slot="prescription"
|
||||
slot-scope="text, record"
|
||||
> {{ record.prescription>0 ? record.prescription + '天' : '-' }}</span>
|
||||
|
||||
<!-- 申请时间 -->
|
||||
<div
|
||||
slot="audit_at"
|
||||
slot-scope="text, record"
|
||||
>
|
||||
|
||||
<!-- 可编辑 -->
|
||||
<a-date-picker
|
||||
v-if="record.editable && services.can_audit_settle_time"
|
||||
:default-value="record.audit_at != '' ? moment(record.audit_at, dateFormat) : ''"
|
||||
placeholder="选择申请时间"
|
||||
@change="dateChange('audit_at', $event)"
|
||||
/>
|
||||
<!-- 不编辑 -->
|
||||
<span v-else><span>{{ record.audit_at || '-' }}</span></span>
|
||||
</div>
|
||||
|
||||
<!-- 结案时间 -->
|
||||
<div
|
||||
slot="settle_at"
|
||||
slot-scope="text, record"
|
||||
>
|
||||
<!-- 可编辑 -->
|
||||
<a-date-picker
|
||||
v-if="record.editable && services.can_audit_settle_time"
|
||||
:default-value="record.settle_at !='' ? moment(record.settle_at, dateFormat) : ''"
|
||||
placeholder="选择结案时间"
|
||||
@change="dateChange('settle_at', $event)"
|
||||
/>
|
||||
<!-- 不编辑 -->
|
||||
<span v-else ><span>{{ record.settle_at || '-' }}</span></span>
|
||||
</div>
|
||||
<!-- 机构名称2 -->
|
||||
<!-- <span
|
||||
slot="institution_name"
|
||||
slot-scope="text, record"
|
||||
>{{ record.institution_name || '-' }}</span> -->
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div
|
||||
slot="actions"
|
||||
slot-scope="text, record, index"
|
||||
>
|
||||
<a
|
||||
v-if="!record.editable"
|
||||
@click="() => editService(record.item_id, index)"
|
||||
>编辑</a>
|
||||
<template v-else>
|
||||
<a @click="() => cancelService(record.item_id, index)">取消</a>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="() => editServiceInfo(record.item_id, index)">保存</a>
|
||||
</template>
|
||||
</div>
|
||||
</a-table>
|
||||
|
||||
<div style="display:flex;margin-top: 30px;">
|
||||
补差价次数:<span style="margin-right:30px;color:#1890ff;">{{ base.count }}次</span>
|
||||
待补差价:<span style="margin-right:30px;color:#1890ff;">¥{{ base.unpay }}</span>
|
||||
已补差价:<span style="margin-right:30px;color:#1890ff;">¥{{ base.paid }}</span>
|
||||
服务包金额:<span style="margin-right:30px;color:#1890ff;">¥{{ base.total }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a-timeline :reverse="true">
|
||||
<a-timeline-item
|
||||
v-for="item in diffsList"
|
||||
:key="item.diff_id"
|
||||
>
|
||||
<a-card
|
||||
:bordered="true"
|
||||
style="margin-top: 24px"
|
||||
:title="item.status"
|
||||
>
|
||||
<template #extra>
|
||||
<a-popconfirm
|
||||
v-if="item.is_delete"
|
||||
title="是否确认撤回该条补差价?"
|
||||
ok-text="确认"
|
||||
cancel-text="取消"
|
||||
@confirm="diffBack(item.diff_id)"
|
||||
>
|
||||
<a> <a-icon
|
||||
type="delete"
|
||||
:style="{ fontSize: '14px', color: '#1890ff', padding: '6px 6px 6px 0' }"
|
||||
/>撤回补差价</a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
<a-descriptions>
|
||||
<a-descriptions-item label="创建时间"> {{ item.created_at }}</a-descriptions-item>
|
||||
<a-descriptions-item label="操作人 ">{{ item.operate.name }}({{ item.operate.type }})</a-descriptions-item>
|
||||
<a-descriptions-item label="操作类型 ">发起<a>{{ item.ins != '' ? '机构' : '服务包' }}</a>补差价</a-descriptions-item>
|
||||
<a-descriptions-item
|
||||
label="操作机构"
|
||||
v-if="item.ins != ''"
|
||||
>{{ item.ins }}</a-descriptions-item>
|
||||
<a-descriptions-item label="补差金额"> ¥{{ item.price }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注原因"> {{ item.remark }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
|
||||
<!-- 备注 -->
|
||||
<div class="or-remark">
|
||||
<H4>备注:</H4>
|
||||
<div
|
||||
style="flex:1;"
|
||||
v-if="canRemark"
|
||||
>
|
||||
{{ remark }} <a-icon
|
||||
@click="remarkNew = remark, canRemark = false"
|
||||
type="edit"
|
||||
:style="{ fontSize: '15px', color: '#1890ff',padding:'0 14px' }"
|
||||
/>
|
||||
</div>
|
||||
<a-textarea
|
||||
v-else
|
||||
class="or-remark-inpu"
|
||||
v-model="remarkNew"
|
||||
placeholder="备注:对订单服务包进行的备注说明"
|
||||
:auto-size="{ minRows: 5, maxRows: 7 }"
|
||||
>
|
||||
</a-textarea>
|
||||
</div>
|
||||
<a-button
|
||||
v-if="!canRemark"
|
||||
style="margin-left:50px;margin-top:10px;"
|
||||
type="primary"
|
||||
@click="sureRemark"
|
||||
>确认修改 </a-button>
|
||||
</a-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
import { remark, editServiceInfo } from '@/api/organization'
|
||||
import moment from 'moment'
|
||||
import PayDifference from '@/components/OrderDetailInfo/modules/PayDifference.vue'
|
||||
import { getAllBanks, diffPayList, diffBack } from '@/api/order'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'OrganizationServiceInfo',
|
||||
props: {
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
orderId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
services: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
remark: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
title: '订单编号',
|
||||
scopedSlots: { customRender: 'order_no' },
|
||||
customRender: (value, row, index) => {
|
||||
const obj = {
|
||||
children: `${this.services.order_no}`,
|
||||
attrs: {}
|
||||
}
|
||||
if (index === 0) {
|
||||
obj.attrs.rowSpan = this.services.data.length // 合并数量 纵向合并
|
||||
// obj.attrs.colSpan = 3 // 横向合并
|
||||
}
|
||||
if (index >= 1) {
|
||||
obj.attrs.rowSpan = 0 // 合并数量 纵向合并
|
||||
// obj.attrs.colSpan = 0 // 横向合并
|
||||
}
|
||||
return obj
|
||||
},
|
||||
width: 150,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '机构名称',
|
||||
dataIndex: 'title',
|
||||
width: 140,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '机构名称2',
|
||||
scopedSlots: { customRender: 'institution_title' },
|
||||
width: 140,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '机构状态',
|
||||
width: 110,
|
||||
dataIndex: 'status_text',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '机构状态2',
|
||||
width: 110,
|
||||
scopedSlots: { customRender: 'status_two_text' },
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '订单金额',
|
||||
dataIndex: 'total',
|
||||
align: 'center',
|
||||
width: 220,
|
||||
customRender: (value, row, index) => {
|
||||
const obj = {
|
||||
children: this.$createElement(
|
||||
'div',
|
||||
[
|
||||
this.$createElement('div'),
|
||||
'服务包总金额:¥' + this.services.order_total,
|
||||
this.$createElement('div'),
|
||||
'服务包现金:¥' + this.services.total,
|
||||
this.$createElement('div'),
|
||||
'服务包火力值:¥' + this.services.fire,
|
||||
this.$createElement('div'),
|
||||
'补差价总额:¥' + this.services.diff_total,
|
||||
this.$createElement('div'),
|
||||
'补差价现金:¥' + this.services.diff_cash,
|
||||
this.$createElement('div'),
|
||||
'补差价火力值:¥' + this.services.diff_fire,
|
||||
this.$createElement('div'),
|
||||
'退款总额:¥' + this.services.refund_fire
|
||||
]
|
||||
),
|
||||
attrs: {}
|
||||
}
|
||||
if (index === 0) {
|
||||
obj.attrs.rowSpan = this.services.data.length // 合并数量 纵向合并
|
||||
// obj.attrs.colSpan = 3 // 横向合并
|
||||
}
|
||||
if (index >= 1) {
|
||||
obj.attrs.rowSpan = 0 // 合并数量 纵向合并
|
||||
// obj.attrs.colSpan = 0 // 横向合并
|
||||
}
|
||||
return obj
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '服务包金额',
|
||||
width: 110,
|
||||
scopedSlots: { customRender: 'amount' },
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '退款金额',
|
||||
width: 110,
|
||||
scopedSlots: { customRender: 'refund_total' },
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '欠款金额',
|
||||
width: 110,
|
||||
scopedSlots: { customRender: 'price' },
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '匹配额度',
|
||||
width: 110,
|
||||
scopedSlots: { customRender: 'allocation' },
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '申请时间',
|
||||
scopedSlots: { customRender: 'audit_at' },
|
||||
width: 160,
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '结案时间',
|
||||
scopedSlots: { customRender: 'settle_at' },
|
||||
width: 160,
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '处理时效',
|
||||
scopedSlots: { customRender: 'prescription' },
|
||||
width: 120,
|
||||
align: 'center'
|
||||
}, {
|
||||
title: '操作',
|
||||
scopedSlots: { customRender: 'actions' },
|
||||
align: 'center',
|
||||
width: 120
|
||||
}
|
||||
],
|
||||
editValue: { // 编辑时的基本信息
|
||||
audit_at: '', // 申请时间
|
||||
settle_at: '', // 结案时间
|
||||
price: '', // 欠款金额
|
||||
refund_total: '', // 退款金额
|
||||
allocation: '' // 匹配金额
|
||||
},
|
||||
remarkNew: '',
|
||||
canRemark: true,
|
||||
editingKey: '', // 服务包修改申请时间,结案时间 的id
|
||||
dateFormat: 'YYYY/MM/DD',
|
||||
banks: [], // 活的所有机构列表
|
||||
diffsList: [], // 补差价列表
|
||||
base: '' // 补差价基本信息
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getPayDiff()
|
||||
},
|
||||
activated () {
|
||||
this.getPayDiff()
|
||||
},
|
||||
methods: {
|
||||
moment,
|
||||
// 点击编辑服务包
|
||||
editService (id) {
|
||||
const newData = [...this.services.data]
|
||||
const target = newData.find(item => id === item.item_id)
|
||||
// 有 key 意味着第二次以上的选择编辑要进行判断,判断是否有,还是上次点击遗留下来的数据,然后再清空和赋值
|
||||
if (this.editingKey !== id && this.editingKey !== '') {
|
||||
const targetOld = newData.find(item => this.editingKey === item.item_id)
|
||||
if (targetOld) {
|
||||
this.editValue = {
|
||||
audit_at: '', // 申请时间
|
||||
settle_at: '', // 结案时间
|
||||
price: '', // 欠款金额
|
||||
allocation: '', // 匹配金额
|
||||
refund_total: '' // 退款金额
|
||||
}
|
||||
targetOld.editable = false
|
||||
}
|
||||
this.editingKey = id
|
||||
} else {
|
||||
// 第一次选择编辑直接赋值
|
||||
this.editingKey = id
|
||||
}
|
||||
if (target) {
|
||||
target.editable = true
|
||||
this.editValue = {
|
||||
audit_at: target.audit_at, // 申请时间
|
||||
settle_at: target.settle_at, // 结案时间
|
||||
price: target.price, // 欠款金额
|
||||
allocation: target.allocation, // 匹配金额
|
||||
refund_total: target.refund_total // 退款金额
|
||||
}
|
||||
this.services.data = newData
|
||||
}
|
||||
},
|
||||
// 取消编辑服务包
|
||||
cancelService (id) {
|
||||
const newData = [...this.services.data]
|
||||
const target = newData.find(item => id === item.item_id)
|
||||
this.editingKey = ''
|
||||
if (target) {
|
||||
target.editable = false
|
||||
this.editValue = {
|
||||
audit_at: '', // 申请时间
|
||||
settle_at: '', // 结案时间
|
||||
price: '', // 欠款金额
|
||||
allocation: '', // 匹配金额
|
||||
refund_total: '' // 退款金额
|
||||
}
|
||||
this.services.data = newData
|
||||
}
|
||||
// 需要刷新一下接口,
|
||||
},
|
||||
/**
|
||||
* 保存服务包
|
||||
* @param {*} id 机构 id
|
||||
*/
|
||||
editServiceInfo (id) {
|
||||
editServiceInfo(this.editingKey, this.editValue).then(res => {
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.cancelService(this.editingKey)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 确认选择了年月日时分秒
|
||||
* @param {*} type 当前修改类型
|
||||
* @param {*} value 日期返回值
|
||||
*/
|
||||
dateChange (type, value) {
|
||||
this.editValue[`${type}`] = moment(value).format('YYYY-MM-DD')
|
||||
},
|
||||
// 新添加备注信息
|
||||
sureRemark () {
|
||||
remark(this.itemId, {
|
||||
remark: this.remarkNew
|
||||
}).then(res => {
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.canRemark = true
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
// 补差价处理弹窗
|
||||
payDiff (item) {
|
||||
// 获得所有机构信息
|
||||
getAllBanks(this.orderId).then(res => {
|
||||
console.log(res)
|
||||
item.banks = res
|
||||
item.id = this.orderId
|
||||
this.$dialog(
|
||||
PayDifference,
|
||||
{
|
||||
item,
|
||||
on: {
|
||||
ok: () => {
|
||||
this.refresh()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '给服务包/机构补差价',
|
||||
width: 500,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认补差价',
|
||||
cancelText: '取消'
|
||||
}
|
||||
)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
refresh () {
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.getPayDiff()
|
||||
},
|
||||
// 获得补差价列表
|
||||
getPayDiff () {
|
||||
diffPayList(this.orderId).then(res => {
|
||||
this.diffsList = res.lists
|
||||
this.base = res.base
|
||||
}).catch(err => {
|
||||
this.$error(err.message)
|
||||
})
|
||||
},
|
||||
// 撤回补差价
|
||||
diffBack (id) {
|
||||
diffBack(this.orderId, id).then(res => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '操作成功!'
|
||||
})
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.getPayDiff()
|
||||
}).catch(err => {
|
||||
this.$error(err.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
.or-remark {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
margin-top: 30px;
|
||||
.or-remark-input {
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
}
|
||||
h4 {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
211
src/components/OrderDetailInfo/RealName.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div v-if="loaded">
|
||||
<!-- 用户实名信息 -->
|
||||
<a-card :bordered="false" style="margin-top: 24px" title="用户基础信息">
|
||||
<template #extra>
|
||||
<span v-if="canSend">
|
||||
<a style="margin-right:20px;" type="primary" @click="seedMessage(info)" >发送通知</a>
|
||||
<a-divider type="vertical" />
|
||||
</span>
|
||||
<span style="margin-right:20px;" v-if="(count>0)">
|
||||
<span style="color:#ff4d4f;"> 共{{ count }}条驳回待审</span>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
有信息被驳回,请先审核通过!
|
||||
</template>
|
||||
<a-icon type="info-circle" :style="{ fontSize: '16px', color: '#ff4d4f',padding:'0 20px 0 10px' }" />
|
||||
</a-tooltip>
|
||||
<a-divider type="vertical" />
|
||||
</span>
|
||||
<a class="active" @click="rejectEdit = !rejectEdit,resetEdit = true" v-if="can.check">
|
||||
<a-icon :type="rejectEdit ? 'undo' : 'undo'" color="green" />
|
||||
{{ rejectEdit ? '驳回信息' : '取消驳回' }}
|
||||
</a>
|
||||
<a @click="resetEdit = !resetEdit, rejectEdit= true" v-if="can.update">
|
||||
<a-divider type="vertical" />
|
||||
<span style="margin-left:20px;padding-right:20px;"><a-icon :type="resetEdit ? 'edit' : 'edit'"/>
|
||||
{{ resetEdit ? '修改信息' : '取消修改' }}</span>
|
||||
</a>
|
||||
</template>
|
||||
<a-descriptions
|
||||
layout="horizontal"
|
||||
size="middle"
|
||||
:bordered="true"
|
||||
:column="{ xxl: 4, xl: 4, lg: 4, md: 1, sm: 1, xs: 1 }"
|
||||
>
|
||||
<a-descriptions-item
|
||||
v-for="item in info.value"
|
||||
:key="item.business_order_user_id"
|
||||
:label="item.title"
|
||||
:span="2"
|
||||
>
|
||||
<!-- 图片展示 -->
|
||||
<div class="row jc_sb" v-if="item.key == 'front_card' || item.key == 'back_card'">
|
||||
<span href="" @click="seeImg(item.key == 'front_card' ? 'zheng' : 'fan', item.value)">查看</span>
|
||||
<ItemPopover
|
||||
type="user"
|
||||
:item="item"
|
||||
:resetEdit="resetEdit"
|
||||
:rejectEdit="rejectEdit"
|
||||
:id="{'item_id':info.business_order_user_id,'order_id':id}" />
|
||||
</div>
|
||||
<!-- 其他类 -->
|
||||
<div v-else class="row jc_sb">
|
||||
{{ item.value_text || '--' }}
|
||||
<ItemPopover
|
||||
type="user"
|
||||
:item="item"
|
||||
:resetEdit="resetEdit"
|
||||
:rejectEdit="rejectEdit"
|
||||
:id="{'item_id':info.business_order_user_id,'order_id':id}" />
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
<!-- 展示身份证 -->
|
||||
<a-modal
|
||||
:title="idCardType === 'zheng' ? '身份证正面展示' : '身份证反面展示'"
|
||||
@cancel="IdCardVisible = false"
|
||||
:visible="IdCardVisible"
|
||||
@ok="IdCardVisible = false"
|
||||
:maskClosable="true"
|
||||
>
|
||||
<div v-if="idCardImageValue">
|
||||
<img :src="idCardImageValue" style="width: 100%" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { realName } from '@/api/order'
|
||||
import { sendMessage } from '@/api/notice'
|
||||
import ItemPopover from './modules/ItemPopover.vue'
|
||||
export default {
|
||||
components: {
|
||||
ItemPopover
|
||||
},
|
||||
name: 'RealName',
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
IdCardVisible: false,
|
||||
idCardType: 'zheng',
|
||||
idCardImageValue: '',
|
||||
loaded: {},
|
||||
rejectEdit: true,
|
||||
resetEdit: true,
|
||||
info: {
|
||||
value: {}
|
||||
},
|
||||
canSend: false
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
this.getInfo()
|
||||
// 接受传参
|
||||
this.eventBus.$on('editRealName', (res) => {
|
||||
console.log('editRealName')
|
||||
this.rejectEdit = true
|
||||
this.resetEdit = true
|
||||
this.getInfo()
|
||||
})
|
||||
},
|
||||
deactivated () {
|
||||
this.eventBus.$off('editRealName')
|
||||
},
|
||||
methods: {
|
||||
// 获取用户基本信息
|
||||
getInfo () {
|
||||
realName(this.id)
|
||||
.then((res) => {
|
||||
this.info = res
|
||||
this.canSend = res.can.send
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
})
|
||||
.finally((er) => {
|
||||
this.loaded = true
|
||||
})
|
||||
},
|
||||
// 预览图片
|
||||
seeImg (type, item) {
|
||||
this.IdCardVisible = true
|
||||
this.idCardType = type
|
||||
this.idCardImageValue = item
|
||||
},
|
||||
// 发送信息
|
||||
seedMessage (item) {
|
||||
sendMessage(this.id, 1, item.business_order_user_id).then(res => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '发送消息成功!'
|
||||
})
|
||||
this.getInfo()
|
||||
}).catch(err => {
|
||||
this.$notification.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
.a-des-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
.pl50 {
|
||||
margin-left: 50px;
|
||||
}
|
||||
.inputT {
|
||||
flex: 1;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
224
src/components/OrderDetailInfo/Services.vue
Normal file
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-card :bordered="true" style="margin-top: 24px" title="匹配的服务包">
|
||||
<template #extra>
|
||||
<a @click="refresh" style="margin-right:20px;margin-left:20px;"><a-icon type="sync" /></a>
|
||||
<span v-if="(count>0)">
|
||||
<span style="color:#ff4d4f;">共{{ count }}条待补差价 </span>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
发起了补差价,等待用户完成补差价操作才可以处理其他事项!
|
||||
</template>
|
||||
<a-icon type="info-circle" :style="{ fontSize: '16px', color: '#ff4d4f',padding:'0 0 0 10px' }" />
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a class="active" @click="payDiff({ id })" v-if="(can.diff && count === 0)">
|
||||
<a-icon type="red-envelope" color="green" />补差价
|
||||
</a>
|
||||
</template>
|
||||
<s-table
|
||||
ref="table"
|
||||
:columns="columns"
|
||||
:data="loadData"
|
||||
:rowKey="(row) => row.group_no"
|
||||
showPagination="auto"
|
||||
size="default"
|
||||
:expandRowByClick="true"
|
||||
>
|
||||
<span slot="price" slot-scope="text, record"> ¥{{ record.price }}</span>
|
||||
<span slot="total" slot-scope="text, record"> ¥{{ record.total }}</span>
|
||||
<span slot="business_type" slot-scope="text, record"> {{ record.items.length || 0 }}个机构</span>
|
||||
<div slot="expandedRowRender" slot-scope="record">
|
||||
<a-descriptions
|
||||
:column="{ xxl: 3, xl: 2, lg: 2, md: 1, sm: 1, xs: 1 }"
|
||||
v-for="item in record.items"
|
||||
:key="item.item_id"
|
||||
:title="item.title"
|
||||
>
|
||||
<a-descriptions-item label="业务名称 ">{{ item.business }}</a-descriptions-item>
|
||||
<a-descriptions-item label="业务类型 ">{{ item.type }}</a-descriptions-item>
|
||||
<a-descriptions-item label="欠款金额"> ¥{{ item.price }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
</s-table>
|
||||
<br/>
|
||||
<div style="display:flex;">
|
||||
补差价次数:<span style="margin-right:30px;color:#1890ff;">{{ base.count }}次</span>
|
||||
待补差价:<span style="margin-right:30px;color:#1890ff;">¥{{ base.unpay }}</span>
|
||||
已补差价:<span style="margin-right:30px;color:#1890ff;">¥{{ base.paid }}</span>
|
||||
服务包金额:<span style="margin-right:30px;color:#1890ff;">¥{{ base.total }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a-timeline :reverse="true">
|
||||
<a-timeline-item v-for="item in diffsList" :key="item.diff_id">
|
||||
<a-card :bordered="true" style="margin-top: 24px" :title="item.status">
|
||||
<template #extra>
|
||||
<a-popconfirm v-if="item.is_delete" title="是否确认撤回该条补差价?" ok-text="确认" cancel-text="取消" @confirm="diffBack(item.diff_id)">
|
||||
<a> <a-icon type="delete" :style="{ fontSize: '14px', color: '#1890ff',padding:'6px 6px 6px 0' }" />撤回补差价</a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
<a-descriptions>
|
||||
<a-descriptions-item label="创建时间"> {{ item.created_at }}</a-descriptions-item>
|
||||
<a-descriptions-item label="操作人 ">{{ item.operate.name }}({{ item.operate.type }})</a-descriptions-item>
|
||||
<a-descriptions-item label="操作类型 ">发起<a>{{ item.ins != '' ? '机构' : '服务包' }}</a>补差价</a-descriptions-item>
|
||||
<a-descriptions-item label="操作机构" v-if="item.ins != ''">{{ item.ins }}</a-descriptions-item>
|
||||
<a-descriptions-item label="补差金额"> ¥{{ item.price }}</a-descriptions-item>
|
||||
<a-descriptions-item label="备注原因"> {{ item.remark }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
getServices,
|
||||
diffPayList,
|
||||
diffBack,
|
||||
getAllBanks
|
||||
} from '@/api/order'
|
||||
import { STable } from '@/components'
|
||||
import BankItem from './BankItem.vue'
|
||||
import PayDifference from '@/components/OrderDetailInfo/modules/PayDifference.vue'
|
||||
|
||||
const columns = [
|
||||
{ title: '服务包名称', dataIndex: 'title', key: 'title' },
|
||||
{
|
||||
title: '包含机构',
|
||||
dataIndex: 'business_type',
|
||||
key: 'business_type',
|
||||
scopedSlots: { customRender: 'business_type' }
|
||||
},
|
||||
{ title: '总欠款金额', dataIndex: 'total', key: 'total', scopedSlots: { customRender: 'total' } },
|
||||
{ title: '服务包金额', dataIndex: 'price', key: 'price', scopedSlots: { customRender: 'price' } }
|
||||
]
|
||||
export default {
|
||||
name: 'Services',
|
||||
components: {
|
||||
STable,
|
||||
BankItem
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns,
|
||||
queryParam: {},
|
||||
diffsList: [],
|
||||
base: {},
|
||||
loadData: (parameter) => {
|
||||
const requestParameters = Object.assign({}, parameter, this.queryParam)
|
||||
return getServices(this.id, requestParameters)
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getPayDiff()
|
||||
},
|
||||
activated () {
|
||||
this.$refs.table.loadData()
|
||||
this.getPayDiff()
|
||||
},
|
||||
methods: {
|
||||
refresh () {
|
||||
this.getPayDiff()
|
||||
this.$refs.table.loadData()
|
||||
},
|
||||
getPayDiff () {
|
||||
diffPayList(this.id).then(res => {
|
||||
this.diffsList = res.lists
|
||||
this.base = res.base
|
||||
}).catch(err => {
|
||||
this.$error(err.message)
|
||||
})
|
||||
},
|
||||
diffBack (id) {
|
||||
diffBack(this.id, id).then(res => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '操作成功!'
|
||||
})
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.getPayDiff()
|
||||
}).catch(err => {
|
||||
this.$error(err.message)
|
||||
})
|
||||
},
|
||||
payDiff (item) {
|
||||
console.log(item)
|
||||
// 获得所有机构信息
|
||||
getAllBanks(item.id).then(res => {
|
||||
console.log(res)
|
||||
item.banks = res
|
||||
this.$dialog(
|
||||
PayDifference,
|
||||
{
|
||||
item,
|
||||
on: {
|
||||
ok: () => {
|
||||
this.$refs.table.loadData()
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
this.getPayDiff()
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '给服务包/机构补差价',
|
||||
width: 500,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认补差价',
|
||||
cancelText: '取消'
|
||||
}
|
||||
)
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ai_start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.jc_start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.jc_sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.js_start {
|
||||
justify-content: start;
|
||||
}
|
||||
</style>
|
||||
225
src/components/OrderDetailInfo/modules/EditOrderInfo.vue
Normal file
@@ -0,0 +1,225 @@
|
||||
<!-- 驳回原因用户姓名输入 -->
|
||||
<template>
|
||||
<a-form
|
||||
ref="form"
|
||||
v-bind="formItemLayout"
|
||||
:form="form"
|
||||
>
|
||||
<a-form-item :label="item.title" >
|
||||
<!-- textarea -->
|
||||
<a-textarea
|
||||
v-if="item.type === 'textarea'"
|
||||
:rows="6"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请输入${item.title}!`, type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请输入${item.title}!`" >
|
||||
</a-textarea>
|
||||
<!-- text number mobile region-->
|
||||
<a-input
|
||||
v-if="item.type === 'password' || item.type === 'text' || item.type === 'number' || item.type == 'mobile' || item.type == 'region'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请输入${item.title}!`, type:'string'},
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请输入${item.title}!`" >
|
||||
</a-input>
|
||||
<!-- price -->
|
||||
<a-input
|
||||
v-if="item.type === 'price'"
|
||||
prefix="¥"
|
||||
suffix="RMB"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请输入${item.title}!`, type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请输入${item.title}!`" >
|
||||
</a-input>
|
||||
<!-- day -->
|
||||
<a-input
|
||||
v-if="item.type === 'day'"
|
||||
suffix="天"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请输入${item.title}!`, type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请输入${item.title}!`" >
|
||||
</a-input>
|
||||
<!-- password -->
|
||||
<!-- <a-input
|
||||
v-if="item.type === 'password'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请输入${item.title}!`, type: item.type },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请输入${item.title}!`" >
|
||||
<a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
|
||||
</a-input> -->
|
||||
<!-- select -->
|
||||
<a-select
|
||||
v-if="item.type == 'select'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请选择${item.title}!`, type: 'number' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请选择${item.title}!`"
|
||||
>
|
||||
<a-select-option v-for="(it,idx) in item.options" :key="idx" :value="idx">
|
||||
{{ it }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<!-- radio -->
|
||||
<a-radio-group
|
||||
v-if="item.type == 'radio'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请选择${item.title}!`, type: 'number' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请选择${item.title}!`"
|
||||
>
|
||||
<a-radio v-for="(it, idx) in item.options" :key="idx" :value="idx">
|
||||
{{ it }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- checkbox 一致没用上所以没办法测试-->
|
||||
<a-checkbox-group
|
||||
v-if="item.type == 'checkbox'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请选择${item.title}!`, type: 'array' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请选择${item.title}!`"
|
||||
>
|
||||
<a-checkbox v-for="(it, idx) in item.options" :key="idx" :value="idx">
|
||||
{{ it }}
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
<!-- date -->
|
||||
<a-date-picker
|
||||
v-if="item.type == 'date'"
|
||||
v-decorator="[
|
||||
item.key,
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: `请选择${item.title}!`},
|
||||
]
|
||||
}
|
||||
]"
|
||||
:placeholder="`请选择${item.title}!`"
|
||||
style="width: 100%">
|
||||
</a-date-picker>
|
||||
|
||||
</a-form-item>
|
||||
|
||||
<!-- const TYPE_TEXT = 'text';*
|
||||
const TYPE_NUMBER = 'number';*
|
||||
const TYPE_MOBILE = 'mobile';*
|
||||
const TYPE_PRICE = 'price';*
|
||||
const TYPE_TEXTAREA = 'textarea';*
|
||||
const TYPE_PASSWORD = 'password';*
|
||||
const TYPE_DAY = 'day';*
|
||||
const TYPE_SELECT = 'select';*
|
||||
const TYPE_RADIO = 'radio';*
|
||||
const TYPE_CHECKBOX = 'checkbox';*
|
||||
const TYPE_DATE = 'date';
|
||||
const TYPE_REGION = 'region';与 text 一致
|
||||
-->
|
||||
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updateOrderInfo } from '@/api/order'
|
||||
export default {
|
||||
name: 'EditOrderInfo',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
formItemLayout: {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 }
|
||||
},
|
||||
loading: false
|
||||
}),
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
methods: {
|
||||
onOk () {
|
||||
return new Promise(resolve => {
|
||||
this.form.validateFields((errors, values) => {
|
||||
if (!errors) {
|
||||
console.log(values)
|
||||
console.log(this.item.actionType)
|
||||
const params = {
|
||||
item_id: this.item.id.item_id,
|
||||
type: this.item.actionType === 'user' ? 1 : 2,
|
||||
params: {
|
||||
key: Object.keys(values)[0],
|
||||
value: this.item.type === 'date' ? values[Object.keys(values)[0]].format('YYYY-MM-DD') : values[Object.keys(values)[0]]
|
||||
}
|
||||
}
|
||||
console.log(params)
|
||||
updateOrderInfo(this.item.id.order_id, params).then((res) => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '修改成功'
|
||||
})
|
||||
resolve(true)
|
||||
}).catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
185
src/components/OrderDetailInfo/modules/ItemPopover.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<!-- 1.没修改过2.修改过未通过,3修改过通过了 -->
|
||||
<!--
|
||||
const CHANGE_NONE = 'none'; // 没修改过
|
||||
const CHANGE_UNPASS = 'unfinished'; // 被驳回,用户未改
|
||||
const CHANGE_UPDATE = 'finished'; // 被驳回,用户改了信息
|
||||
const CHANGE_PASS = 'success'; // 被驳回,审核通过
|
||||
-->
|
||||
<div class="jc_sb row">
|
||||
<a-popover placement="topLeft" v-if="resetEdit">
|
||||
<template slot="content" v-if="item.reason">
|
||||
<span>操作人员: <span class="spanItem">{{ item.reason.type }} {{ item.reason.personal }} </span></span><br />
|
||||
<span>驳回原因: <span class="spanItem">{{ item.reason.description }} </span></span><br />
|
||||
<span class="spanItem">{{ item.reason.created_at }}</span><br />
|
||||
<a-popconfirm title="是否确认审核通过该信息?" ok-text="确认" cancel-text="取消" @confirm="popoverAction(item)">
|
||||
<a class="popoverAction" v-if="item.is_change == 'finished'">通过</a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
<span slot="title">驳回记录</span>
|
||||
<a-icon v-if="item.is_change == 'unfinished'" type="info-circle" :style="{ fontSize: '16px', color: '#ff4d4f' }" />
|
||||
<a-icon v-if="item.is_change == 'finished'" type="issues-close" :style="{ fontSize: '16px', color: '#faad14' }" />
|
||||
<a-icon v-if="(item.is_change == 'success' && rejectEdit)" type="check-circle" :style="{ fontSize: '16px', color: '#87d068' }" />
|
||||
</a-popover>
|
||||
<a-icon v-if="!rejectEdit && item.is_change != 'unfinished' && item.is_change != 'finished' && !item.disabled" @click="edit(item)" type="edit" :style="{ fontSize: '16px', color: '#1890ff' }" />
|
||||
<a-icon v-if="!resetEdit && !item.disabled " @click="edit(item)" type="edit" :style="{ fontSize: '16px', color: '#1890ff' }" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Reason from '@/components/OrderDetailInfo/modules/Reason.vue'
|
||||
import EditOrderInfo from '@/components/OrderDetailInfo/modules/EditOrderInfo.vue'
|
||||
import { passInfo } from '@/api/order'
|
||||
export default {
|
||||
name: 'ItemPopover',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
id: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
rejectEdit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
resetEdit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
edit (item) {
|
||||
item.id = this.id
|
||||
item.actionType = this.type
|
||||
let success = {}
|
||||
if (!this.resetEdit) {
|
||||
if (this.type === 'user') {
|
||||
success = {
|
||||
title: '修改用户信息',
|
||||
width: 600,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认修改',
|
||||
cancelText: '取消'
|
||||
}
|
||||
} else if (this.type === 'bank') {
|
||||
success = {
|
||||
title: '修改该机构信息',
|
||||
width: 600,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认修改',
|
||||
cancelText: '取消'
|
||||
}
|
||||
}
|
||||
console.log('resetEdit', item)
|
||||
this.$dialog(
|
||||
EditOrderInfo,
|
||||
{
|
||||
item,
|
||||
on: {
|
||||
ok: () => {
|
||||
if (this.type === 'bank') {
|
||||
this.eventBus.$emit('editBank', { data: true })
|
||||
} else if (this.type === 'user') {
|
||||
this.eventBus.$emit('editRealName', { data: true })
|
||||
}
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
}
|
||||
}
|
||||
},
|
||||
success
|
||||
)
|
||||
return
|
||||
}
|
||||
if (!this.rejectEdit) {
|
||||
if (this.type === 'user') {
|
||||
success = {
|
||||
title: '驳回用户信息',
|
||||
width: 500,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认驳回',
|
||||
cancelText: '取消'
|
||||
}
|
||||
} else if (this.type === 'bank') {
|
||||
success = {
|
||||
title: '驳回该机构信息',
|
||||
width: 500,
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
okText: '确认驳回',
|
||||
cancelText: '取消'
|
||||
}
|
||||
}
|
||||
this.$dialog(
|
||||
Reason,
|
||||
{
|
||||
item,
|
||||
on: {
|
||||
ok: () => {
|
||||
if (this.type === 'bank') {
|
||||
this.eventBus.$emit('editBank', { data: true })
|
||||
} else if (this.type === 'user') {
|
||||
this.eventBus.$emit('editRealName', { data: true })
|
||||
}
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
}
|
||||
}
|
||||
},
|
||||
success
|
||||
)
|
||||
}
|
||||
},
|
||||
// 驳回通过
|
||||
popoverAction (item) {
|
||||
const params = {
|
||||
item_id: this.id.item_id,
|
||||
type: this.type === 'user' ? 1 : 2,
|
||||
params: {
|
||||
key: item.key
|
||||
}
|
||||
}
|
||||
passInfo(this.id.order_id, params)
|
||||
.then((res) => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '驳回被通过!'
|
||||
})
|
||||
if (this.type === 'user') {
|
||||
this.eventBus.$emit('editRealName', { data: true })
|
||||
} else {
|
||||
this.eventBus.$emit('editBank', { data: true })
|
||||
}
|
||||
this.eventBus.$emit('updateOrderInfo', { data: true })
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.spanItem {
|
||||
color: grey;
|
||||
}
|
||||
.popoverAction {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
105
src/components/OrderDetailInfo/modules/MoneyChange.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<!-- 驳回原因客户姓名输入 -->
|
||||
<template>
|
||||
<a-form
|
||||
ref="form"
|
||||
v-bind="formItemLayout"
|
||||
:form="form"
|
||||
>
|
||||
<a-form-item label="当前机构/欠款" v-if="order">
|
||||
<span>{{ order.item.institution }} / <span>¥{{ order.item.price }}</span></span>
|
||||
</a-form-item>
|
||||
<a-form-item label="修改欠款金额">
|
||||
<a-input
|
||||
prefix="¥"
|
||||
suffix="RMB"
|
||||
v-decorator="[
|
||||
'price',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入欠款金额!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入欠款金额" />
|
||||
</a-form-item>
|
||||
<a-form-item label="修改原因">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-decorator="[
|
||||
'reason',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入记录内容!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入记录内容!" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { changeBankCount } from '@/api/order'
|
||||
import moment from 'moment'
|
||||
export default {
|
||||
name: 'OperationAdd',
|
||||
props: {
|
||||
order: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
formItemLayout: {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 }
|
||||
},
|
||||
loading: false,
|
||||
expressList: []
|
||||
}),
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
methods: {
|
||||
moment,
|
||||
onOk () {
|
||||
return new Promise(resolve => {
|
||||
this.form.validateFields((errors, values) => {
|
||||
if (!errors) {
|
||||
const params = {
|
||||
reason: values.reason,
|
||||
price: values.price
|
||||
}
|
||||
changeBankCount(this.order.orderId, this.order.item.order_item_id, params).then((res) => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '欠款金额修改成功'
|
||||
})
|
||||
resolve(true)
|
||||
}).catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.flexrow{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
129
src/components/OrderDetailInfo/modules/OperationAdd.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<!-- 驳回原因客户姓名输入 -->
|
||||
<template>
|
||||
<a-form
|
||||
ref="form"
|
||||
v-bind="formItemLayout"
|
||||
:form="form"
|
||||
>
|
||||
<a-form-item label="记录类型">
|
||||
<a-select
|
||||
v-decorator="[
|
||||
'type',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请选择添加记录类型!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请选择添加记录类型"
|
||||
>
|
||||
<a-select-option value="system" v-if="order.itemId != ''"><a-icon type="apartment" :style="{ fontSize: '14px', color: '#1890ff',padding:'6px 16px 6px 0' }" />添加记录(系统展示)</a-select-option>
|
||||
<a-select-option value="user"><a-icon type="user" :style="{ fontSize: '14px', color: '#1890ff',padding:'6px 16px 6px 0' }" />添加记录(客户展示)</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="添加时间">
|
||||
<a-date-picker
|
||||
show-time
|
||||
placeholder="请选择添加时间"
|
||||
v-decorator="[
|
||||
'do_at',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请选择添加时间' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="记录内容">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-decorator="[
|
||||
'description',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入记录内容!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入记录内容!" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { doLogs } from '@/api/order'
|
||||
import moment from 'moment'
|
||||
export default {
|
||||
name: 'OperationAdd',
|
||||
props: {
|
||||
order: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
formItemLayout: {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 }
|
||||
},
|
||||
loading: false,
|
||||
expressList: []
|
||||
}),
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
created () {
|
||||
// getExpressCommonList(this.order.order_no).then(res => {
|
||||
// this.expressList = res
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
moment,
|
||||
onChange (date, dateString) {
|
||||
},
|
||||
onOk () {
|
||||
return new Promise(resolve => {
|
||||
this.form.validateFields((errors, values) => {
|
||||
console.log(values)
|
||||
if (!errors) {
|
||||
const params = {
|
||||
order: this.order.orderId,
|
||||
item_id: this.order.itemId,
|
||||
description: values.description,
|
||||
do_at: values.do_at.format('YYYY-MM-DD HH:mm:ss'),
|
||||
type: values.type
|
||||
}
|
||||
doLogs(this.order.orderId, params).then((res) => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '添加记录成功'
|
||||
})
|
||||
resolve(true)
|
||||
}).catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.flexrow{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
107
src/components/OrderDetailInfo/modules/PayDifference.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<!-- 驳回原因用户姓名输入 -->
|
||||
<template>
|
||||
<a-form ref="form" v-bind="formItemLayout" :form="form">
|
||||
<a-form-item label="补差价格">
|
||||
<a-input
|
||||
prefix="¥"
|
||||
suffix="RMB"
|
||||
v-decorator="[
|
||||
'price',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入补差价格!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入补差价格" />
|
||||
</a-form-item>
|
||||
<a-form-item label="关联机构">
|
||||
<a-checkbox-group v-decorator="['business_order_item_ids']" style="width: 100%;">
|
||||
<a-row>
|
||||
<a-col v-for="it in item.banks" :key="it.business_order_item_id" :span="24">
|
||||
<a-checkbox :value="it.business_order_item_id">{{ it.institution.title }}</a-checkbox>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-checkbox-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="补差价原因">
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
v-decorator="[
|
||||
'remark',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入详细的添加补差价原因!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入详细的添加补差价原因" />
|
||||
</a-form-item>
|
||||
<div class="remark">勾选机构是给机构补差价,不勾选则是给服务包补差价。</div>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { diffPrice } from '@/api/order'
|
||||
export default {
|
||||
name: 'PayDifference',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
banks: [] // 机构列表
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
formItemLayout: {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 }
|
||||
},
|
||||
loading: false,
|
||||
expressList: []
|
||||
}),
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
created () {
|
||||
// getExpressCommonList(this.order.order_no).then(res => {
|
||||
// this.expressList = res
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
onOk () {
|
||||
return new Promise(resolve => {
|
||||
console.log(this.item)
|
||||
this.form.validateFields((errors, values) => {
|
||||
console.log(values)
|
||||
if (!errors) {
|
||||
diffPrice(this.item.id, values).then(() => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '补差价成功'
|
||||
})
|
||||
resolve(true)
|
||||
}).catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.remark{
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
91
src/components/OrderDetailInfo/modules/Reason.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<!-- 驳回原因用户姓名输入 -->
|
||||
<template>
|
||||
<a-form
|
||||
ref="form"
|
||||
v-bind="formItemLayout"
|
||||
:form="form"
|
||||
>
|
||||
<a-form-item label="驳回原因">
|
||||
<a-textarea
|
||||
:rows="6"
|
||||
v-decorator="[
|
||||
'reason',
|
||||
{
|
||||
rules: [
|
||||
{ required: true, message: '请输入驳回原因!', type: 'string' },
|
||||
]
|
||||
}
|
||||
]"
|
||||
placeholder="请输入驳回原因" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { checkInfo } from '@/api/order'
|
||||
// import { getExpressCommonList } from '@/api/express'
|
||||
|
||||
export default {
|
||||
name: 'Reason',
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
formItemLayout: {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 14 }
|
||||
},
|
||||
loading: false,
|
||||
expressList: []
|
||||
}),
|
||||
beforeCreate () {
|
||||
this.form = this.$form.createForm(this)
|
||||
},
|
||||
created () {
|
||||
// getExpressCommonList(this.order.order_no).then(res => {
|
||||
// this.expressList = res
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
onOk () {
|
||||
return new Promise(resolve => {
|
||||
this.form.validateFields((errors, values) => {
|
||||
if (!errors) {
|
||||
const params = {
|
||||
item_id: this.item.id.item_id,
|
||||
type: this.item.actionType === 'user' ? 1 : 2,
|
||||
params: {
|
||||
key: this.item.key,
|
||||
value: this.item.value,
|
||||
reason: values.reason
|
||||
}
|
||||
}
|
||||
checkInfo(this.item.id.order_id, params).then((res) => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: '驳回成功'
|
||||
})
|
||||
resolve(true)
|
||||
}).catch((err) => {
|
||||
this.$notification.error({
|
||||
message: '失败',
|
||||
description: err.message
|
||||
})
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
106
src/components/PageLoading/index.jsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { Spin } from 'ant-design-vue'
|
||||
|
||||
export const PageLoading = {
|
||||
name: 'PageLoading',
|
||||
props: {
|
||||
tip: {
|
||||
type: String,
|
||||
default: 'Loading..'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'large'
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const style = {
|
||||
textAlign: 'center',
|
||||
background: 'rgba(0,0,0,0.6)',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 1100
|
||||
}
|
||||
const spinStyle = {
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '40%',
|
||||
transform: 'translate(-50%, -50%)'
|
||||
}
|
||||
return (<div style={style}>
|
||||
<Spin size={this.size} style={spinStyle} tip={this.tip} />
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
|
||||
const version = '0.0.1'
|
||||
const loading = {}
|
||||
|
||||
loading.newInstance = (Vue, options) => {
|
||||
let loadingElement = document.querySelector('body>div[type=loading]')
|
||||
if (!loadingElement) {
|
||||
loadingElement = document.createElement('div')
|
||||
loadingElement.setAttribute('type', 'loading')
|
||||
loadingElement.setAttribute('class', 'ant-loading-wrapper')
|
||||
document.body.appendChild(loadingElement)
|
||||
}
|
||||
|
||||
const cdProps = Object.assign({ visible: false, size: 'large', tip: 'Loading...' }, options)
|
||||
|
||||
const instance = new Vue({
|
||||
data () {
|
||||
return {
|
||||
...cdProps
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { tip } = this
|
||||
const props = {}
|
||||
this.tip && (props.tip = tip)
|
||||
if (this.visible) {
|
||||
return <PageLoading { ...{ props } } />
|
||||
}
|
||||
return null
|
||||
}
|
||||
}).$mount(loadingElement)
|
||||
|
||||
function update (config) {
|
||||
const { visible, size, tip } = { ...cdProps, ...config }
|
||||
instance.$set(instance, 'visible', visible)
|
||||
if (tip) {
|
||||
instance.$set(instance, 'tip', tip)
|
||||
}
|
||||
if (size) {
|
||||
instance.$set(instance, 'size', size)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
instance,
|
||||
update
|
||||
}
|
||||
}
|
||||
|
||||
const api = {
|
||||
show: function (options) {
|
||||
this.instance.update({ ...options, visible: true })
|
||||
},
|
||||
hide: function () {
|
||||
this.instance.update({ visible: false })
|
||||
}
|
||||
}
|
||||
|
||||
const install = function (Vue, options) {
|
||||
if (Vue.prototype.$loading) {
|
||||
return
|
||||
}
|
||||
api.instance = loading.newInstance(Vue, options)
|
||||
Vue.prototype.$loading = api
|
||||
}
|
||||
|
||||
export default {
|
||||
version,
|
||||
install
|
||||
}
|
||||
62
src/components/Search/GlobalSearch.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Select } from 'ant-design-vue'
|
||||
import './index.less'
|
||||
|
||||
const GlobalSearch = {
|
||||
name: 'GlobalSearch',
|
||||
data () {
|
||||
return {
|
||||
visible: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const keyboardHandle = (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const { ctrlKey, shiftKey, altKey, keyCode } = e
|
||||
// key is `K` and hold ctrl
|
||||
if (keyCode === 75 && ctrlKey && !shiftKey && !altKey) {
|
||||
this.visible = !this.visible
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', keyboardHandle)
|
||||
},
|
||||
render () {
|
||||
const { visible } = this
|
||||
const handleSearch = (e) => {
|
||||
this.$emit('search', e)
|
||||
}
|
||||
|
||||
const handleChange = (e) => {
|
||||
this.$emit('change', e)
|
||||
}
|
||||
if (!visible) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<div class={'global-search global-search-wrapper'}>
|
||||
<div class={'global-search-box'}>
|
||||
<Select
|
||||
size={'large'}
|
||||
showSearch
|
||||
placeholder="Input search text.."
|
||||
style={{ width: '100%' }}
|
||||
defaultActiveFirstOption={false}
|
||||
showArrow={false}
|
||||
filterOption={false}
|
||||
onSearch={handleSearch}
|
||||
onChange={handleChange}
|
||||
notFoundContent={null}
|
||||
>
|
||||
</Select>
|
||||
<div class={'global-search-tips'}>Open with Ctrl/⌘ + K</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
GlobalSearch.install = function (Vue) {
|
||||
Vue.component(GlobalSearch.name, GlobalSearch)
|
||||
}
|
||||
|
||||
export default GlobalSearch
|
||||
25
src/components/Search/index.less
Normal file
@@ -0,0 +1,25 @@
|
||||
@import "~ant-design-vue/es/style/themes/default";
|
||||
|
||||
.global-search-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: @zindex-modal-mask;
|
||||
background: @modal-mask-bg;
|
||||
|
||||
.global-search-box {
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
left: 50%;
|
||||
width: 450px;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.global-search-tips {
|
||||
color: @white;
|
||||
font-size: @font-size-lg;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/components/SelectLang/index.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import './index.less'
|
||||
|
||||
import { Dropdown, Icon, Menu } from 'ant-design-vue'
|
||||
import { i18nRender } from '@/locales'
|
||||
import i18nMixin from '@/store/i18n-mixin'
|
||||
|
||||
const locales = ['zh-CN', 'en-US']
|
||||
const languageLabels = {
|
||||
'zh-CN': '简体中文',
|
||||
'en-US': 'English'
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const languageIcons = {
|
||||
'zh-CN': '🇨🇳',
|
||||
'en-US': '🇺🇸'
|
||||
}
|
||||
|
||||
const SelectLang = {
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String,
|
||||
default: 'ant-pro-drop-down'
|
||||
}
|
||||
},
|
||||
name: 'SelectLang',
|
||||
mixins: [i18nMixin],
|
||||
render () {
|
||||
const { prefixCls } = this
|
||||
const changeLang = ({ key }) => {
|
||||
this.setLang(key)
|
||||
}
|
||||
const langMenu = (
|
||||
<Menu class={['menu', 'ant-pro-header-menu']} selectedKeys={[this.currentLang]} onClick={changeLang}>
|
||||
{locales.map(locale => (
|
||||
<Menu.Item key={locale}>
|
||||
<span role='img' aria-label={languageLabels[locale]}>
|
||||
{languageIcons[locale]}
|
||||
</span>{' '}
|
||||
{languageLabels[locale]}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
)
|
||||
return (
|
||||
<Dropdown overlay={langMenu} placement='bottomRight'>
|
||||
<span class={prefixCls}>
|
||||
<Icon type='global' title={i18nRender('navBar.lang')} />
|
||||
</span>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectLang
|
||||
32
src/components/SelectLang/index.less
Normal file
@@ -0,0 +1,32 @@
|
||||
@import "~ant-design-vue/es/style/themes/default";
|
||||
|
||||
@header-menu-prefix-cls: ~'@{ant-prefix}-pro-header-menu';
|
||||
@header-drop-down-prefix-cls: ~'@{ant-prefix}-pro-drop-down';
|
||||
|
||||
.@{header-menu-prefix-cls} {
|
||||
|
||||
.anticon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{header-drop-down-prefix-cls} {
|
||||
|
||||
line-height: @layout-header-height;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
|
||||
> i {
|
||||
font-size: 16px !important;
|
||||
transform: none !important;
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
342
src/components/SettingDrawer/SettingDrawer.vue
Normal file
@@ -0,0 +1,342 @@
|
||||
<template>
|
||||
<div class="setting-drawer">
|
||||
<a-drawer
|
||||
width="300"
|
||||
placement="right"
|
||||
@close="onClose"
|
||||
:closable="false"
|
||||
:visible="visible"
|
||||
:drawer-style="{ position: 'absolute' }"
|
||||
style="position: absolute"
|
||||
>
|
||||
<div class="setting-drawer-index-content">
|
||||
|
||||
<div :style="{ marginBottom: '24px' }">
|
||||
<h3 class="setting-drawer-index-title">整体风格设置</h3>
|
||||
|
||||
<div class="setting-drawer-index-blockChecbox">
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
暗色菜单风格
|
||||
</template>
|
||||
<div class="setting-drawer-index-item" @click="handleMenuTheme('dark')">
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/LCkqqYNmvBEbokSDscrm.svg" alt="dark">
|
||||
<div class="setting-drawer-index-selectIcon" v-if="navTheme === 'dark'">
|
||||
<a-icon type="check"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
亮色菜单风格
|
||||
</template>
|
||||
<div class="setting-drawer-index-item" @click="handleMenuTheme('light')">
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/jpRkZQMyYRryryPNtyIC.svg" alt="light">
|
||||
<div class="setting-drawer-index-selectIcon" v-if="navTheme !== 'dark'">
|
||||
<a-icon type="check"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :style="{ marginBottom: '24px' }">
|
||||
<h3 class="setting-drawer-index-title">主题色</h3>
|
||||
|
||||
<div style="height: 20px">
|
||||
<a-tooltip class="setting-drawer-theme-color-colorBlock" v-for="(item, index) in colorList" :key="index">
|
||||
<template slot="title">
|
||||
{{ item.key }}
|
||||
</template>
|
||||
<a-tag :color="item.color" @click="changeColor(item.color)">
|
||||
<a-icon type="check" v-if="item.color === primaryColor"></a-icon>
|
||||
</a-tag>
|
||||
</a-tooltip>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a-divider />
|
||||
|
||||
<div :style="{ marginBottom: '24px' }">
|
||||
<h3 class="setting-drawer-index-title">导航模式</h3>
|
||||
|
||||
<div class="setting-drawer-index-blockChecbox">
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
侧边栏导航
|
||||
</template>
|
||||
<div class="setting-drawer-index-item" @click="handleLayout('sidemenu')">
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg" alt="sidemenu">
|
||||
<div class="setting-drawer-index-selectIcon" v-if="layoutMode === 'sidemenu'">
|
||||
<a-icon type="check"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
顶部栏导航
|
||||
</template>
|
||||
<div class="setting-drawer-index-item" @click="handleLayout('topmenu')">
|
||||
<img src="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" alt="topmenu">
|
||||
<div class="setting-drawer-index-selectIcon" v-if="layoutMode !== 'sidemenu'">
|
||||
<a-icon type="check"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div :style="{ marginTop: '24px' }">
|
||||
<a-list :split="false">
|
||||
<a-list-item>
|
||||
<a-tooltip slot="actions">
|
||||
<template slot="title">
|
||||
该设定仅 [顶部栏导航] 时有效
|
||||
</template>
|
||||
<a-select size="small" style="width: 80px;" :defaultValue="contentWidth" @change="handleContentWidthChange">
|
||||
<a-select-option value="Fixed">固定</a-select-option>
|
||||
<a-select-option value="Fluid" v-if="layoutMode !== 'sidemenu'">流式</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
<a-list-item-meta>
|
||||
<div slot="title">内容区域宽度</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="fixedHeader" @change="handleFixedHeader" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">固定 Header</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :disabled="!fixedHeader" :defaultChecked="autoHideHeader" @change="handleFixedHeaderHidden" />
|
||||
<a-list-item-meta>
|
||||
<a-tooltip slot="title" placement="left">
|
||||
<template slot="title">固定 Header 时可配置</template>
|
||||
<div :style="{ opacity: !fixedHeader ? '0.5' : '1' }">下滑时隐藏 Header</div>
|
||||
</a-tooltip>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item >
|
||||
<a-switch slot="actions" size="small" :disabled="(layoutMode === 'topmenu')" :defaultChecked="fixSiderbar" @change="handleFixSiderbar" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title" :style="{ textDecoration: layoutMode === 'topmenu' ? 'line-through' : 'unset' }">固定侧边菜单</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider />
|
||||
|
||||
<div :style="{ marginBottom: '24px' }">
|
||||
<h3 class="setting-drawer-index-title">其他设置</h3>
|
||||
<div>
|
||||
<a-list :split="false">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="colorWeak" @change="onColorWeak" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">色弱模式</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="multiTab" @change="onMultiTab" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">多页签模式</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider />
|
||||
<div :style="{ marginBottom: '24px' }">
|
||||
<a-button
|
||||
@click="doCopy"
|
||||
icon="copy"
|
||||
block
|
||||
>拷贝设置</a-button>
|
||||
<a-alert type="warning" :style="{ marginTop: '24px' }">
|
||||
<span slot="message">
|
||||
配置栏只在开发环境用于预览,生产环境不会展现,请手动修改配置文件。修改配置文件后,需要清空本地缓存和LocalStorage
|
||||
<a href="https://github.com/sendya/ant-design-pro-vue/blob/master/src/config/defaultSettings.js" target="_blank">src/config/defaultSettings.js</a>
|
||||
</span>
|
||||
</a-alert>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-drawer-index-handle" @click="toggle" slot="handle">
|
||||
<a-icon type="setting" v-if="!visible"/>
|
||||
<a-icon type="close" v-else/>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingItem from './SettingItem'
|
||||
import config from '@/config/defaultSettings'
|
||||
import { updateTheme, updateColorWeak, colorList } from './settingConfig'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingItem
|
||||
},
|
||||
mixins: [],
|
||||
data () {
|
||||
return {
|
||||
visible: false,
|
||||
colorList
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
mounted () {
|
||||
updateTheme(this.primaryColor)
|
||||
if (this.colorWeak !== config.colorWeak) {
|
||||
updateColorWeak(this.colorWeak)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showDrawer () {
|
||||
this.visible = true
|
||||
},
|
||||
onClose () {
|
||||
this.visible = false
|
||||
},
|
||||
toggle () {
|
||||
this.visible = !this.visible
|
||||
},
|
||||
onColorWeak (checked) {
|
||||
this.$store.dispatch('ToggleWeak', checked)
|
||||
updateColorWeak(checked)
|
||||
},
|
||||
onMultiTab (checked) {
|
||||
this.$store.dispatch('ToggleMultiTab', checked)
|
||||
},
|
||||
handleMenuTheme (theme) {
|
||||
this.$store.dispatch('ToggleTheme', theme)
|
||||
},
|
||||
doCopy () {
|
||||
// get current settings from mixin or this.$store.state.app, pay attention to the property name
|
||||
const text = `export default {
|
||||
primaryColor: '${this.primaryColor}', // primary color of ant design
|
||||
navTheme: '${this.navTheme}', // theme for nav menu
|
||||
layout: '${this.layoutMode}', // nav menu position: sidemenu or topmenu
|
||||
contentWidth: '${this.contentWidth}', // layout of content: Fluid or Fixed, only works when layout is topmenu
|
||||
fixedHeader: ${this.fixedHeader}, // sticky header
|
||||
fixSiderbar: ${this.fixSiderbar}, // sticky siderbar
|
||||
autoHideHeader: ${this.autoHideHeader}, // auto hide header
|
||||
colorWeak: ${this.colorWeak},
|
||||
multiTab: ${this.multiTab},
|
||||
production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'
|
||||
}`
|
||||
this.$copyText(text).then(message => {
|
||||
this.$message.success('复制完毕')
|
||||
}).catch(err => {
|
||||
console.log('copy.err', err)
|
||||
this.$message.error('复制失败')
|
||||
})
|
||||
},
|
||||
handleLayout (mode) {
|
||||
this.$store.dispatch('ToggleLayoutMode', mode)
|
||||
// 因为顶部菜单不能固定左侧菜单栏,所以强制关闭
|
||||
this.handleFixSiderbar(false)
|
||||
},
|
||||
handleContentWidthChange (type) {
|
||||
this.$store.dispatch('ToggleContentWidth', type)
|
||||
},
|
||||
changeColor (color) {
|
||||
if (this.primaryColor !== color) {
|
||||
this.$store.dispatch('ToggleColor', color)
|
||||
updateTheme(color)
|
||||
}
|
||||
},
|
||||
handleFixedHeader (fixed) {
|
||||
this.$store.dispatch('ToggleFixedHeader', fixed)
|
||||
},
|
||||
handleFixedHeaderHidden (autoHidden) {
|
||||
this.$store.dispatch('ToggleFixedHeaderHidden', autoHidden)
|
||||
},
|
||||
handleFixSiderbar (fixed) {
|
||||
if (this.layoutMode === 'topmenu') {
|
||||
this.$store.dispatch('ToggleFixSiderbar', false)
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('ToggleFixSiderbar', fixed)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.setting-drawer-index-content {
|
||||
|
||||
.setting-drawer-index-blockChecbox {
|
||||
display: flex;
|
||||
|
||||
.setting-drawer-index-item {
|
||||
margin-right: 16px;
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.setting-drawer-index-selectIcon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
padding-top: 15px;
|
||||
padding-left: 24px;
|
||||
height: 100%;
|
||||
color: #1890ff;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
.setting-drawer-theme-color-colorBlock {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 2px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.setting-drawer-index-handle {
|
||||
position: absolute;
|
||||
top: 240px;
|
||||
background: #1890ff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
right: 300px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
z-index: 1001;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
|
||||
i {
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
38
src/components/SettingDrawer/SettingItem.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="setting-drawer-index-item">
|
||||
<h3 class="setting-drawer-index-title">{{ title }}</h3>
|
||||
<slot></slot>
|
||||
<a-divider v-if="divider"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SettingItem',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
divider: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.setting-drawer-index-item {
|
||||
margin-bottom: 24px;
|
||||
|
||||
.setting-drawer-index-title {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, .85);
|
||||
line-height: 22px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||