细节优化

This commit is contained in:
磷叶 2025-02-06 18:01:38 +08:00
parent 0b8ccd4602
commit 064961019c
18 changed files with 335 additions and 138 deletions

View File

@ -9,6 +9,14 @@ export function listApp(query) {
})
}
// 所有APP列表
export function listAllApp() {
return request({
url: '/ss/app/all',
method: 'get'
})
}
// 查询APP信息列表
export function listAppByIds(ids) {
return request({

View File

@ -1,11 +1,12 @@
<template>
<el-link v-if="userType === UserType.ADMIN" type="primary" @click="handleClick" :disabled="id == null">{{name | defaultValue}}</el-link>
<el-link v-if="userType === UserType.ADMIN" :type="linkType" @click="handleClick" :disabled="id == null">{{name | defaultValue}}</el-link>
<span v-else >{{name | defaultValue}}</span>
</template>
<script>
import { mapGetters } from 'vuex'
import { UserType } from '@/utils/constants'
import { UserRiskTag } from '@/utils/constants'
export default {
name: 'UserLink',
@ -17,13 +18,32 @@ export default {
name: {
type: String,
default: null,
},
riskTag: {
type: String,
default: UserRiskTag.NORMAL
}
},
computed: {
UserType() {
return UserType
},
...mapGetters(['userType'])
...mapGetters(['userType']),
//
linkType() {
switch(this.riskTag) {
case UserRiskTag.NORMAL:
return 'primary'
case UserRiskTag.TRUST:
return 'success'
case UserRiskTag.SUSPICIOUS:
return 'warning'
case UserRiskTag.RISK:
return 'danger'
default:
return 'primary'
}
}
},
methods: {
handleClick() {

View File

@ -23,6 +23,56 @@ import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { getToken } from "@/utils/auth";
import axios from 'axios';
//
class ImageHandler {
constructor(quill) {
this.quill = quill;
this.handlePaste = this.handlePaste.bind(this);
this.quill.root.addEventListener('paste', this.handlePaste);
}
handlePaste(e) {
const clipboardData = e.clipboardData;
if (!clipboardData || !clipboardData.items) return;
const items = clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
e.preventDefault();
const file = items[i].getAsFile();
this.upload(file);
break;
}
}
}
upload(file) {
const formData = new FormData();
formData.append('file', file);
axios.post(process.env.VUE_APP_BASE_API + "/common/upload", formData, {
headers: {
Authorization: "Bearer " + getToken(),
'Content-Type': 'multipart/form-data'
}
}).then(response => {
const res = response.data;
if (res.code === 200) {
const range = this.quill.getSelection(true);
this.quill.insertEmbed(range.index, 'image', res.url);
} else {
this.$message.error('图片上传失败');
}
}).catch(() => {
this.$message.error('图片上传失败');
});
}
}
//
Quill.register('modules/imageHandler', ImageHandler);
export default {
name: "Editor",
@ -60,7 +110,7 @@ export default {
},
data() {
return {
uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload", //
uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload",
headers: {
Authorization: "Bearer " + getToken()
},
@ -71,23 +121,27 @@ export default {
bounds: document.body,
debug: "warn",
modules: {
//
toolbar: [
["bold", "italic", "underline", "strike"], // 线 线
["blockquote", "code-block"], //
[{ list: "ordered" }, { list: "bullet" }], //
[{ indent: "-1" }, { indent: "+1" }], //
[{ size: ["small", false, "large", "huge"] }], //
[{ header: [1, 2, 3, 4, 5, 6, false] }], //
[{ color: [] }, { background: [] }], //
[{ align: [] }], //
["clean"], //
["link", "image", "video"] //
["bold", "italic", "underline", "strike"],
["blockquote", "code-block"],
[{ list: "ordered" }, { list: "bullet" }],
[{ indent: "-1" }, { indent: "+1" }],
[{ size: ["small", false, "large", "huge"] }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }],
[{ align: [] }],
["clean"],
["link", "image", "video"]
],
clipboard: {
matchVisual: false,
matchers: []
},
imageHandler: true
},
placeholder: "请输入内容",
readOnly: this.readOnly,
},
readOnly: this.readOnly
}
};
},
computed: {
@ -117,27 +171,50 @@ export default {
},
mounted() {
this.init();
// 使 MutationObserver
if (this.$refs.editor) {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList' || mutation.type === 'characterData') {
this.$nextTick(() => {
const html = this.$refs.editor.children[0].innerHTML;
if (html !== this.currentValue) {
this.currentValue = html;
this.$emit("input", html);
}
});
}
});
});
observer.observe(this.$refs.editor.children[0], {
childList: true,
characterData: true,
subtree: true
});
}
},
beforeDestroy() {
// MutationObserver
if (this._observer) {
this._observer.disconnect();
}
this.Quill = null;
},
methods: {
init() {
const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);
//
if (this.type == 'url') {
let toolbar = this.Quill.getModule("toolbar");
toolbar.addHandler("image", (value) => {
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
} else {
this.quill.format("image", false);
}
toolbar.addHandler("image", () => {
this.$refs.upload.$children[0].$refs.input.click();
});
}
this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.Quill.on('text-change', (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
@ -145,15 +222,6 @@ export default {
this.$emit("input", html);
this.$emit("on-change", { html, text, quill });
});
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
},
//
handleBeforeUpload(file) {
@ -192,6 +260,20 @@ export default {
handleUploadError() {
this.$message.error("图片插入失败");
},
// base64 Blob
base64ToBlob(base64) {
return new Promise((resolve) => {
const arr = base64.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
resolve(new Blob([u8arr], { type: mime }));
});
},
},
};
</script>

View File

@ -341,3 +341,12 @@ export const VipOrderStatus = {
SUCCESS: "2", // 支付成功
CANCEL: "3", // 已取消
}
// 用户风控标签
export const UserRiskTag = {
NORMAL: "1", // 正常
TRUST: "2", // 信任
SUSPICIOUS: "3", // 可疑
RISK: "4", // 风险
}

View File

@ -1,12 +1,11 @@
// 获取微信小程序外链
import {tansParams} from "@/utils/ruoyi";
import { tansParams } from "@/utils/ruoyi";
export function getWxSchemeUrl(path, query) {
return `${process.env.VUE_APP_WX_DEVICE_URL}&path=${path}&query=${encodeURIComponent(query)}`;
}
export function getWxIndexUrl(query) {
let url = `https://kg.chuantewulian.cn/w`;
export function getWxIndexUrl(url, query) {
if (query != null ) {
if (query instanceof Object) {
query = tansParams(query).slice(0, -1);
@ -19,8 +18,7 @@ export function getWxIndexUrl(query) {
}
// 获取合伙人外链
export function getStaffUrl(query) {
let url = `https://kg.chuangtewl.com/h`;
export function getStaffUrl(url, query) {
if (query != null ) {
if (query instanceof Object) {
query = tansParams(query).slice(0, -1);

View File

@ -124,46 +124,56 @@
<!-- 添加或修改APP信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="6em">
<el-form-item label="应用名称" prop="name">
<el-input v-model="form.name" placeholder="请输入应用名称" />
</el-form-item>
<el-form-item label="应用类型" prop="type">
<el-select v-model="form.type" placeholder="请选择应用类型" style="width: 100%">
<el-option v-for="item of dict.type.app_type" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-row>
<form-col :span="span" label="应用名称" prop="name">
<el-input v-model="form.name" placeholder="请输入应用名称" />
</form-col>
<form-col :span="span" label="应用类型" prop="type">
<el-select v-model="form.type" placeholder="请选择应用类型" style="width: 100%">
<el-option v-for="item of dict.type.app_type" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</form-col>
<!-- 微信配置 -->
<template v-if="form.type === AppType.WECHAT">
<el-form-item label="应用ID" prop="config.appId">
<el-input v-model="form.config.appId" placeholder="请输入应用ID" />
</el-form-item>
<el-form-item label="应用秘钥" prop="config.appSecret">
<el-input v-model="form.config.appSecret" placeholder="请输入应用秘钥" />
</el-form-item>
</template>
<!-- 支付宝配置 -->
<template v-else-if="form.type === AppType.ALI_PAY">
<form-col :span="24" label="应用ID" prop="config.appId">
<!-- 微信配置 -->
<template v-if="form.type === AppType.WECHAT">
<form-col :span="span" label="应用ID" prop="config.appId">
<el-input v-model="form.config.appId" placeholder="请输入应用ID" />
</form-col>
<form-col :span="span" label="应用秘钥" prop="config.appSecret">
<el-input v-model="form.config.appSecret" placeholder="请输入应用秘钥" />
</form-col>
</template>
<!-- 支付宝配置 -->
<template v-else-if="form.type === AppType.ALI_PAY">
<form-col :span="span" label="应用ID" prop="config.appId">
<el-input v-model="form.config.appId" placeholder="请输入应用ID" />
</form-col>
<form-col :span="span" label="应用私钥" prop="config.privateKey">
<el-input v-model="form.config.privateKey" placeholder="请输入应用私钥" type="textarea" />
</form-col>
<form-col :span="span" label="应用公钥证书地址" prop="config.appCertPath" label-width="9em">
<el-input v-model="form.config.appCertPath" placeholder="请输入应用公钥证书地址" />
</form-col>
<form-col :span="span" label="支付宝公钥证书地址" prop="config.alipayCertPath" label-width="10em">
<el-input v-model="form.config.alipayCertPath" placeholder="请输入支付宝公钥证书地址" />
</form-col>
<form-col :span="span" label="支付宝根证书地址" prop="config.alipayRootCertPath" label-width="9em">
<el-input v-model="form.config.alipayRootCertPath" placeholder="请输入支付宝根证书地址" />
</form-col>
<form-col :span="span" label="AES秘钥" prop="config.aesPrivateKey">
<el-input v-model="form.config.aesPrivateKey" placeholder="请输入AES秘钥" />
</form-col>
</template>
<form-col :span="span" label="SN前缀" prop="snPrefix">
<el-input v-model="form.snPrefix" placeholder="请输入SN前缀" />
</form-col>
<form-col :span="24" label="应用私钥" prop="config.privateKey">
<el-input v-model="form.config.privateKey" placeholder="请输入应用私钥" type="textarea" />
<form-col :span="span" label="合伙人前缀" prop="staffPrefix">
<el-input v-model="form.staffPrefix" placeholder="请输入合伙人前缀" />
</form-col>
<form-col :span="24" label="应用公钥证书地址" prop="config.appCertPath" label-width="9em">
<el-input v-model="form.config.appCertPath" placeholder="请输入应用公钥证书地址" />
</form-col>
<form-col :span="24" label="支付宝公钥证书地址" prop="config.alipayCertPath" label-width="10em">
<el-input v-model="form.config.alipayCertPath" placeholder="请输入支付宝公钥证书地址" />
</form-col>
<form-col :span="24" label="支付宝根证书地址" prop="config.alipayRootCertPath" label-width="9em">
<el-input v-model="form.config.alipayRootCertPath" placeholder="请输入支付宝根证书地址" />
</form-col>
<form-col :span="24" label="AES秘钥" prop="config.aesPrivateKey">
<el-input v-model="form.config.aesPrivateKey" placeholder="请输入AES秘钥" />
</form-col>
</template>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
@ -190,12 +200,15 @@ export default {
dicts: ['app_type'],
data() {
return {
span: 24,
AppType,
//
columns: [
{key: 'id', visible: true, label: 'ID', minWidth: null, sortable: true, overflow: false, align: 'center', width: "80"},
{key: 'name', visible: true, label: '应用名称', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
{key: 'type', visible: true, label: '应用类型', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
{key: 'snPrefix', visible: true, label: 'SN前缀', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
{key: 'staffPrefix', visible: true, label: '合伙人前缀', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
{key: 'createTime', visible: true, label: '创建时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
],
//

View File

@ -104,7 +104,7 @@
<dict-tag :options="dict.type.risk_type" :value="d.row[column.key]"/>
</template>
<template v-else-if="column.key === 'userId'">
<user-link :id="d.row.userId" :name="d.row.userName" />
<user-link :id="d.row.userId" :name="d.row.userName" :risk-tag="d.row.userRiskTag"/>
</template>
<template v-else-if="column.key === 'verifyStatus'">
<dict-tag :value="d.row.verifyStatus" :options="dict.type.risk_info_status"/>

View File

@ -101,7 +101,7 @@
<dict-tag :options="dict.type.risk_info_status" :value="d.row[column.key]"/>
</template>
<template v-else-if="column.key === 'userName'">
<user-link :id="d.row.userId" :name="d.row.userName"/>
<user-link :id="d.row.userId" :name="d.row.userName" :risk-tag="d.row.userRiskTag"/>
</template>
<template v-else-if="['idCardFront', 'idCardBack', 'idCardHand', 'businessLicence'].includes(column.key)">
<image-preview :src="d.row[column.key]" :width="50" :height="50"/>

View File

@ -75,7 +75,7 @@
</template>
<template v-else-if="column.key === 'userId'">
<user-link v-if="d.row.userId != null" :id="d.row.userId" :name="d.row.userName"/>
<template v-else>
<!-- <template v-else>
<el-popover
placement="top"
width="180"
@ -86,7 +86,7 @@
</div>
<el-button slot="reference" type="text" icon="el-icon-picture">绑定二维码</el-button>
</el-popover>
</template>
</template> -->
</template>
<template v-else-if="column.key === 'storeName'">
<store-link :id="d.row.storeId" :name="d.row.storeName"/>

View File

@ -0,0 +1,74 @@
<template>
<el-popover
placement="top"
width="400"
trigger="hover">
<div class="qr-code-box">
<el-tabs tab-position="left">
<template v-for="app in appList" >
<el-tab-pane :key="app.id" :label="app.name" v-if="app.snPrefix != null">
<qr-code :text="qrCodeText(app.snPrefix)" :width="150" :height="150" />
<div>{{sn | defaultValue}}</div>
</el-tab-pane>
</template>
</el-tabs>
</div>
<template #reference>
<slot>
<el-button type="text" icon="el-icon-picture">查看</el-button>
</slot>
</template>
</el-popover>
</template>
<script>
import { getWxIndexUrl } from '@/utils/wx';
import { listAllApp } from '@/api/ss/app';
import QrCode from '@/components/QrCode/index.vue'
export default {
name: 'DeviceSn',
components: {
QrCode
},
props: {
sn: {
type: String,
default: ''
},
},
data() {
return {
appList: [], // APP
}
},
computed: {
//
qrCodeText() {
return (url) => {
if (url == null) {
return "";
}
return getWxIndexUrl(url, { s: this.sn});
}
},
},
created() {
this.getAppList();
},
methods: {
// APP
getAppList() {
listAllApp().then(res => {
this.appList = res.data;
})
}
}
}
</script>
<style lang="scss" scoped>
.qr-code-box {
text-align: center;
}
</style>

View File

@ -8,20 +8,6 @@
<image-preview v-else :src="scope.row.customPicture" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="二维码" align="center" width="80">
<template slot-scope="d">
<el-popover
placement="top"
width="180"
trigger="hover">
<div class="qr-code-box">
<qr-code :text="qrCodeText(d.row)" :width="150" :height="150" />
<div>{{d.row.deviceNo | defaultValue}}</div>
</div>
<el-button slot="reference" type="text" icon="el-icon-picture">查看</el-button>
</el-popover>
</template>
</el-table-column>
<el-table-column label="MAC-1" align="center" prop="mac" min-width="100" v-if="isAdmin">
<device-link slot-scope="d" :text="d.row.mac" :id="d.row.deviceId"/>
</el-table-column>
@ -125,12 +111,6 @@ export default {
DeviceServiceMode() {
return DeviceServiceMode
},
//
qrCodeText() {
return (device) => {
return getWxIndexUrl({ s: device.deviceNo});
}
},
},
methods: {
isEmpty,
@ -143,8 +123,5 @@ export default {
</script>
<style scoped>
.qr-code-box {
text-align: center;
}
</style>

View File

@ -28,16 +28,9 @@
<el-button size="small" plain type="warning" icon="el-icon-switch-button" v-if="!isOpen" @click="handleSwitch(true)">强制开启</el-button>
<el-button size="small" plain type="warning" icon="el-icon-switch-button" v-if="isOpen" @click="handleSwitch(false)">强制关闭</el-button>
<el-button size="small" plain icon="el-icon-refresh" @click="refreshIot(deviceId, true, DeviceOnlineType.COMMAND)">刷新设备信息</el-button>
<el-popover
placement="left"
width="180"
trigger="click">
<div class="qr-code-box">
<qr-code :text="qrCodeText(deviceData)" :width="150" :height="150" />
<div>{{deviceData.deviceNo | defaultValue}}</div>
</div>
<el-button size="small" slot="reference" type="primary" icon="el-icon-picture" style="margin-left: 0.5em">设备二维码</el-button>
</el-popover>
<device-sn :sn="deviceData.deviceNo">
<el-button size="small" type="primary" icon="el-icon-picture" style="margin-left: 0.5em">设备二维码</el-button>
</device-sn>
</el-row>
</div>
@ -368,6 +361,7 @@ import LineField from '@/components/LineField/index.vue'
import DeviceSetWifiDialog from '@/views/system/device/components/DeviceSetWifiDialog.vue'
import CommandLog from "@/views/ss/commandLog/index.vue";
import DotStatus from '@/components/DotStatus/index.vue'
import DeviceSn from '@/views/system/device/components/DeviceSn.vue'
export default {
name: 'Device/:deviceId',
@ -384,7 +378,7 @@ export default {
UserLink,
StoreLink,
RecordTime,
Suit, ResetRecord, BindRecord, ReadingRecord, MeterRecordReport, QrCode, RechargeRecord, LineChart, DotStatus},
Suit, ResetRecord, BindRecord, ReadingRecord, MeterRecordReport, QrCode, RechargeRecord, LineChart, DotStatus, DeviceSn},
data() {
return {
showSetWifi: false,

View File

@ -183,10 +183,10 @@
<model-select v-model="form.modelId" :show-value.sync="form.model" @submit="onSubmitModel"/>
</form-col>
<form-col :span="span" label="MAC-1" prop="mac">
<el-input v-model="form.mac" placeholder="请输入设备MAC-1" :disabled="isEdit"/>
<el-input v-model="form.mac" placeholder="请输入设备MAC-1"/>
</form-col>
<form-col :span="span" label="MAC-2" prop="mac2">
<el-input v-model="form.mac2" placeholder="请输入设备MAC-2" :disabled="isEdit"/>
<el-input v-model="form.mac2" placeholder="请输入设备MAC-2"/>
</form-col>
<form-col :span="span" label="SN" prop="deviceNo">
<el-input v-model="form.deviceNo" placeholder="请输入设备SN" />
@ -277,6 +277,7 @@ import { $serviceType, $view } from '@/utils/mixins'
import ModelSimpleSelect from '@/components/Business/Model/ModelSimpleSelect.vue'
import { DeviceServiceMode, SmUserType } from '@/utils/constants'
import DeviceTable from '@/views/system/device/components/DeviceTable.vue'
import { listAllApp } from '@/api/ss/app';
export default {
name: "Device",

View File

@ -147,16 +147,16 @@
<recharge-link :bill-id="d.row.billId" :text="d.row.billNo"/>
</template>
<template v-else-if="column.key === 'userName'">
<user-link :id="d.row.userId" :name="d.row.userName"/><br/>
<user-link :id="d.row.userId" :name="d.row.userMobile"/>
<user-link :id="d.row.userId" :name="d.row.userName" :risk-tag="d.row.userRiskTag"/><br/>
<user-link :id="d.row.userId" :name="d.row.userMobile" :risk-tag="d.row.userRiskTag"/>
</template>
<template v-else-if="column.key === 'deviceName'">
<device-link :id="d.row.deviceId" :text="d.row.deviceName"/><br/>
<device-link :id="d.row.deviceId" :text="d.row.deviceNo"/>
</template>
<template v-else-if="column.key === 'mchName'">
<user-link :id="d.row.mchId" :name="d.row.mchName"/><br/>
<user-link :id="d.row.mchId" :name="d.row.mchMobile"/>
<user-link :id="d.row.mchId" :name="d.row.mchName" :risk-tag="d.row.mchRiskTag"/><br/>
<user-link :id="d.row.mchId" :name="d.row.mchMobile" :risk-tag="d.row.mchRiskTag"/>
</template>
<template v-else-if="column.key === 'storeId'">
<store-link :id="d.row.storeId" :name="d.row.storeName"/>

View File

@ -133,7 +133,7 @@
<el-card class="box-card">
<el-descriptions title="支付方信息" :column="1">
<el-descriptions-item label="用户名称">
<user-link :id="detail.userId" :name="detail.userName"/>
<user-link :id="detail.userId" :name="detail.userName" :risk-tag="detail.userRiskTag"/>
</el-descriptions-item>
<el-descriptions-item label="支付渠道">
{{detail.channelName | defaultValue}}
@ -145,10 +145,10 @@
<el-card class="box-card">
<el-descriptions title="收款方信息" :column="1">
<el-descriptions-item label="代理商" v-if="DeviceServiceMode.AGENT === detail.deviceServiceMode">
<user-link :id="detail.agentId" :name="detail.agentMobile"/>
<user-link :id="detail.agentId" :name="detail.agentMobile" :risk-tag="detail.agentRiskTag"/>
</el-descriptions-item>
<el-descriptions-item label="商户">
<user-link :id="detail.mchId" :name="detail.mchName"/>
<user-link :id="detail.mchId" :name="detail.mchName" :risk-tag="detail.mchRiskTag"/>
</el-descriptions-item>
<el-descriptions-item label="商户手机号">{{detail.mchMobile | defaultValue}}</el-descriptions-item>
<el-descriptions-item label="店铺名称">

View File

@ -64,6 +64,11 @@
</el-row>
<el-row>
<group-title title="风控配置"/>
<form-col :span="span" label="风控标签" prop="riskTag" label-width="6em" tip="请选择风控标签">
<el-select v-model="form.riskTag" placeholder="请选择风控标签" clearable style="width: 100%">
<el-option v-for="item of dict.type.user_risk_tag" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</form-col>
<form-col :span="span" label="充值延迟到账" prop="arrivalDelay" label-width="7em" tip="开启后,该用户的收益将延迟到账">
<el-input v-model="form.arrivalDelay" placeholder="请输入到账延迟时长">
<template #append>小时</template>
@ -102,7 +107,7 @@
<script>
import { addSmUser, getSmUser, updateSmUser } from '@/api/system/smUser'
import { SmUserType } from '@/utils/constants'
import { SmUserType, UserRiskTag } from '@/utils/constants'
import { $withdrawServiceType } from '@/utils/mixins'
import ChannelInput from '@/components/Business/Channel/ChannelInput.vue'
import AppInput from '@/components/Business/App/AppInput.vue'
@ -111,7 +116,7 @@ import GroupTitle from '@/components/GroupTitle/index.vue'
export default {
name: "UserFormDialog",
mixins: [$withdrawServiceType],
dicts: ['sm_user_status', 'sm_user_type', 'sys_user_sex', 'service_type', 'withdraw_service_type'],
dicts: ['sm_user_status', 'sm_user_type', 'sys_user_sex', 'service_type', 'withdraw_service_type', 'user_risk_tag'],
components: { ChannelInput, AppInput, GroupTitle },
props: {
show: {
@ -148,6 +153,9 @@ export default {
agentServiceRate: [
{ required: true, message: '请输入代理服务费', trigger: 'change' }
],
riskTag: [
{ required: true, message: '请选择风控标签', trigger: 'change' }
],
}
}
},
@ -186,7 +194,8 @@ export default {
channelIds: [],
showBillMobile: false,
showBillMobilePrice: 0,
enabledRenew: true
enabledRenew: true,
riskTag: UserRiskTag.NORMAL
}
this.$nextTick(() => {
this.$refs.form && this.$refs.form.clearValidate()

View File

@ -33,10 +33,8 @@
<el-avatar :size="64" :src="detail.avatar"></el-avatar>
<el-row type="flex" class="name-box">
<span class="user-name">{{ detail.realOrUserName }}</span>
<dict-tag
:value="detail.type"
:options="dict.type.sm_user_type"
/>
<dict-tag :value="detail.riskTag" :options="dict.type.user_risk_tag" />
<dict-tag :value="detail.type" :options="dict.type.sm_user_type" />
</el-row>
<div class="phone-number">{{ !isEmpty(detail.phonenumber) ? detail.phonenumber : '未绑定手机' }}</div>
</div>
@ -45,6 +43,9 @@
<el-descriptions-item label="充值服务费">
{{ detail.realServiceRate | money | defaultValue }} %
</el-descriptions-item>
<el-descriptions-item label="VIP服务费">
{{ detail.vipServiceRate | money | defaultValue }} %
</el-descriptions-item>
<el-descriptions-item label="代理服务费">
{{ detail.agentServiceRate | money | defaultValue }} %
</el-descriptions-item>
@ -67,7 +68,6 @@
</template>
</el-descriptions-item>
<el-descriptions-item label="所属应用">{{ detail.appName | dv }}</el-descriptions-item>
<el-descriptions-item label="实名认证">
<boolean-tag :value="detail.isReal" size="small" />
<el-link
@ -89,8 +89,9 @@
<el-descriptions-item label="实名手机">
{{ detail.realPhone | defaultValue }}
</el-descriptions-item>
<el-descriptions-item label="注册时间">{{ detail.createTime | dv }}</el-descriptions-item>
<el-descriptions-item label="所属应用">{{ detail.appName | dv }}</el-descriptions-item>
<el-descriptions-item label="开放平台ID" :span="2">{{ detail.wxOpenId | dv }}</el-descriptions-item>
<el-descriptions-item label="注册时间" :span="2">{{ detail.createTime | dv }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{detail.remark | defaultValue}}</el-descriptions-item>
<el-descriptions-item label="专属渠道" :span="2">
<el-tag type="success" v-for="item in detail.channelList" :key="item.channelId" size="mini">{{ item.name }}</el-tag>
@ -184,6 +185,12 @@
<el-tab-pane label="店铺列表" lazy>
<store :query="{ userId: detail.userId }" :view="views.user" />
</el-tab-pane>
<el-tab-pane label="合伙人列表" lazy>
<store-staff :query="{ mchId: detail.userId }" :view="views.user" />
</el-tab-pane>
<el-tab-pane label="合伙店铺" lazy>
<store-staff :query="{ userId: detail.userId }" :view="views.user" />
</el-tab-pane>
<el-tab-pane label="套餐列表" lazy>
<suit :query="{ userId: detail.userId }" :view="views.user" />
</el-tab-pane>
@ -227,10 +234,7 @@
<real-name :query="{ userId: detail.userId }" :view="views.user" />
</el-tab-pane>
<el-tab-pane label="绑定记录" lazy>
<bind-record
:query="{ userId: detail.userId }"
:view="views.user"
/>
<bind-record :query="{ userId: detail.userId }" :view="views.user"/>
</el-tab-pane>
<el-tab-pane label="收款账户" lazy>
<account :query="{ userId: detail.userId }" :view="views.user" />
@ -286,10 +290,12 @@ import RiskInfo from '@/views/ss/riskInfo/index.vue'
import BindRecord from '@/views/system/bindRecord/index.vue'
import UserFormDialog from '@/views/system/smUser/components/UserFormDialog.vue'
import {isEmpty} from '@/utils/index'
import StoreStaff from '@/views/ss/storeStaff/index.vue'
export default {
name: 'User/:userId',
mixins: [$view, $serviceType],
dicts: ['sm_user_type', 'service_type', 'withdraw_service_type'],
dicts: ['sm_user_type', 'service_type', 'withdraw_service_type', 'user_risk_tag'],
components: {
BindRecord,
RiskInfo,
@ -312,7 +318,8 @@ export default {
UserAccount,
UserDevice,
LineChart,
UserFormDialog
UserFormDialog,
StoreStaff
},
data() {
return {

View File

@ -62,6 +62,11 @@
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="风控标签" prop="riskTag" v-if="isShow('realOrUserName')">
<el-select v-model="queryParams.riskTag" placeholder="请选择风控标签" clearable @change="handleQuery">
<el-option v-for="item of dict.type.user_risk_tag" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@ -122,7 +127,7 @@
<user-link :id="d.row.userId" :name="d.row.phonenumber"/>
</template>
<template v-else-if="column.key === 'realOrUserName'">
<user-link :id="d.row.userId" :name="d.row.realOrUserName"/>
<user-link :id="d.row.userId" :name="d.row.realOrUserName" :risk-tag="d.row.riskTag"/>
</template>
<template v-else-if="column.key === 'storeCount'">
{{d.row.storeCount | defaultValue}}
@ -254,7 +259,7 @@ export default {
name: "SmUser",
mixins: [$showColumns, $serviceType, $withdrawServiceType],
components: { BooleanTag, UserConfigDialog, UserLink, UserFormDialog },
dicts: ['sm_user_status', 'sm_user_type', 'sys_user_sex', 'service_type', 'withdraw_service_type'],
dicts: ['sm_user_status', 'sm_user_type', 'sys_user_sex', 'service_type', 'withdraw_service_type', 'user_risk_tag'],
computed: {
SmUserType() {
return SmUserType