Merge branch 'fix/0714-ch'

main
ch 2 years ago
commit ca1149eb9c

@ -1,5 +1,5 @@
VITE_BASE_URL=/api
VITE_BASE_URL=https://k8s-horse-gateway.mashibing.cn
VITE_SOCKET_URL=wss://k8s-horse-gateway.mashibing.cn/ws
#VITE_SOCKET_URL=ws://192.168.10.93:8090/ws
VITE_REQUEST_TIMEOUT=5000
VITE_BROWSER_URL = https://k8s-shop-pc.mashibing.cn
VITE_BROWSER_URL = https://k8s-shop-pc.mashibing.cn
VITE_REQUEST_TIMEOUT=5000

@ -0,0 +1,4 @@
VITE_BASE_URL=https://you-gateway.mashibing.com
VITE_SOCKET_URL=wss://you-gateway.mashibing.com/ws
VITE_REQUEST_TIMEOUT=20000
VITE_BROWSER_URL = https://you.mashibing.com

@ -1,4 +1,4 @@
VITE_BASE_URL=https://k8s-horse-gateway.mashibing.cn/
VITE_BASE_URL=https://k8s-horse-gateway.mashibing.cn
VITE_SOCKET_URL=wss://k8s-horse-gateway.mashibing.cn/ws
VITE_REQUEST_TIMEOUT=20000
VITE_BROWSER_URL = https://k8s-shop-pc.mashibing.cn

61
components.d.ts vendored

@ -0,0 +1,61 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
declare module 'vue' {
export interface GlobalComponents {
ElArea: typeof import('./src/components/ElArea.vue')['default']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('./src/components/extra/ElButton.vue')['default']
ElCard: typeof import('element-plus/es')['ElCard']
ElCascader: typeof import('./src/components/extra/ElCascader.vue')['default']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('./src/components/extra/ElCheckboxGroup.vue')['default']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('./src/components/extra/ElDialog.vue')['default']
ElDropdown: typeof import('./src/components/extra/ElDropdown.vue')['default']
ElEditor: typeof import('./src/components/ElEditor.vue')['default']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('./src/components/extra/ElIcon.vue')['default']
ElImage: typeof import('./src/components/extra/ElImage.vue')['default']
ElInput: typeof import('./src/components/extra/ElInput.vue')['default']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('./src/components/extra/ElRadioGroup.vue')['default']
ElRate: typeof import('element-plus/es')['ElRate']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('./src/components/extra/ElSelect.vue')['default']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('./src/components/extra/ElSwitch.vue')['default']
ElTable: typeof import('./src/components/extra/ElTable.vue')['default']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTooltip: typeof import('./src/components/extra/ElTooltip.vue')['default']
ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload']
ElUploadFile: typeof import('./src/components/ElUploadFile.vue')['default']
ElUploadImage: typeof import('./src/components/ElUploadImage.vue')['default']
Loading: typeof import('element-plus/es')['ElLoadingDirective']
TableList: typeof import('./src/components/TableList.vue')['default']
}
}
export { }

@ -7,7 +7,10 @@
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite",
"server": "vite",
"server:test": "vite --mode test",
"server:bate": "vite --mode bate",
"server:prod": "vite --mode prod",
"build:test": "vite build --mode test",
"build:beta": "vite build --mode beta",
"build:prod": "vite build --mode prod",

@ -1,4 +1,13 @@
/*
* @Author: ch
* @Date: 2022-07-07 17:27:04
* @LastEditors: ch
* @LastEditTime: 2022-07-11 17:47:42
* @Description: file content
*/
import { ElMessage } from '@/plugins/element-plus';
import request from '@/utils/request';
import { CreateUUID } from '@/utils/utils';
// OSS签名
export function sign(serviceName, configId) {
return request({
@ -9,24 +18,32 @@ export function sign(serviceName, configId) {
configId,
},
});
// console.info(serviceName, configId);
// return {
// accessId: 'LTAI4GHRNb5Xn2w5NeHVbR4c',
// policy: 'eyJleHBpcmF0aW9uIjoiMjAyMi0wNC0xNVQyMDowODoyNi4zMTlaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCJ0ZXN0LyJdXX0=',
// signature: 'okaB3sNp3vzyfM0S3ypudaUAZ+0=',
// dir: 'test/',
// host: 'https://msb-edu-dev.oss-cn-beijing.aliyuncs.com',
// expire: '1650053306',
// };
}
export function payCenterSign() {
return request({
url: '/payCenter/oss/ossSignature',
method: 'GET',
});
}
// 上传文件
export async function upload(serviceName, configId, file, cancelToken) {
let oss = await sign(serviceName, configId);
let data = new FormData();
let arr = file.name.split('/');
arr[arr.length - 1] = encodeURIComponent(arr[arr.length - 1]);
data.append('name', arr.join('/'));
data.append('key', `${oss.dir}${'${filename}'}`);
export async function upload(serviceName, configId, file, cancelToken, suffix) {
const _suffix = file.name.substring(file.name.lastIndexOf('.'));
const suffixObj = typeof suffix === 'string' ? suffix.split(',') : suffix;
if (suffixObj && !suffixObj.includes(_suffix)) {
ElMessage.error('上传文件类型错误');
return '';
}
let oss = {};
if (serviceName) {
oss = await sign(serviceName, configId);
} else {
oss = await payCenterSign();
}
const data = new FormData();
const name = CreateUUID() + _suffix;
data.append('name', name);
data.append('key', `${oss.dir}${name}`);
data.append('policy', oss.policy);
data.append('OSSAccessKeyId', oss.accessId);
data.append('Signature', oss.signature);

@ -0,0 +1,61 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:20:02
* @LastEditors: ch
* @LastEditTime: 2022-07-07 11:06:40
* @Description: file content
*/
import request from '@/utils/request.js';
export const create = (data) => {
return request({
url: '/payCenter/appInfo',
method: 'post',
data,
});
};
export const del = (mchPrimaryId) => {
return request({
url: `/payCenter/appInfo/${mchPrimaryId}`,
method: 'delete',
});
};
export const detail = (mchPrimaryId) => {
return request({
url: `/payCenter/appInfo/${mchPrimaryId}`,
method: 'get',
});
};
export const update = (data) => {
return request({
url: '/payCenter/appInfo',
method: 'put',
data,
});
};
export const updateStatus = (params) => {
return request({
url: '/payCenter/appInfo/updateStatus',
method: 'put',
params,
});
};
export const getApplicationList = (params) => {
return request({
url: '/payCenter/appInfo/page',
method: 'get',
params,
});
};
export const getApplicationSelector = (params) => {
return request({
url: '/payCenter/appInfo/appSelector',
method: 'get',
params,
});
};
export const getPayType = () => {
return request({
url: '/payCenter/appInfo/payCode',
method: 'get',
});
};

@ -0,0 +1,61 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:20:02
* @LastEditors: ch
* @LastEditTime: 2022-07-07 10:10:21
* @Description: file content
*/
import request from '@/utils/request.js';
export const create = (data) => {
return request({
url: '/payCenter/mchInfo',
method: 'post',
data,
});
};
export const del = (mchPrimaryId) => {
return request({
url: `/payCenter/mchInfo/${mchPrimaryId}`,
method: 'delete',
});
};
export const detail = (mchPrimaryId) => {
return request({
url: `/payCenter/mchInfo/${mchPrimaryId}`,
method: 'get',
});
};
export const update = (data) => {
return request({
url: '/payCenter/mchInfo',
method: 'put',
data,
});
};
export const updateStatus = (params) => {
return request({
url: '/payCenter/mchInfo/updateStatus',
method: 'put',
params,
});
};
export const getMerchantList = (params) => {
return request({
url: '/payCenter/mchInfo/page',
method: 'get',
params,
});
};
export const getMerchantSelector = () => {
return request({
url: '/payCenter/mchInfo/mchSelector',
method: 'get',
});
};
export const getMerchantPlatform = (params) => {
return request({
url: '/payCenter/mchInfo/mchCode',
method: 'get',
params,
});
};

@ -0,0 +1,21 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:20:02
* @LastEditors: ch
* @LastEditTime: 2022-07-07 14:55:24
* @Description: file content
*/
import request from '@/utils/request.js';
export const detail = (orderId) => {
return request({
url: `/payCenter/payOrder/${orderId}`,
method: 'get',
});
};
export const getOrderList = (params) => {
return request({
url: '/payCenter/payOrder/page',
method: 'get',
params,
});
};

@ -0,0 +1,21 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:20:02
* @LastEditors: ch
* @LastEditTime: 2022-07-07 15:25:01
* @Description: file content
*/
import request from '@/utils/request.js';
export const detail = (refundOrderId) => {
return request({
url: `/payCenter/refundOrder/${refundOrderId}`,
method: 'get',
});
};
export const getOrderList = (params) => {
return request({
url: '/payCenter/refundOrder/page',
method: 'get',
params,
});
};

@ -2,7 +2,7 @@
* @Author: ch
* @Date: 2022-06-07 15:41:05
* @LastEditors: ch
* @LastEditTime: 2022-06-14 15:26:44
* @LastEditTime: 2022-07-04 11:34:14
* @Description: file content
*/
import * as api from '@/api/chat';
@ -166,7 +166,7 @@ const actions = {
/**
* 提交转移会话
*/
submitTransferSession: ({}, data) => {
submitTransferSession: (context, data) => {
return api
.transferCustomerService({
storeId: 1,

@ -150,10 +150,6 @@ const actions = {
data.commentTimeBegin = data.dateRange[0];
data.commentTimeEnd = data.dateRange[1];
}
if (data.scoreList) {
data.commentScoreList = data.scoreList.join(',');
delete data.scoreList;
}
delete data.dateRange;
delete data.pagingCode;
const res = await api.commentList({
@ -171,7 +167,7 @@ const actions = {
commit('setTotal', res?.total || 0);
}
},
async updateShow({}, params) {
async updateShow(context, params) {
const res = await api.updateCommentShow(params);
if (!res) {
ElMessage.error('状态更新失败!');
@ -188,7 +184,7 @@ const actions = {
commit('setDetail', res);
return Promise.resolve(res);
},
async add({}, data) {
async add(context, data) {
const res = await api.commentAdd(data);
if (!res) {
ElMessage.error('回复失败');

@ -0,0 +1,112 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:21:30
* @LastEditors: ch
* @LastEditTime: 2022-07-06 17:18:37
* @Description: file content
*/
import * as api from '@/api/pay/application.js';
import * as mchApi from '@/api/pay/merchant.js';
import { ElMessage, ElMessageBox } from '@/plugins/element-plus';
const state = {
code: 'PayApplicationManagement',
list: [],
detail: {},
total: 0,
opts: {
status: [
{
value: false,
label: '启用',
},
{
value: true,
label: '禁用',
},
],
merchant: [],
payType: [],
},
};
const getters = {};
const mutations = {
setList: (state, data) => (state.list = data),
setPayType: (state, data) => (state.opts.payType = data),
setMerchant: (state, data) => (state.opts.merchant = data),
setTotal: (state, data) => (state.total = data),
setDetail: (state, data) => (state.detail = data),
};
const actions = {
async search({ rootGetters, commit }, params) {
const res = await api.getApplicationList({
...rootGetters['local/page'](state.code),
...params,
});
if (res) {
commit('setList', res?.records.map((i) => ({ ...i, isShow: !i.isDisabled })) || []);
commit('setTotal', res?.total || 0);
}
},
async save({ dispatch }, data) {
let save = data.appPrimaryId ? api.update : api.create;
let res = await save(data);
if (res) {
ElMessage.success('保存成功');
dispatch('search');
} else {
ElMessage.error('保存失败');
}
return res;
},
detail: async (context, id) => {
let res = await api.detail(id);
if (!res) {
ElMessage.error('加载详情失败');
}
return res;
},
del: async ({ dispatch }, id) => {
try {
await ElMessageBox.confirm('数据删除后无法恢复,确定要删除吗?', '危险操作');
let res = await api.del(id);
if (res) {
ElMessage.success('删除成功');
dispatch('search');
} else {
ElMessage.error('删除失败');
}
return res;
} catch (e) {
console.info('取消删除', e);
}
},
async updateStatus({ dispatch }, data) {
let res = await api.updateStatus(data);
if (res) {
ElMessage.success('保存成功');
dispatch('search');
} else {
ElMessage.error('保存失败');
}
return res;
},
async getMerchantList({ commit }) {
const res = await mchApi.getMerchantSelector();
if (res) {
commit('setMerchant', res || []);
}
},
async getPayType({ commit }) {
const res = await api.getPayType();
if (res) {
commit('setPayType', res || []);
}
},
};
export default {
state,
getters,
mutations,
actions,
};

@ -0,0 +1,103 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:21:30
* @LastEditors: ch
* @LastEditTime: 2022-07-06 11:26:06
* @Description: file content
*/
import * as api from '@/api/pay/merchant.js';
import { ElMessage, ElMessageBox } from '@/plugins/element-plus';
const state = {
code: 'PayMerchantManagement',
list: [],
detail: {},
total: 0,
opts: {
status: [
{
value: false,
label: '启用',
},
{
value: true,
label: '禁用',
},
],
platform: [],
},
};
const getters = {};
const mutations = {
setList: (state, data) => (state.list = data),
setPlatform: (state, data) => (state.opts.platform = data),
setTotal: (state, data) => (state.total = data),
setDetail: (state, data) => (state.detail = data),
};
const actions = {
async search({ rootGetters, commit }, params) {
const res = await api.getMerchantList({
...rootGetters['local/page'](state.code),
...params,
});
if (res) {
commit('setList', res?.records.map((i) => ({ ...i, isShow: !i.isDisabled })) || []);
commit('setTotal', res?.total || 0);
}
},
async save({ dispatch }, data) {
let save = data.mchPrimaryId ? api.update : api.create;
let res = await save(data);
if (res) {
ElMessage.success('保存成功');
dispatch('search');
} else {
ElMessage.error('保存失败');
}
return res;
},
detail: async (context, id) => {
let res = await api.detail(id);
if (!res) {
ElMessage.error('加载详情失败');
}
return res;
},
del: async ({ dispatch }, id) => {
try {
await ElMessageBox.confirm('数据删除后无法恢复,确定要删除吗?', '危险操作');
let res = await api.del(id);
if (res) {
ElMessage.success('删除成功');
dispatch('search');
} else {
ElMessage.error('删除失败');
}
return res;
} catch (e) {
console.info('取消删除', e);
}
},
async updateStatus({ dispatch }, data) {
let res = await api.updateStatus(data);
if (res) {
ElMessage.success('保存成功');
dispatch('search');
} else {
ElMessage.error('保存失败');
}
return res;
},
async getMerchantPlatform({ commit }) {
const res = await api.getMerchantPlatform();
if (res) {
commit('setPlatform', res || []);
}
},
};
export default {
state,
getters,
mutations,
actions,
};

@ -0,0 +1,114 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:21:30
* @LastEditors: ch
* @LastEditTime: 2022-07-07 11:37:49
* @Description: file content
*/
import * as appApi from '@/api/pay/application.js';
import * as mchApi from '@/api/pay/merchant.js';
import * as api from '@/api/pay/payOrder.js';
import { ElMessage } from '@/plugins/element-plus';
const state = {
code: 'PayCenterPayOrderManagement',
list: [],
detail: {},
total: 0,
opts: {
notifyStatus: [
{
value: 1,
label: '未通知',
},
{
value: 2,
label: '已通知',
},
{
value: 3,
label: '已响应',
},
],
payStatus: [
{
value: 1,
label: '支付中',
},
{
value: 2,
label: '已关闭',
},
{
value: 3,
label: '支付成功',
},
{
value: 4,
label: '支付失败',
},
{
value: 5,
label: '部分退款',
},
{
value: 6,
label: '全额退款',
},
],
merchant: [],
payType: [],
application: [],
},
};
const getters = {};
const mutations = {
setList: (state, data) => (state.list = data),
setPayType: (state, data) => (state.opts.payType = data),
setMerchant: (state, data) => (state.opts.merchant = data),
setApplication: (state, data) => (state.opts.application = data),
setTotal: (state, data) => (state.total = data),
};
const actions = {
async search({ rootGetters, commit }, params) {
const res = await api.getOrderList({
...rootGetters['local/page'](state.code),
...params,
});
if (res) {
commit('setList', res?.records.map((i) => ({ ...i, isShow: !i.isDisabled })) || []);
commit('setTotal', res?.total || 0);
}
},
detail: async (context, id) => {
let res = await api.detail(id);
if (!res) {
ElMessage.error('加载详情失败');
}
return res;
},
async getMerchantList({ commit }) {
const res = await mchApi.getMerchantSelector();
if (res) {
commit('setMerchant', res || []);
}
},
async getApplicationList({ commit }) {
const res = await appApi.getApplicationSelector();
if (res) {
commit('setApplication', res || []);
}
},
async getPayType({ commit }) {
const res = await appApi.getPayType();
if (res) {
commit('setPayType', res || []);
}
},
};
export default {
state,
getters,
mutations,
actions,
};

@ -0,0 +1,106 @@
/*
* @Author: ch
* @Date: 2022-07-04 15:21:30
* @LastEditors: ch
* @LastEditTime: 2022-07-07 15:25:26
* @Description: file content
*/
import * as appApi from '@/api/pay/application.js';
import * as mchApi from '@/api/pay/merchant.js';
import * as api from '@/api/pay/refundOrder.js';
import { ElMessage } from '@/plugins/element-plus';
const state = {
code: 'PayCenterRefundOrderManagement',
list: [],
detail: {},
total: 0,
opts: {
notifyStatus: [
{
value: 1,
label: '未通知',
},
{
value: 2,
label: '已通知',
},
{
value: 3,
label: '已响应',
},
],
refundStatus: [
{
value: 1,
label: '退款中',
},
{
value: 2,
label: '退款关闭',
},
{
value: 3,
label: '退款成功',
},
{
value: 4,
label: '退款失败',
},
],
merchant: [],
payType: [],
application: [],
},
};
const getters = {};
const mutations = {
setList: (state, data) => (state.list = data),
setPayType: (state, data) => (state.opts.payType = data),
setMerchant: (state, data) => (state.opts.merchant = data),
setApplication: (state, data) => (state.opts.application = data),
setTotal: (state, data) => (state.total = data),
};
const actions = {
async search({ rootGetters, commit }, params) {
const res = await api.getOrderList({
...rootGetters['local/page'](state.code),
...params,
});
if (res) {
commit('setList', res?.records.map((i) => ({ ...i, isShow: !i.isDisabled })) || []);
commit('setTotal', res?.total || 0);
}
},
detail: async (context, id) => {
let res = await api.detail(id);
if (!res) {
ElMessage.error('加载详情失败');
}
return res;
},
async getMerchantList({ commit }) {
const res = await mchApi.getMerchantSelector();
if (res) {
commit('setMerchant', res || []);
}
},
async getApplicationList({ commit }) {
const res = await appApi.getApplicationSelector();
if (res) {
commit('setApplication', res || []);
}
},
async getPayType({ commit }) {
const res = await appApi.getPayType();
if (res) {
commit('setPayType', res || []);
}
},
};
export default {
state,
getters,
mutations,
actions,
};

@ -0,0 +1,204 @@
<!--
* @Author: ch
* @Date: 2022-07-04 16:42:21
* @LastEditors: ch
* @LastEditTime: 2022-07-11 17:06:12
* @Description: file content
-->
<template>
<div>
<el-form class="main" ref="formEl" label-width="120px" :model="form" :rules="rules">
<el-form-item label="商户平台" prop="mchPrimaryId">
<el-select v-model="form.mchPrimaryId" @change="handleChangeMch" :disabled="isEdit">
<el-option
v-for="item in opts.merchant"
:key="item.mchPrimaryId"
:label="item.mchName"
:value="item.mchPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="应用名称" prop="appName">
<el-input v-model="form.appName" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="应用代号" prop="appCode">
<el-input v-model="form.appCode" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="支付方式" prop="payCodes" v-if="form.mchInfo.mchCode">
<el-checkbox-group v-model="form.payCodes">
<el-checkbox v-for="item in payTypeData" :label="item.code" :key="item.code">
{{ item.text }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="应用ID" prop="appId">
<el-input v-model="form.appId" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="签名秘钥" prop="signKey">
<el-input v-model="form.signKey" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="应用状态">
<el-select v-model="form.isDisabled" :clearable="false">
<el-option v-for="item in opts.status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<template v-if="form.mchInfo.mchCode === 'wxpay'">
<el-form-item label="应用Secret" prop="appSecret">
<el-input
type="textarea"
maxlength="400"
show-word-limit
v-model="form.appSecret"
:placeholder="form.wxAppData.appSecret"
/>
</el-form-item>
</template>
<template v-if="form.mchInfo.mchCode === 'alipay'">
<el-form-item label="应用私钥" prop="privateKey">
<el-input
type="textarea"
maxlength="400"
show-word-limit
v-model="form.privateKey"
:placeholder="form.aliAppData.privateKey"
/>
</el-form-item>
<el-form-item label="应用证书" prop="appCertUrl">
<el-upload action="none" accept=".crt" :show-file-list="false" :http-request="handleUpload">
<el-button type="success" v-if="form.aliAppData.hasAppCert || form.appCertUrl">
已上传点击重新上传
</el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
</template>
<el-form-item>
<el-button @click="handleCancel"></el-button>
<el-button :disabled="loading" :loading="submitting" type="primary" @click="handleSave"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="jsx">
import { upload } from '@/api/file';
const store = useStore();
const router = useRouter();
const route = useRoute();
//
const opts = computed(() => store.state.application.opts);
const defaultForm = {
mchInfo: {},
mchPrimaryId: '',
appName: '',
appCode: '',
payCodes: [],
appId: '',
signKey: '',
isDisabled: false,
aliAppData: {
privateKey: '',
appCertUrl: '',
},
wxAppData: {
appSecret: '',
},
};
const defaultRules = {
mchPrimaryId: [{ required: true, message: '请选择商户平台' }],
appName: [{ required: true, message: '应用名称不能为空' }],
appCode: [{ required: true, message: '应用代号不能为空' }],
payCodes: [{ type: 'array', required: true, message: '至少选一个支付方式' }],
appId: [{ required: true, message: '应用ID不能为空' }],
signKey: [{ required: true, message: '签名秘钥不能为空' }],
};
const form = reactive({ ...defaultForm });
const isEdit = computed(() => Boolean(route.params.id));
const payTypeData = computed(() => {
return (
unref(opts).payType.filter((i) => {
return i.mchCode === form.mchInfo.mchCode;
}) || []
);
});
const rules = computed(() => {
let meRules = { ...defaultRules };
if (!isEdit.value) {
meRules.appSecret = [{ required: true, message: '应用Secret不能为空' }];
meRules.privateKey = [{ required: true, message: '应用私钥不能为空' }];
meRules.appCertUrl = [{ required: true, message: '应用证书不能为空' }];
}
return meRules;
});
const formEl = ref(null);
const init = () => {
store.dispatch('application/getMerchantList');
store.dispatch('application/getPayType');
form.mchInfo = {};
formEl.value.resetFields();
let id = route.params.id;
if (id && form.id !== id) {
handlelLoadDetail(id);
}
};
onActivated(init);
/**
* 编辑加载初始数据加载
*/
const handlelLoadDetail = async (id) => {
let res = await store.dispatch('application/detail', id);
res.payCodes = res.payCodes.split(',');
Object.assign(form, res);
};
/**
* 切换商户时需要拿到当前商户信息用来应用判断属于哪个平台
*/
const handleChangeMch = (item) => {
if (!item) {
return false;
}
const mchCode = form.mchInfo.mchCode;
form.mchInfo = unref(opts).merchant.find((i) => i.mchPrimaryId === item);
if (mchCode !== form.mchInfo.mchCode) {
form.payCodes = [];
}
};
/**
* 上传阿里应用证书
*/
const handleUpload = async ({ file }) => {
const res = await upload(null, null, file, null, '.crt');
form.appCertUrl = res;
};
const handleSave = async () => {
try {
await formEl.value.validate();
let data = { ...form };
data.payCodes = data.payCodes.join(',');
if (data.privateKey) {
data.aliAppData.privateKey = data.privateKey;
}
if (data.appCertUrl) {
data.aliAppData.appCertUrl = data.appCertUrl;
}
if (data.appSecret) {
data.wxAppData.appSecret = data.appSecret;
}
const res = await store.dispatch('application/save', data);
if (res) {
handleCancel();
}
} catch (e) {}
};
const handleCancel = () => {
router.push({ name: 'PayApplication' });
};
</script>
<style lang="less" scoped>
.main {
padding-right: 50px;
}
</style>

@ -0,0 +1,204 @@
<!--
* @Author: ch
* @Date: 2022-06-15 17:29:32
* @LastEditors: ch
* @LastEditTime: 2022-07-11 18:07:14
* @Description: file content
-->
<template>
<table-list
v-loading="loading"
:code="code"
:config="config"
:data="list"
:operation="['create', 'search']"
:reset="handleReset"
title="应用"
:total="total"
@create="handleCreate"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item label="所属商户">
<el-select v-model="state.condition.mchPrimaryId">
<el-option
v-for="item in opts.merchant"
:key="item.mchPrimaryId"
:label="item.mchName"
:value="item.mchPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="应用名称">
<el-input v-model="state.condition.appName" />
</el-form-item>
<el-form-item label="应用ID">
<el-input v-model="state.condition.appId" />
</el-form-item>
<el-form-item label="支付方式">
<el-select v-model="state.condition.payCode">
<el-option
v-for="(item, idx) in opts.payType"
:key="idx"
:label="item.text"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="应用状态">
<el-select v-model="state.condition.isDisabled">
<el-option
v-for="(item, idx) in opts.status"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form>
</template>
</table-list>
</template>
<script setup lang="jsx">
import ElButton from '@/components/extra/ElButton.vue';
import ElSwitch from '@/components/extra/ElSwitch.vue';
const router = useRouter();
const store = useStore();
const loading = ref(false);
//
const opts = computed(() => store.state.application.opts);
//
const code = computed(() => store.state.application.code);
const list = computed(() => _.cloneDeep(store.state.application.list));
const total = computed(() => store.state.application.total);
//
const _condition = {
mchPrimaryId: '',
payCode: '',
appId: '',
appName: '',
isDisabled: null,
};
const state = reactive({
condition: { ..._condition },
});
/**
* 搜索
*/
const handleSearch = async () => {
loading.value = true;
await store.dispatch('application/search', { ...state.condition });
loading.value = false;
};
const init = () => {
store.dispatch('application/getMerchantList');
store.dispatch('application/getPayType');
handleSearch();
};
onActivated(init);
/**
* 重置
*/
const handleReset = () => {
state.condition = { ..._condition };
};
const handleCreate = () => {
router.push({ name: 'CreateApplication' });
};
const handleShowHide = (row) => {
store.dispatch('application/updateStatus', {
appPrimaryId: row.appPrimaryId,
isDisabled: !row.isShow,
});
};
const handleEdit = (id) => {
router.push({
name: 'UpdateApplication',
params: {
id,
},
});
};
const handleDelete = (id) => {
store.dispatch('application/del', id);
};
const config = reactive({
columns: [
{
label: '应用名称',
align: 'left',
prop: 'appName',
},
{
label: '应用代号',
align: 'left',
prop: 'appCode',
},
{
label: '应用ID',
align: 'left',
prop: 'appId',
},
{
label: '所属商户',
width: 120,
slots: {
default: ({ row }) => <span>{row.mchInfo.mchName}</span>,
},
},
{
label: '支付方式',
width: 120,
prop: 'payCodes',
},
{
label: '状态',
width: 80,
slots: {
default: ({ row }) => <ElSwitch v-model={row.isShow} onChange={() => handleShowHide(row)} />,
},
},
{
label: '创建时间',
prop: 'createTime',
width: 160,
},
{
label: '操作',
width: 120,
slots: {
default: ({ row }) => (
<div>
<ElButton type="text" onClick={() => handleEdit(row.appPrimaryId)}>
编辑
</ElButton>
<ElButton type="text" onClick={() => handleDelete(row.appPrimaryId)}>
删除
</ElButton>
</div>
),
},
},
],
});
</script>
<style lang="less" scoped>
.batch-show-hide {
margin-left: 20px;
}
:deep(.row-ellipsis) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
:deep(.ctx-link) {
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
</style>

@ -0,0 +1,126 @@
<!--
* @Author: ch
* @Date: 2022-07-04 17:57:55
* @LastEditors: ch
* @LastEditTime: 2022-07-11 17:07:42
* @Description: file content
-->
<template>
<el-form labelWidth="160px" ref="formEl" :rules="rules" :model="form">
<el-form-item label="公钥" prop="publicKey">
<el-input
type="textarea"
maxlength="400"
show-word-limit
:placeholder="modelValue.hasPublicKey"
v-model="form.publicKey"
/>
</el-form-item>
<el-form-item label="公钥证书" prop="aliPayCertUrl">
<el-upload action="none" accept=".crt" :show-file-list="false" :http-request="handleUploadCert">
<el-button type="success" v-if="modelValue.hasAliPayCert || form.aliPayCertUrl">
已上传点击重新上传
</el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
<el-form-item label="根证书" prop="aliPayRootCertUrl">
<el-upload action="none" accept=".crt" :show-file-list="false" :http-request="handleUploadRootCert">
<el-button type="success" v-if="modelValue.hasAliPayRootCert || form.aliPayRootCertUrl">
已上传点击重新上传
</el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
</el-form>
</template>
<script setup lang="jsx">
import { upload } from '@/api/file';
const route = useRoute();
const emits = defineEmits(['update:modelValue']);
const attrs = useAttrs();
const createRules = {
publicKey: [{ required: true, message: '公钥不能为空' }],
aliPayCertUrl: [{ required: true, message: '请上传公钥证书' }],
aliPayRootCertUrl: [{ required: true, message: '请上传根证书' }],
};
const editRules = {
publicKey: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasPublicKey) {
cb(new Error('公钥不能为空'));
} else {
cb();
}
},
},
],
aliPayCertUrl: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasAliPayCert) {
cb(new Error('请上传公钥证书'));
} else {
cb();
}
},
},
],
aliPayRootCertUrl: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasAliPayRootCert) {
cb(new Error('请上传根证书'));
} else {
cb();
}
},
},
],
};
const rules = computed(() => {
return route.name === 'UpdateMerchant' ? editRules : createRules;
});
const form = reactive({
publicKey: '',
aliPayRootCertUrl: '',
aliPayCertUrl: '',
});
const formEl = ref();
const modelValue = computed(() => attrs.modelValue);
watch(
() => toRefs(form),
() => {
emits('update:modelValue', Object.assign(unref(modelValue), form));
}
);
/**
* 上传公钥证书
*/
const handleUploadCert = async ({ file }) => {
const res = await upload(null, null, file, null, '.crt');
form.aliPayCertUrl = res;
};
/**
* 上传根证书
*/
const handleUploadRootCert = async ({ file }) => {
const res = await upload(null, null, file, null, '.crt');
form.aliPayRootCertUrl = res;
};
/**
* 验证方法暴露给父组件
*/
const validate = async () => {
await formEl.value.validate();
};
const resetFields = () => {
formEl.value.resetFields();
};
defineExpose({
validate,
resetFields,
});
</script>

@ -0,0 +1,122 @@
<!--
* @Author: ch
* @Date: 2022-07-04 16:42:21
* @LastEditors: ch
* @LastEditTime: 2022-07-07 16:38:06
* @Description: file content
-->
<template>
<div>
<el-form class="main" ref="formEl" label-width="160px" :model="form" :rules="rules">
<el-form-item label="商户平台" prop="mchCode">
<el-radio-group v-model="form.mchCode" :disabled="idEdit">
<el-radio v-for="item in opts.platform" :key="item.code" :label="item.code" border>
{{ item.text }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商户名称" prop="mchName">
<el-input v-model="form.mchName" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="商户ID" prop="mchId">
<el-input v-model="form.mchId" maxlength="64" show-word-limit />
</el-form-item>
<el-form-item label="商户状态" prop="disabled">
<el-select v-model="form.isDisabled" :clearable="false">
<el-option v-for="item in opts.status" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<Ali v-if="form.mchCode === 'alipay'" ref="aliFormEl" v-model="form.aliMchData" :detai="aliMchData" />
<Wx v-if="form.mchCode === 'wxpay'" v-model="form.wxMchData" ref="wxFormEl" />
<el-form-item>
<el-button @click="handleCancel"></el-button>
<el-button :disabled="loading" :loading="submitting" type="primary" @click="handleSave"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="jsx">
import Ali from './ali.vue';
import Wx from './wx.vue';
const store = useStore();
const router = useRouter();
const route = useRoute();
//
const opts = computed(() => store.state.merchant.opts);
const defaultForm = {
isDisabled: false,
mchCode: route.params.id ? '' : 'wxpay',
mchName: '',
mchId: '',
aliMchData: {},
wxMchData: {},
};
const form = reactive({ ...defaultForm });
const rules = reactive({
mchName: [{ required: true, message: '商户名称不能为空' }],
mchId: [{ required: true, message: '商户ID不能为空' }],
});
const idEdit = computed(() => Boolean(route.params.id));
const formEl = ref();
const aliFormEl = ref();
const wxFormEl = ref();
const init = () => {
store.dispatch('merchant/getMerchantPlatform');
formEl.value.resetFields();
wxFormEl.value && wxFormEl.value.resetFields();
aliFormEl.value && aliFormEl.value.resetFields();
let id = route.params.id;
if (id && form.id !== id) {
handlelLoadDetail(id);
}
};
onActivated(init);
/**
* 如果是编辑需要加载初始数据加载
*/
const handlelLoadDetail = async (id) => {
let res = await store.dispatch('merchant/detail', id);
if (res.mchCode === 'alipay') {
const publicKey = res.aliMchData.publicKey;
if (publicKey) {
res.aliMchData.hasPublicKey = publicKey;
delete res.aliMchData.publicKey;
}
} else {
const { apiKey, apiKeyV3, serialNo } = res.wxMchData;
res.wxMchData.hasApiKey = apiKey;
delete res.wxMchData.apiKey;
res.wxMchData.hasApiKeyV3 = apiKeyV3;
delete res.wxMchData.apiKeyV3;
res.wxMchData.hasSerialNo = serialNo;
delete res.wxMchData.serialNo;
}
Object.assign(form, res);
};
const handleSave = async () => {
let validate = false;
if (form.mchCode === 'wxpay') {
validate = wxFormEl.value.validate;
} else {
validate = aliFormEl.value.validate;
}
Promise.all([formEl.value.validate(), validate()])
.then(async () => {
const res = await store.dispatch('merchant/save', form);
if (res) {
handleCancel();
}
})
.catch(() => {});
};
const handleCancel = () => {
router.push({ name: 'PayMerchant' });
};
</script>
<style lang="less" scoped>
.main {
padding-right: 50px;
}
</style>

@ -0,0 +1,182 @@
<!--
* @Author: ch
* @Date: 2022-07-04 17:57:45
* @LastEditors: ch
* @LastEditTime: 2022-07-11 17:06:45
* @Description: file content
-->
<template>
<el-form labelWidth="160px" ref="formEl" :rules="rules" :model="form">
<el-form-item label="API秘钥" prop="apiKey">
<el-input
maxlength="64"
show-word-limit
v-model="form.apiKey"
:placeholder="modelValue.hasApiKey || '请输入'"
/>
</el-form-item>
<el-form-item label="v3秘钥" prop="apiKeyV3">
<el-input maxlength="64" show-word-limit v-model="form.apiKeyV3" :placeholder="modelValue.hasApiKeyV3" />
</el-form-item>
<el-form-item label="证书序列号" prop="serialNo">
<el-input maxlength="64" show-word-limit v-model="form.serialNo" :placeholder="modelValue.hasSerialNo" />
</el-form-item>
<el-form-item label="私钥证书(key.pem)" prop="keyOssUrl">
<el-upload action="none" accept=".pem" :show-file-list="false" :http-request="handleUploadKeyCert">
<el-button type="success" v-if="modelValue.hasKey || form.keyOssUrl"></el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
<el-form-item label="商户证书(cert.pem)" prop="certOssUrl">
<el-upload action="none" accept=".pem" :show-file-list="false" :http-request="handleUploadCert">
<el-button type="success" v-if="modelValue.hasCert || form.certOssUrl"></el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
<el-form-item label="p12证书(cert.p12)" prop="certP12OssUrl">
<el-upload action="none" accept=".p12" :show-file-list="false" :http-request="handleUploadCert120">
<el-button type="success" v-if="modelValue.hasCertP12 || form.certP12OssUrl">
已上传点击重新上传
</el-button>
<el-button type="primary" v-else></el-button>
</el-upload>
</el-form-item>
</el-form>
</template>
<script setup lang="jsx">
import { upload } from '@/api/file';
const route = useRoute();
const emits = defineEmits(['update:modelValue']);
const attrs = useAttrs();
const createRules = {
apiKey: [{ required: true, message: 'API秘钥不能为空' }],
apiKeyV3: [{ required: true, message: 'v3秘钥不能为空' }],
serialNo: [{ required: true, message: '证书序列号不能为空' }],
certOssUrl: [{ required: true, message: '请上传根商户证书' }],
keyOssUrl: [{ required: true, message: '请上传私钥证书' }],
certP12OssUrl: [{ required: true, message: '请上传p12证书' }],
};
const editRules = {
apiKey: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasApiKey) {
cb(new Error('API秘钥不能为空'));
} else {
cb();
}
},
},
],
apiKeyV3: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasApiKeyV3) {
cb(new Error('v3秘钥不能为空'));
} else {
cb();
}
},
},
],
serialNo: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasSerialNo) {
cb(new Error('证书序列号不能为空'));
} else {
cb();
}
},
},
],
certOssUrl: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasCert) {
cb(new Error('请上传根商户证书'));
} else {
cb();
}
},
},
],
keyOssUrl: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasKey) {
cb(new Error('请上传私钥证书'));
} else {
cb();
}
},
},
],
certP12OssUrl: [
{
validator: (rule, val, cb) => {
if (!val && !modelValue.value.hasCertP12) {
cb(new Error('请上传p12证书'));
} else {
cb();
}
},
},
],
};
const form = reactive({
apiKey: '',
apiKeyV3: '',
serialNo: '',
certOssUrl: '',
keyOssUrl: '',
certP12OssUrl: '',
});
const rules = computed(() => {
return route.name === 'UpdateMerchant' ? editRules : createRules;
});
const modelValue = computed(() => attrs.modelValue);
const formEl = ref();
watch(
() => toRefs(form),
() => {
emits('update:modelValue', Object.assign(unref(modelValue), form));
}
);
/**
* 上传公钥证书
*/
const handleUploadCert = async ({ file }) => {
const res = await upload(null, null, file, null, '.pem');
form.certOssUrl = res;
};
/**
* 上传私钥证书
*/
const handleUploadKeyCert = async ({ file }) => {
const res = await upload(null, null, file, null, '.pem');
form.keyOssUrl = res;
};
/**
* 上传p12证书
*/
const handleUploadCert120 = async ({ file }) => {
const res = await upload(null, null, file, null, '.p12');
form.certP12OssUrl = res;
};
/**
* 验证方法暴露给父组件
*/
const validate = async () => {
await formEl.value.validate();
};
const resetFields = () => {
formEl.value.resetFields();
};
defineExpose({
validate,
resetFields,
});
</script>

@ -0,0 +1,180 @@
<!--
* @Author: ch
* @Date: 2022-06-15 17:29:32
* @LastEditors: ch
* @LastEditTime: 2022-07-07 16:31:04
* @Description: file content
-->
<template>
<table-list
v-loading="loading"
:code="code"
:config="config"
:data="list"
:operation="['create', 'search']"
:reset="handleReset"
title="商户"
:total="total"
@create="handleCreate"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item label="商户名称">
<el-input v-model="state.condition.mchName" />
</el-form-item>
<el-form-item label="商户ID">
<el-input v-model="state.condition.mchId" />
</el-form-item>
<el-form-item label="商户平台">
<el-select v-model="state.condition.mchCode">
<el-option
v-for="(item, idx) in opts.platform"
:key="idx"
:label="item.text"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="商户状态">
<el-select v-model="state.condition.isDisabled">
<el-option
v-for="(item, idx) in opts.status"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form>
</template>
</table-list>
</template>
<script setup lang="jsx">
import ElButton from '@/components/extra/ElButton.vue';
import ElSwitch from '@/components/extra/ElSwitch.vue';
const router = useRouter();
const store = useStore();
const loading = ref(false);
//
const opts = computed(() => store.state.merchant.opts);
//
const code = computed(() => store.state.merchant.code);
const list = computed(() => _.cloneDeep(store.state.merchant.list));
const total = computed(() => store.state.merchant.total);
//
const _condition = {
mchCode: '',
mchId: '',
mchName: '',
isDisabled: null,
};
const state = reactive({
condition: { ..._condition },
});
const init = () => {
store.dispatch('merchant/getMerchantPlatform');
handleSearch();
};
onActivated(init);
/**
* 搜索
*/
const handleSearch = async () => {
loading.value = true;
await store.dispatch('merchant/search', { ...state.condition });
loading.value = false;
};
/**
* 重置
*/
const handleReset = () => {
state.condition = { ..._condition };
};
const handleCreate = () => {
router.push('./create');
};
const handleShowHide = (row) => {
store.dispatch('merchant/updateStatus', {
mchPrimaryId: row.mchPrimaryId,
isDisabled: !row.isShow,
});
};
const handleDetail = (id) => {
router.push({
name: 'UpdateMerchant',
params: {
id,
},
});
};
const handleDelete = (id) => {
store.dispatch('merchant/del', id);
};
const config = reactive({
columns: [
{
label: '商户名称',
align: 'left',
prop: 'mchName',
},
{
label: '商户ID',
align: 'left',
prop: 'mchId',
},
{
label: '商户平台',
width: 120,
prop: 'mchCodeText',
},
{
label: '状态',
width: 80,
slots: {
default: ({ row }) => <ElSwitch v-model={row.isShow} onChange={() => handleShowHide(row)} />,
},
},
{
label: '创建时间',
prop: 'createTime',
width: 160,
},
{
label: '操作',
width: 120,
slots: {
default: ({ row }) => (
<div>
<ElButton type="text" onClick={() => handleDetail(row.mchPrimaryId)}>
编辑
</ElButton>
<ElButton type="text" onClick={() => handleDelete(row.mchPrimaryId)}>
删除
</ElButton>
</div>
),
},
},
],
});
</script>
<style lang="less" scoped>
.batch-show-hide {
margin-left: 20px;
}
:deep(.row-ellipsis) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
:deep(.ctx-link) {
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
</style>

@ -0,0 +1,58 @@
<!--
* @Author: ch
* @Date: 2022-07-07 14:29:36
* @LastEditors: ch
* @LastEditTime: 2022-07-07 15:22:53
* @Description: file content
-->
<template>
<div class="main">
<el-descriptions title="支付订单信息" border :column="2">
<el-descriptions-item label="所属商户">{{ detail.mchInfo?.mchName }}</el-descriptions-item>
<el-descriptions-item label="所属应用">{{ detail.appInfo?.appName }}</el-descriptions-item>
<el-descriptions-item label="支付订单号">{{ detail.payOrderNo }}</el-descriptions-item>
<el-descriptions-item label="订单金额">{{ detail.amount }}</el-descriptions-item>
<el-descriptions-item label="商品标题">{{ detail.subject }}</el-descriptions-item>
<el-descriptions-item label="商品描述">{{ detail.body }}</el-descriptions-item>
<el-descriptions-item label="支付方式">{{ detail.payCodeText }}</el-descriptions-item>
<el-descriptions-item label="下单时间">{{ detail.createTime }}</el-descriptions-item>
<el-descriptions-item label="订单状态">{{ detail.payStatusText }}</el-descriptions-item>
<el-descriptions-item label="支付时间">{{ detail.successTime }}</el-descriptions-item>
<el-descriptions-item label="通知状态">{{ detail.notifyStatusText }}</el-descriptions-item>
<el-descriptions-item label="通知地址">{{ detail.notifyUrl }}</el-descriptions-item>
<el-descriptions-item label="已退款金额">{{ detail.refundAmount }}</el-descriptions-item>
<el-descriptions-item label="退款次数">{{ detail.refundTimes }}</el-descriptions-item>
<el-descriptions-item label="支付渠道订单">{{ detail.channelPayOrderNo }}</el-descriptions-item>
<el-descriptions-item label="支付渠道用户ID">{{ detail.channelUserId }}</el-descriptions-item>
</el-descriptions>
<el-descriptions title="渠道订单信息" :column="1" class="channel">
<el-descriptions-item label="发起支付参数">
<el-input type="textarea" rows="2" v-model="detail.channelRequest" readonly />
</el-descriptions-item>
<el-descriptions-item label="发起支付响应">
<el-input type="textarea" v-model="detail.channelResponse" readonly />
</el-descriptions-item>
<el-descriptions-item label="渠道支付回调">
<el-input type="textarea" v-model="detail.channelNotify" readonly />
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
const store = useStore();
const route = useRoute();
let detail = reactive({});
const getDetail = async () => {
const res = await store.dispatch('payOrder/detail', route.params.id);
detail = Object.assign(detail, res);
};
onActivated(getDetail);
</script>
<style lang="less" scoped>
.main {
padding: 30px !important;
}
.channel {
padding: 30px 0;
}
</style>

@ -0,0 +1,232 @@
<!--
* @Author: ch
* @Date: 2022-06-15 17:29:32
* @LastEditors: ch
* @LastEditTime: 2022-07-07 16:34:27
* @Description: file content
-->
<template>
<table-list
v-loading="loading"
:code="code"
:config="config"
:data="list"
:operation="['search']"
:reset="handleReset"
:total="total"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item label="支付订单号">
<el-input v-model="state.condition.payOrderNo" />
</el-form-item>
<el-form-item label="所属商户">
<el-select v-model="state.condition.mchPrimaryId">
<el-option
v-for="item in opts.merchant"
:key="item.mchPrimaryId"
:label="item.mchName"
:value="item.mchPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="所属应用">
<el-select v-model="state.condition.appPrimaryId">
<el-option
v-for="item in opts.application"
:key="item.appPrimaryId"
:label="item.appName"
:value="item.appPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="支付方式">
<el-select v-model="state.condition.payCode">
<el-option
v-for="(item, idx) in opts.payType"
:key="idx"
:label="item.text"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="订单状态">
<el-select v-model="state.condition.payStatus">
<el-option
v-for="(item, idx) in opts.payStatus"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="通知状态">
<el-select v-model="state.condition.notifyStatus">
<el-option
v-for="(item, idx) in opts.notifyStatus"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="下单时间" prop="dateRange">
<el-date-picker
v-model="state.condition.dateRange"
:default-time="[new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 23, 59, 59)]"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-form>
</template>
</table-list>
</template>
<script setup lang="jsx">
import ElButton from '@/components/extra/ElButton.vue';
import ElSwitch from '@/components/extra/ElSwitch.vue';
const router = useRouter();
const store = useStore();
const loading = ref(false);
//
const opts = computed(() => store.state.payOrder.opts);
//
const code = computed(() => store.state.payOrder.code);
const list = computed(() => _.cloneDeep(store.state.payOrder.list));
const total = computed(() => store.state.payOrder.total);
//
const _condition = {
mchPrimaryId: '',
appPrimaryId: '',
payOrderNo: '',
payCode: '',
payStatus: '',
notifyStatus: '',
dateRange: '',
};
const state = reactive({
condition: { ..._condition },
});
store.dispatch('payOrder/getPayType');
const init = () => {
store.dispatch('payOrder/getMerchantList');
store.dispatch('payOrder/getApplicationList');
handleSearch();
};
onActivated(init);
/**
* 搜索
*/
const handleSearch = async () => {
loading.value = true;
let par = { ...state.condition };
if (par.dateRange?.length) {
par.startTime = par.dateRange[0];
par.endTime = par.dateRange[1];
delete par.dateRange;
}
await store.dispatch('payOrder/search', par);
loading.value = false;
};
/**
* 重置
*/
const handleReset = () => {
state.condition = { ..._condition };
};
const handleDetail = (id) => {
router.push({
name: 'PayOrderDetail',
params: {
id,
},
});
};
const config = reactive({
columns: [
{
label: '所属商户',
align: 'left',
slots: {
default: ({ row }) => <span class="row-ellipsis">{row.mchInfo?.mchName}</span>,
},
},
{
label: '所属应用',
align: 'left',
slots: {
default: ({ row }) => <span class="row-ellipsis">{row.appInfo?.appName}</span>,
},
},
{
label: '支付订单号',
minWidth: 110,
prop: 'payOrderNo',
slots: {
default: ({ row }) => <span>{row.payOrderNo}</span>,
},
},
{
label: '支付方式',
width: 150,
prop: 'payCodeText',
},
{
label: '订单金额',
prop: 'amount',
width: 90,
},
{
label: '订单状态',
width: 90,
prop: 'payStatusText',
},
{
label: '通知状态',
width: 90,
prop: 'notifyStatusText',
},
{
label: '下单时间',
prop: 'createTime',
minWidth: 100,
slots: {
default: ({ row }) => <span>{row.createTime}</span>,
},
},
{
label: '操作',
width: 60,
slots: {
default: ({ row }) => (
<div>
<ElButton type="text" onClick={() => handleDetail(row.payOrderId)}>
详情
</ElButton>
</div>
),
},
},
],
});
</script>
<style lang="less" scoped>
.batch-show-hide {
margin-left: 20px;
}
:deep(.row-ellipsis) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
:deep(.ctx-link) {
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
</style>

@ -0,0 +1,55 @@
<!--
* @Author: ch
* @Date: 2022-07-07 14:29:36
* @LastEditors: ch
* @LastEditTime: 2022-07-09 10:41:24
* @Description: file content
-->
<template>
<div class="main">
<el-descriptions title="退款订单信息" border :column="2">
<el-descriptions-item label="所属商户">{{ detail.mchInfo?.mchName }}</el-descriptions-item>
<el-descriptions-item label="所属应用">{{ detail.appInfo?.appName }}</el-descriptions-item>
<el-descriptions-item label="支付订单号">{{ detail.payOrderInfo?.payOrderNo }}</el-descriptions-item>
<el-descriptions-item label="退款订单号">{{ detail.refundOrderNo }}</el-descriptions-item>
<el-descriptions-item label="订单金额">{{ detail.payOrderInfo?.amount }}</el-descriptions-item>
<el-descriptions-item label="退款金额">{{ detail.refundAmount }}</el-descriptions-item>
<el-descriptions-item label="退款状态">{{ detail.refundStatusText }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ detail.createTime }}</el-descriptions-item>
<el-descriptions-item label="通知状态">{{ detail.notifyStatusText }}</el-descriptions-item>
<el-descriptions-item label="通知地址">{{ detail.notifyUrl }}</el-descriptions-item>
<el-descriptions-item label="退款渠道订单">
{{ detail.channelRefundOrderNo }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions title="渠道订单信息" :column="1" class="channel">
<el-descriptions-item label="发起退款参数">
<el-input type="textarea" rows="2" v-model="detail.channelRequest" readonly />
</el-descriptions-item>
<el-descriptions-item label="发起退款响应">
<el-input type="textarea" v-model="detail.channelResponse" readonly />
</el-descriptions-item>
<el-descriptions-item label="渠道退款回调">
<el-input type="textarea" v-model="detail.channelNotify" readonly />
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
const store = useStore();
const route = useRoute();
let detail = reactive({});
const getDetail = async () => {
const res = await store.dispatch('refundOrder/detail', route.params.id);
detail = Object.assign(detail, res);
};
onActivated(getDetail);
</script>
<style lang="less" scoped>
.main {
padding: 30px !important;
}
.channel {
padding: 30px 0;
}
</style>

@ -0,0 +1,231 @@
<!--
* @Author: ch
* @Date: 2022-06-15 17:29:32
* @LastEditors: ch
* @LastEditTime: 2022-07-07 16:33:53
* @Description: file content
-->
<template>
<table-list
v-loading="loading"
:code="code"
:config="config"
:data="list"
:operation="['search']"
:reset="handleReset"
:total="total"
@search="handleSearch"
>
<template #search>
<el-form inline>
<el-form-item label="支付订单号">
<el-input v-model="state.condition.payOrderNo" />
</el-form-item>
<el-form-item label="退款订单号">
<el-input v-model="state.condition.refundOrderNo" />
</el-form-item>
<el-form-item label="所属商户">
<el-select v-model="state.condition.mchPrimaryId">
<el-option
v-for="item in opts.merchant"
:key="item.mchPrimaryId"
:label="item.mchName"
:value="item.mchPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="所属应用">
<el-select v-model="state.condition.appPrimaryId">
<el-option
v-for="item in opts.application"
:key="item.appPrimaryId"
:label="item.appName"
:value="item.appPrimaryId"
/>
</el-select>
</el-form-item>
<el-form-item label="退款状态">
<el-select v-model="state.condition.refundStatus">
<el-option
v-for="(item, idx) in opts.refundStatus"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="通知状态">
<el-select v-model="state.condition.notifyStatus">
<el-option
v-for="(item, idx) in opts.notifyStatus"
:key="idx"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="申请时间" prop="dateRange">
<el-date-picker
v-model="state.condition.dateRange"
:default-time="[new Date(0, 0, 0, 0, 0, 0), new Date(0, 0, 0, 23, 59, 59)]"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-form>
</template>
</table-list>
</template>
<script setup lang="jsx">
import ElButton from '@/components/extra/ElButton.vue';
import ElSwitch from '@/components/extra/ElSwitch.vue';
const router = useRouter();
const store = useStore();
const loading = ref(false);
//
const opts = computed(() => store.state.refundOrder.opts);
//
const code = computed(() => store.state.refundOrder.code);
const list = computed(() => _.cloneDeep(store.state.refundOrder.list));
const total = computed(() => store.state.refundOrder.total);
//
const _condition = {
mchPrimaryId: '',
appPrimaryId: '',
payOrderNo: '',
refundOrderNo: '',
refundStatus: '',
notifyStatus: '',
dateRange: '',
};
const state = reactive({
condition: { ..._condition },
});
store.dispatch('refundOrder/getPayType');
const init = () => {
store.dispatch('refundOrder/getMerchantList');
store.dispatch('refundOrder/getApplicationList');
handleSearch();
};
onActivated(init);
/**
* 搜索
*/
const handleSearch = async () => {
loading.value = true;
let par = { ...state.condition };
if (par.dateRange?.length) {
par.startTime = par.dateRange[0];
par.endTime = par.dateRange[1];
delete par.dateRange;
}
await store.dispatch('refundOrder/search', par);
loading.value = false;
};
/**
* 重置
*/
const handleReset = () => {
state.condition = { ..._condition };
};
const handleDetail = (id) => {
router.push({
name: 'RefundOrderDetail',
params: {
id,
},
});
};
const config = reactive({
columns: [
{
label: '所属商户',
align: 'left',
slots: {
default: ({ row }) => <span class="row-ellipsis">{row.mchInfo?.mchName}</span>,
},
},
{
label: '所属应用',
align: 'left',
slots: {
default: ({ row }) => <span class="row-ellipsis">{row.appInfo?.appName}</span>,
},
},
{
label: '支付订单号',
minWidth: 110,
slots: {
default: ({ row }) => <span>{row.payOrderInfo?.payOrderNo}</span>,
},
},
{
label: '退款订单号',
minWidth: 110,
slots: {
default: ({ row }) => <span>{row.refundOrderNo}</span>,
},
},
{
label: '订单金额',
width: 90,
slots: {
default: ({ row }) => <span>{row.payOrderInfo.amount}</span>,
},
},
{
label: '退款金额',
prop: 'refundAmount',
width: 90,
},
{
label: '退款状态',
width: 90,
prop: 'refundStatusText',
},
{
label: '通知状态',
width: 90,
prop: 'notifyStatusText',
},
{
label: '申请时间',
prop: 'createTime',
minWidth: 100,
slots: {
default: ({ row }) => <span>{row.createTime}</span>,
},
},
{
label: '操作',
width: 60,
slots: {
default: ({ row }) => (
<div>
<ElButton type="text" onClick={() => handleDetail(row.refundOrderId)}>
详情
</ElButton>
</div>
),
},
},
],
});
</script>
<style lang="less" scoped>
:deep(.row-ellipsis) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
:deep(.ctx-link) {
cursor: pointer;
&:hover {
color: var(--el-color-primary);
}
}
</style>

@ -16,12 +16,12 @@ export default (configEnv) => {
return {
server: {
host: '0.0.0.0',
port: 3000,
port: 3001,
open: false,
proxy: {
'/api': {
target: 'https://k8s-horse-gateway.mashibing.cn/', // 测试地址
// target: 'https://you-gateway.mashibing.com', // 生产环境
// target: 'https://k8s-horse-gateway.mashibing.cn/', // 测试地址
target: 'https://you-gateway.mashibing.com', // 生产环境
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
@ -67,13 +67,13 @@ export default (configEnv) => {
dts: 'src/auto-imports.d.ts',
}),
Components({
dirs: ['src/components'],
extensions: ['vue', 'jsx', 'tsx', 'js', 'ts'],
deep: true,
// dirs: ['src/components'],
// extensions: ['vue', 'jsx', 'tsx', 'js', 'ts'],
// deep: true,
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts',
include: [/\.tsx$/, /\.jsx$/, /\.ts$/, /\.js$/, /\.vue$/, /\.vue\?vue/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/],
// dts: 'src/components.d.ts',
// include: [/\.tsx$/, /\.jsx$/, /\.ts$/, /\.js$/, /\.vue$/, /\.vue\?vue/],
// exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/],
}),
removeConsole(),
globalStyle({
@ -85,7 +85,7 @@ export default (configEnv) => {
{
...eslintPlugin({
eslintOptions: {
cache: true,
cache: false,
},
shouldLint: (path) => /\/src\/[^?]*\.(vue|m?[jt]sx?)$/.test(path),
}),

Loading…
Cancel
Save