ref 单商户前端移植

This commit is contained in:
bootx
2024-10-05 22:12:52 +08:00
parent a9374cf191
commit 096ec5b37b
60 changed files with 147 additions and 2599 deletions

View File

@@ -1,20 +1,17 @@
# 名称
VITE_GLOB_APP_TITLE=DaxPay运营
# 压缩方式
VITE_BUILD_COMPRESS='gzip'
VITE_GLOB_APP_TITLE=DaxPay服务
# 发布路径
VITE_PUBLIC_PATH=/
# 接口地址
VITE_GLOB_API_URL=/admin
VITE_GLOB_API_URL=/server
# 接口前缀
VITE_GLOB_API_URL_PREFIX =
# 终端类型
VITE_GLOB_APP_CLIENT=dax-pay-admin
VITE_GLOB_APP_CLIENT=dax-pay
# 超时时间
VITE_GLOB_API_TIMEOUT=30000

View File

@@ -1,20 +0,0 @@
# 名称
VITE_GLOB_APP_TITLE=DaxPay运营端
# 压缩方式
VITE_BUILD_COMPRESS='gzip'
# 发布路径
VITE_PUBLIC_PATH=/
# 接口地址
VITE_GLOB_API_URL=/admin
# 接口前缀
VITE_GLOB_API_URL_PREFIX =
# 终端类型
VITE_GLOB_APP_CLIENT=dax-pay-admin
# 超时时间
VITE_GLOB_API_TIMEOUT=30000

18
.env.analyze Normal file
View File

@@ -0,0 +1,18 @@
# public path
VITE_PUBLIC_PATH=/
# 是否启用 gzip 或 brotli 压缩
# 可选gzip |brotli | none
# 如果需要多个表单,可以使用 '' 来分隔
VITE_BUILD_COMPRESS='none'
# 基本接口地址 SPA
VITE_GLOB_API_URL=/basic-api
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_ENABLE_ANALYZE=true

View File

@@ -1,5 +1,5 @@
# 名称
VITE_GLOB_APP_TITLE=DaxPay商户
VITE_GLOB_APP_TITLE=DaxPay服务
# 压缩方式
VITE_BUILD_COMPRESS='gzip'
@@ -8,13 +8,13 @@ VITE_BUILD_COMPRESS='gzip'
VITE_PUBLIC_PATH=/
# 接口地址
VITE_GLOB_API_URL=/merchant
VITE_GLOB_API_URL=/server
# 接口前缀
VITE_GLOB_API_URL_PREFIX=
# 终端类型
VITE_GLOB_APP_CLIENT=dax-pay-merchant
VITE_GLOB_APP_CLIENT=dax-pay
# 超时时间
VITE_GLOB_API_TIMEOUT=30000

View File

@@ -1,20 +0,0 @@
# 名称
VITE_GLOB_APP_TITLE=DaxPay商户端
# 压缩方式
VITE_BUILD_COMPRESS='gzip'
# 发布路径
VITE_PUBLIC_PATH=/
# 接口地址
VITE_GLOB_API_URL=/merchant
# 接口前缀
VITE_GLOB_API_URL_PREFIX=
# 终端类型
VITE_GLOB_APP_CLIENT=dax-pay-merchant
# 超时时间
VITE_GLOB_API_TIMEOUT=30000

View File

@@ -1,16 +1,15 @@
{
"name": "daxpay-multi-ui",
"name": "daxpay-single-ui",
"version": "2.11.5",
"homepage": "",
"license": "Apache License v2",
"type": "module",
"scripts": {
"bootstrap": "pnpm install",
"build:analyze": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode admin-build",
"build:admin": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode admin",
"build:merchant": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode merchant-build",
"dev:admin": "pnpm vite --mode admin --port=13000",
"dev:merchant": "pnpm vite --mode merchant --port=13300",
"build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build",
"build:analyze": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode analyze",
"build:no-cache": "pnpm store prune && npm run build",
"dev": "pnpm vite --mode admin --port=13000",
"preinstall": "npx only-allow pnpm",
"postinstall": "turbo run stub",
"lint": "turbo run lint",

View File

@@ -1,14 +0,0 @@
/**
* 终端类型
*/
export enum DaxPayClientEnum {
/**
* 运营端
*/
ADMIN = 'dax-pay-admin',
/**
* 商户端
*/
MERCHANT = 'dax-pay-merchant',
}

View File

@@ -1,7 +1,6 @@
import type { GlobEnvConfig } from '#/config'
import pkg from '../../package.json'
import { API_ADDRESS } from '@/enums/cacheEnum'
import { DaxPayClientEnum } from "@/enums/daxpay/daxpayClientEnum";
export function getCommonStoragePrefix() {
const { VITE_GLOB_APP_TITLE } = getAppEnvConfig()
@@ -78,10 +77,3 @@ export function isDevMode(): boolean {
export function isProdMode(): boolean {
return import.meta.env.PROD
}
/**
* 是否为运营端
*/
export function isAdmin() {
return import.meta.env.VITE_GLOB_APP_CLIENT === DaxPayClientEnum.ADMIN
}

View File

@@ -1,118 +0,0 @@
import { defHttp } from '@/utils/http/axios'
import { PageResult, Result } from '#/axios'
import { BaseEntity } from '#/web'
import { LabeledValue } from 'ant-design-vue/lib/select'
/**
* 分页
*/
export const page = (params) => {
return defHttp.get<Result<PageResult<Merchant>>>({
url: '/merchant/page',
params,
})
}
/**
* 详情
*/
export const get = (id) => {
return defHttp.get<Result<Merchant>>({
url: '/merchant/findById',
params: { id },
})
}
/**
* 新增
*/
export const add = (obj) => {
return defHttp.post<Result<void>>({
url: '/merchant/add',
data: obj,
})
}
/**
* 更新
*/
export const update = (obj) => {
return defHttp.post<Result<void>>({
url: '/merchant/update',
data: obj,
})
}
/**
* 商户下拉列表
*/
export const merchantDropdown = () => {
return defHttp.get<Result<LabeledValue[]>>({
url: '/merchant/dropdown',
})
}
/**
* 删除
*/
export const del = (id) => {
return defHttp.post<Result<void>>({
url: '/merchant/delete',
params: { id },
})
}
/**
* 创建商户管理员
*/
export const createMerchantAdmin = (obj: MerchantAdmin) => {
return defHttp.post<Result<void>>({
url: '/merchant/createAdmin',
data: obj,
})
}
/**
* 商户
*/
export interface Merchant extends BaseEntity {
// 商户号
mchNo?: string
// 商户名称
mchName?: string
// 公司名称
companyName?: string
// 公司联系方式
companyContact?: string
// 公司地址
companyAddress?: string
// 公司信用编码
companyCode?: string
// 法人名称
legalPerson?: string
// 法人证件类型
idType?: string
// 法人证件号
idNo?: string
// 法人联系方式
contact?: string
// 状态
status?: string
}
/**
* 商户管理员创建参数
*/
export interface MerchantAdmin {
// 商户号
mchNo?: string
// 管理员名称
name?: string
// 商户管理员账号
account?: string
// 商户管理员密码
password?: string
// 重复密码
confirmPassword?: string
// 手机号
phone?: string
// 邮箱
email?: string
}

View File

@@ -1,196 +0,0 @@
<template>
<basic-drawer
showFooter
title="创建商户管理员"
v-bind="$attrs"
:width="modalWidth"
:open="visible"
:mask-closable="false"
@close="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form
class="small-from-item"
ref="formRef"
:model="form"
:rules="rules"
:validate-trigger="['blur', 'change']"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="商户名称">
<a-tag color="green">{{ merchant.mchName }}</a-tag>
</a-form-item>
<a-form-item label="商户号">
<a-tag color="green">{{ merchant.mchNo }}</a-tag>
</a-form-item>
<a-form-item label="管理员账号" name="account" validate-first>
<a-input v-model:value="form.account" placeholder="请输入管理员账号" />
</a-form-item>
<a-form-item label="管理员名称" name="name">
<a-input v-model:value="form.name" placeholder="请输入管理员名称" />
</a-form-item>
<a-form-item label="登录密码" name="password" validate-first>
<strength-meter
v-model:value="form.password"
placeholder="请输入登录密码"
@change="validateToNextPassword"
/>
</a-form-item>
<a-form-item label="确认密码" name="confirmPassword" validate-first>
<a-input-password v-model:value="form.confirmPassword" placeholder="请重新输入登录密码" />
</a-form-item>
<a-form-item label="手机号" validate-first name="phone">
<a-input v-model:value="form.phone" placeholder="请输入用户手机号" />
</a-form-item>
<a-form-item label="邮箱" validate-first name="email">
<a-input v-model:value="form.email" placeholder="请输入用户邮箱" />
</a-form-item>
</a-form>
</a-spin>
<template #footer>
<a-space>
<a-button key="cancel" @click="handleCancel">取消</a-button>
<a-button key="forward" :loading="confirmLoading" type="primary" @click="handleOk"
>保存</a-button
>
</a-space>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import { BasicDrawer } from '@/components/Drawer'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { nextTick, reactive, ref } from 'vue'
import StrengthMeter from '/@/components/StrengthMeter/src/StrengthMeter.vue'
import { validateEmail, validateMobile } from '@/utils/validate'
import { existsAccount, existsEmail, existsPhone } from '@/api/sys/userAssist'
import { useMessage } from '@/hooks/web/useMessage'
import { createMerchantAdmin, Merchant, MerchantAdmin } from './Merchant.api'
const { handleCancel, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
const { createMessage } = useMessage()
const merchant = ref<Merchant>({})
const formRef = ref<FormInstance>()
const form = ref<MerchantAdmin>({
name: '',
account: '',
phone: '',
email: '',
password: '',
confirmPassword: '',
})
// 校验
const rules = reactive({
name: [{ required: true, message: '请输入用户名称' }],
account: [
{ required: true, message: '请输入用户账号' },
{ validator: checkAccount, trigger: 'blur' },
],
password: [{ required: true, message: '请输入登录密码!' }],
confirmPassword: [
{ required: true, message: '请重新输入登录密码!' },
{ validator: compareToFirstPassword },
],
phone: [{ validator: validatePhone }, { validator: validateBindPhone, trigger: 'blur' }],
email: [{ validator: validateEmailRule }, { validator: validateBindEmail, trigger: 'blur' }],
} as Record<string, Rule[]>)
let confirmDirty = ref(false)
// 事件
const emits = defineEmits(['ok'])
/**
* 入口
*/
function init(record: Merchant) {
merchant.value = record
form.value.mchNo = record.mchNo
visible.value = true
confirmLoading.value = false
nextTick(() => {
formRef.value?.resetFields()
})
}
function handleOk() {
formRef.value?.validate().then(async () => {
confirmLoading.value = true
await createMerchantAdmin(form.value).finally(() => (confirmLoading.value = false))
createMessage.success('添加用户成功')
confirmLoading.value = false
emits('ok')
handleCancel()
})
}
/**
* 用户名检查
*/
async function checkAccount() {
const { data } = await existsAccount(form.value.account)
return data ? Promise.reject('用户名已存在!') : Promise.resolve()
}
/**
* 密码检查
*/
function validateToNextPassword() {
if (confirmDirty.value) {
formRef.value?.validateFields(['confirmPassword'])
}
}
function compareToFirstPassword() {
if (form.value.confirmPassword !== form.value.password) {
confirmDirty.value = true
return Promise.reject('密码不一致')
} else {
return Promise.resolve()
}
}
/**
* 校验邮箱号
*/
function validateEmailRule() {
const { email } = form.value
if (!email) {
return Promise.resolve()
}
const { msg, result } = validateEmail(email)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验邮箱号是否被使用
*/
async function validateBindEmail() {
const { email } = form.value
const { data } = await existsEmail(email)
return data ? Promise.reject('邮箱已被使用') : Promise.resolve()
}
/**
* 校验手机号
*/
function validatePhone() {
const { phone } = form.value
if (!phone) {
return Promise.resolve()
}
const { msg, result } = validateMobile(phone)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验手机号是否被使用
*/
async function validateBindPhone() {
const { phone } = form.value
const { data } = await existsPhone(phone)
return data ? Promise.reject('手机号已被使用') : Promise.resolve()
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -1,191 +0,0 @@
<template>
<basic-drawer
showFooter
v-bind="$attrs"
width="50%"
:title="title"
:mask-closable="showable"
:open="visible"
@close="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form
class="small-from-item"
:model="form"
ref="formRef"
:validate-trigger="['blur', 'change']"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="主键" name="id" :hidden="true">
<a-input v-model:value="form.id" :disabled="showable" />
</a-form-item>
<a-form-item label="商户号" name="mchNo" v-show="!addable">
<a-input v-model:value="form.mchNo" disabled />
</a-form-item>
<a-form-item label="商户名称" name="mchName">
<a-input v-model:value="form.mchName" :disabled="showable" placeholder="请输入商户名称" />
</a-form-item>
<a-form-item label="公司名称" name="companyName">
<a-input
v-model:value="form.companyName"
:disabled="showable"
placeholder="请输入公司名称"
/>
</a-form-item>
<a-form-item label="公司联系方式" name="companyContact">
<a-input
v-model:value="form.companyContact"
:disabled="showable"
placeholder="请输入公司联系方式"
/>
</a-form-item>
<a-form-item label="公司信用编码" name="companyCode">
<a-input
v-model:value="form.companyCode"
:disabled="showable"
placeholder="请输入公司信用编码"
/>
</a-form-item>
<a-form-item label="公司地址" name="companyAddress">
<a-textarea
v-model:value="form.companyAddress"
:disabled="showable"
placeholder="请输入公司地址"
/>
</a-form-item>
<a-form-item label="法人名称" name="legalPerson">
<a-input
v-model:value="form.legalPerson"
:disabled="showable"
placeholder="请输入法人名称"
/>
</a-form-item>
<a-form-item label="法人联系方式" name="contact">
<a-input
v-model:value="form.contact"
:disabled="showable"
placeholder="请输入法人联系方式"
/>
</a-form-item>
<a-form-item label="法人证件号码" name="idNo">
<a-input
v-model:value="form.idNo"
:disabled="showable"
placeholder="请输入法人证件号码"
/>
</a-form-item>
</a-form>
</a-spin>
<template #footer>
<a-space>
<a-button key="cancel" @click="handleCancel">取消</a-button>
<a-button
v-if="!showable"
key="forward"
:loading="confirmLoading"
type="primary"
@click="handleOk"
>保存</a-button
>
</a-space>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import { nextTick, reactive, ref, unref } from 'vue'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { add, get, Merchant, update } from './Merchant.api'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { FormEditType } from '@/enums/formTypeEnum'
import { BasicDrawer } from '@/components/Drawer'
import { useDict } from '@/hooks/bootx/useDict'
import { LabeledValue } from 'ant-design-vue/lib/select'
const {
initFormEditType,
handleCancel,
labelCol,
wrapperCol,
title,
confirmLoading,
visible,
addable,
showable,
formEditType,
} = useFormEdit()
// 表单
const formRef = ref<FormInstance>()
let form = ref<Merchant>({})
const { dictDropDown } = useDict()
const idTypes = ref<LabeledValue[]>([])
// 校验
const rules = reactive({
mchName: [{ required: true, message: '请输入商户名称' }],
companyName: [{ required: true, message: '请输入公司名称' }],
} as Record<string, Rule[]>)
// 事件
const emits = defineEmits(['ok'])
// 入口
function init(id, editType: FormEditType) {
initData()
initFormEditType(editType)
resetForm()
getInfo(id, editType)
}
/**
* 初始化数据
*/
function initData() {
dictDropDown('id_type').then((data) => {
idTypes.value = data
})
}
/**
* 获取信息
*/
function getInfo(id, editType: FormEditType) {
if ([FormEditType.Edit, FormEditType.Show].includes(editType)) {
confirmLoading.value = true
get(id).then(({ data }) => {
form.value = data
confirmLoading.value = false
})
} else if (editType === FormEditType.Add) {
confirmLoading.value = false
}
}
// 保存
function handleOk() {
formRef.value?.validate().then(async () => {
confirmLoading.value = true
if (formEditType.value === FormEditType.Add) {
await add(unref(form)).finally(() => (confirmLoading.value = false))
} else if (formEditType.value === FormEditType.Edit) {
await update(unref(form)).finally(() => (confirmLoading.value = false))
}
handleCancel()
emits('ok')
})
}
/**
* 重置表单的校验
*/
function resetForm() {
nextTick(() => formRef.value?.resetFields())
}
defineExpose({
init,
})
</script>
<style lang="less" scoped></style>

View File

@@ -1,173 +0,0 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query
:query-params="model.queryParam"
:fields="fields"
@query="queryPage"
@reset="resetQueryParams"
/>
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }">
<template #buttons>
<a-space>
<a-button type="primary" pre-icon="ant-design:plus-outlined" @click="add"
>新建</a-button
>
</a-space>
</template>
</vxe-toolbar>
<div class="h-65vh">
<vxe-table
height="auto"
ref="xTable"
key-field="id"
:data="pagination.records"
:loading="loading"
>
<vxe-column type="seq" :width="60" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="mchName" title="商户名称" :min-width="150" />
<vxe-column field="companyName" title="公司名称" :min-width="180" />
<vxe-column field="companyContact" title="联系方式" :min-width="120" />
<vxe-column field="companyCode" title="信用编码" :min-width="180" />
<vxe-column field="administrator" title="关联管理员" :min-width="120" align="center">
<template #default="{ row }">
<a-tag v-if="row.administrator" @click="showAdmin(row)" color="green"
><a-link>查看管理员</a-link></a-tag
>
<a-tag v-else><a-link danger @click="createAdmin(row)">创建管理员</a-link></a-tag>
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间" :min-width="170" />
<vxe-column fixed="right" :width="150" :showOverflow="false" title="操作">
<template #default="{ row }">
<span>
<a-link @click="show(row)">查看</a-link>
</span>
<a-divider type="vertical" />
<span>
<a-link @click="edit(row)">编辑</a-link>
</span>
<a-divider type="vertical" />
<a-link danger @click="remove(row)">删除</a-link>
</template>
</vxe-column>
</vxe-table>
</div>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
<MerchantEdit ref="merchantEdit" @ok="queryPage" />
<MerchantCreateAdmin ref="merchantCreateAdmin" />
<UserShow ref="userShow" />
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { del, page } from './Merchant.api'
import useTablePage from '@/hooks/bootx/useTablePage'
import MerchantEdit from './MerchantEdit.vue'
import BQuery from '@/components/Bootx/Query/BQuery.vue'
import { QueryField, STRING } from '@/components/Bootx/Query/Query'
import { FormEditType } from '@/enums/formTypeEnum'
import { useMessage } from '@/hooks/web/useMessage'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import ALink from '@/components/Link/Link.vue'
import MerchantCreateAdmin from './MerchantCreateAdmin.vue'
import UserShow from '@/views/iam/user/UserShow.vue'
// 使用hooks
const {
handleTableChange,
pageQueryResHandel,
resetQueryParams,
pagination,
pages,
model,
loading,
} = useTablePage(queryPage)
const { createMessage, createConfirm } = useMessage()
// 查询条件
const fields = [
{ field: 'mchName', type: STRING, name: '商户名称', placeholder: '请输入商户名称' },
{ field: 'companyName', type: STRING, name: '公司名称', placeholder: '请输入公司名称' },
] as QueryField[]
const xTable = ref<VxeTableInstance>()
const xToolbar = ref<VxeToolbarInstance>()
const merchantEdit = ref<any>()
const userShow = ref<any>()
const merchantCreateAdmin = ref<any>()
onMounted(() => {
vxeBind()
queryPage()
})
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
// 分页查询
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
}).then(({ data }) => {
pageQueryResHandel(data)
})
return Promise.resolve()
}
// 新增
function add() {
merchantEdit.value.init(null, FormEditType.Add)
}
// 查看
function edit(record) {
merchantEdit.value.init(record.id, FormEditType.Edit)
}
// 查看
function show(record) {
merchantEdit.value.init(record.id, FormEditType.Show)
}
// 删除
function remove(record) {
createConfirm({
iconType: 'warning',
title: '警告',
content: '是否删除该条数据',
onOk: () => {
del(record.id).then(() => {
createMessage.success('删除成功')
queryPage()
})
},
})
}
/**
* 创建管理员用户
*/
function createAdmin(record) {
merchantCreateAdmin.value.init(record)
}
/**
*
*/
function showAdmin(record) {
userShow.value.init(record.adminUserId)
}
</script>
<style lang="less" scoped></style>

View File

@@ -27,10 +27,6 @@ export function saveOrUpdate(obj: AlipayConfig) {
* 支付宝配置
*/
export interface AlipayConfig extends MchEntity {
// 商户号
mchNo?: string
// 商户AppId
appId?: string
// 支付宝商户appId
aliAppId?: string
// 是否启用

View File

@@ -11,16 +11,6 @@
>
<a-alert style="width: 400px" message="请选择参数后生成授权链接进行扫码" type="info" />
<a-form class="small-from-item mt-15px mb-15px" ref="formRef" :model="form">
<a-form-item label="商户" name="mchNo">
<a-select
style="width: 320px"
:filter-option="search"
:options="merchantList"
v-model:value="form.mchNo"
placeholder="请选择商户"
@change="merchantChange"
/>
</a-form-item>
<a-form-item label="商户应用" name="appId" v-show="form.mchNo">
<a-select
:filter-option="search"
@@ -90,7 +80,6 @@
queryAuthResult,
} from './ChannelAuth.api'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
import { useDict } from '@/hooks/bootx/useDict'
import { ChannelAuthStatusEnum } from '@/enums/daxpay/daxpayEnum'
@@ -120,18 +109,14 @@
async function initData() {
// 通道
channels.value = await dictDropDown('channel')
// 商户
merchantDropdown().then(({ data }) => {
merchantList.value = data
})
initMchApp()
}
/**
* 商户变动时刷新应用列表
*/
function merchantChange() {
form.value.appId = undefined
mchAppDropdown(form.value.mchNo).then(({ data }) => {
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}

View File

@@ -77,8 +77,6 @@ export interface PayParam {
notifyUrl?: string
/** 终端IP */
clientIp?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */
@@ -101,8 +99,6 @@ export interface PayResult {
status?: string
/** 支付参数体 */
payBody?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */
@@ -133,8 +129,6 @@ export interface RefundParam {
notifyUrl?: string
/** 终端IP */
clientIp?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */
@@ -155,8 +149,6 @@ export interface RefundResult {
bizRefundNo?: string
/** 退款状态 */
status?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */
@@ -193,8 +185,6 @@ export interface TransferParam {
notifyUrl?: string
/** 终端IP */
clientIp?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */
@@ -216,8 +206,6 @@ export interface TransferResult {
status?: string
/** 提示信息 */
errorMsg?: string
/** 商户号 */
mchNo?: string
/** 应用号 */
appId?: string
/** 随机数 */

View File

@@ -10,19 +10,10 @@
:wrapperCol="{ span: 18 }"
:validate-trigger="['blur', 'change']"
>
<a-form-item label="商户号" name="mchNo">
<a-select
:filter-option="search"
v-model:value="form.mchNo"
placeholder="请选择商户"
:options="mchNoOptions"
@change="merchantChange"
/>
</a-form-item>
<a-form-item label="应用号" name="appId">
<a-select
:filter-option="search"
:options="mchAppOptions"
:options="mchAppList"
v-model:value="form.appId"
placeholder="请选择商户应用"
/>
@@ -130,7 +121,6 @@
import { Modal } from 'ant-design-vue'
import { PayParam, paySign, tradePay } from './DevelopTrade.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
import { useDict } from '@/hooks/bootx/useDict'
@@ -150,7 +140,6 @@
})
const rules = computed(() => {
return {
mchNo: [{ required: true, message: '商户号不可为空' }],
appId: [{ required: true, message: '应用号不可为空' }],
channel: [{ required: true, message: '支付通道不可为空' }],
bizOrderNo: [{ required: true, message: '订单号不可为空' }],
@@ -163,8 +152,7 @@
} as Record<string, Rule[]>
})
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const channelOptions = ref<LabeledValue[]>([])
const methodOptions = ref<LabeledValue[]>([])
@@ -177,9 +165,6 @@
*/
async function initData() {
confirmLoading.value = false
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
channelOptions.value = await dictDropDown('channel')
methodOptions.value = await dictDropDown('pay_method')
// 时间默认30M后
@@ -195,10 +180,9 @@
/**
* 商户变动时刷新应用列表
*/
function merchantChange() {
form.appId = undefined
mchAppDropdown(form.mchNo).then(({ data }) => {
mchAppOptions.value = data
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}

View File

@@ -10,19 +10,10 @@
:wrapperCol="{ span: 18 }"
:validate-trigger="['blur', 'change']"
>
<a-form-item label="商户号" name="mchNo">
<a-select
:filter-option="search"
v-model:value="form.mchNo"
placeholder="请选择商户"
:options="mchNoOptions"
@change="merchantChange"
/>
</a-form-item>
<a-form-item label="应用号" name="appId">
<a-select
:filter-option="search"
:options="mchAppOptions"
:options="mchAppList"
v-model:value="form.appId"
placeholder="请选择商户应用"
/>
@@ -106,7 +97,6 @@
import { Modal } from 'ant-design-vue'
import { refundSign, RefundParam, tradeRefund } from './DevelopTrade.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
import XEUtils from 'xe-utils'
@@ -122,7 +112,6 @@
})
const rules = computed(() => {
return {
mchNo: [{ required: true, message: '商户号不可为空' }],
appId: [{ required: true, message: '应用号不可为空' }],
bizRefundNo: [{ required: true, message: '商户退款号不可为空' }],
title: [{ required: true, message: '退款标题不可为空' }],
@@ -133,8 +122,7 @@
} as Record<string, Rule[]>
})
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
onMounted(() => {
initData()
@@ -145,10 +133,7 @@
*/
async function initData() {
confirmLoading.value = false
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
// 时间默认30M后
initMchApp()
genNonceStr()
genBizOrderNo()
updateReqTime()
@@ -157,10 +142,9 @@
/**
* 商户变动时刷新应用列表
*/
function merchantChange() {
form.appId = undefined
mchAppDropdown(form.mchNo).then(({ data }) => {
mchAppOptions.value = data
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}

View File

@@ -10,19 +10,10 @@
:wrapperCol="{ span: 18 }"
:validate-trigger="['blur', 'change']"
>
<a-form-item label="商户号" name="mchNo">
<a-select
:filter-option="search"
v-model:value="form.mchNo"
placeholder="请选择商户"
:options="mchNoOptions"
@change="merchantChange"
/>
</a-form-item>
<a-form-item label="应用号" name="appId">
<a-select
:filter-option="search"
:options="mchAppOptions"
:options="mchAppList"
v-model:value="form.appId"
placeholder="请选择商户应用"
/>
@@ -122,7 +113,6 @@
import { Modal } from 'ant-design-vue'
import { transferSign, TransferParam, tradeTransfer } from './DevelopTrade.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
import XEUtils from 'xe-utils'
@@ -140,7 +130,6 @@
})
const rules = computed(() => {
return {
mchNo: [{ required: true, message: '商户号不可为空' }],
appId: [{ required: true, message: '应用号不可为空' }],
channel: [{ required: true, message: '支付通道不可为空' }],
bizRefundNo: [{ required: true, message: '商户转账号不可为空' }],
@@ -154,8 +143,7 @@
} as Record<string, Rule[]>
})
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const channelOptions = ref<LabeledValue[]>([])
const payeeTypeOptions = ref<LabeledValue[]>([])
@@ -170,10 +158,7 @@
confirmLoading.value = false
channelOptions.value = await dictDropDown('channel')
payeeTypeOptions.value = await dictDropDown('transfer_payee_type')
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
// 时间默认30M后
initMchApp()
genNonceStr()
genBizOrderNo()
updateReqTime()
@@ -182,10 +167,9 @@
/**
* 商户变动时刷新应用列表
*/
function merchantChange() {
form.appId = undefined
mchAppDropdown(form.mchNo).then(({ data }) => {
mchAppOptions.value = data
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}

View File

@@ -53,10 +53,9 @@ export const del = (id) => {
/**
* 查询商户下的应用列表
*/
export function mchAppDropdown(mchNo) {
export function mchAppDropdown() {
return defHttp.get<Result<LabeledValue[]>>({
url: '/mch/app/dropdown',
params: { mchNo },
})
}
@@ -64,8 +63,6 @@ export function mchAppDropdown(mchNo) {
* 商户应用
*/
export interface MchApp extends BaseEntity {
// 商户号
mchNo?: string
// 应用号
appId?: string
// 应用名称

View File

@@ -21,15 +21,6 @@
<a-form-item label="主键" name="id" :hidden="true">
<a-input v-model:value="form.id" :disabled="showable" />
</a-form-item>
<a-form-item label="商户号" name="mchNo">
<a-select
:filter-option="search"
v-model:value="form.mchNo"
:disabled="showable"
placeholder="请选择商户"
:options="mchNoOptions"
/>
</a-form-item>
<a-form-item label="应用号" name="appId" v-if="!addable">
<a-tag> {{ form.appId }}</a-tag>
</a-form-item>
@@ -120,7 +111,6 @@
import { FormEditType } from '@/enums/formTypeEnum'
import { BasicDrawer } from '@/components/Drawer'
import { buildUUID } from '@/utils/uuid'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import { useDict } from '@/hooks/bootx/useDict'
@@ -150,7 +140,6 @@
})
const signTypes = ref<LabeledValue[]>([])
const merchantNotifyTypes = ref<LabeledValue[]>([])
const mchNoOptions = ref<LabeledValue[]>([])
// 校验
const rules = reactive({
@@ -180,10 +169,6 @@
* 初始化商户列表信息
*/
function initData() {
// 商户
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
// 签名方式
dictDropDown('sign_type').then((data) => {
signTypes.value = data

View File

@@ -104,7 +104,6 @@
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import ALink from '@/components/Link/Link.vue'
import { useDict } from '@/hooks/bootx/useDict'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { LabeledValue } from 'ant-design-vue/lib/select'
import ChannelConfigList from '@/views/daxpay/common/merchant/channel/ChannelConfigList.vue'
import MerchantNotifyConfigList from '@/views/daxpay/common/merchant/notify/MerchantNotifyConfigList.vue'
@@ -127,18 +126,10 @@
// 查询条件
const fields = computed(() => {
return [
{
field: 'mchNo',
type: LIST,
name: '商户',
selectList: mchNoOptions.value,
placeholder: '请选择商户',
},
{ field: 'appId', type: STRING, name: '应用号', placeholder: '请输入应用号' },
{ field: 'appName', type: STRING, name: '应用名称', placeholder: '请输入应用名称' },
] as QueryField[]
})
const mchNoOptions = ref<LabeledValue[]>([])
const xTable = ref<VxeTableInstance>()
const xToolbar = ref<VxeToolbarInstance>()
@@ -150,19 +141,9 @@
onMounted(() => {
vxeBind()
initMerchant()
queryPage()
})
/**
* 初始化商户列表信息
*/
function initMerchant() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
}
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}

View File

@@ -38,9 +38,6 @@
<a-descriptions-item label="创建时间" :span="1">
{{ task.createTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="1">
{{ task.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="1">
{{ task.appId }}
</a-descriptions-item>

View File

@@ -50,7 +50,6 @@
/>
<vxe-column field="latestTime" title="最后发送时间" sortable :min-width="170" />
<vxe-column field="createTime" title="创建时间" sortable :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="180" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -94,7 +93,6 @@
import PayOrderInfo from '@/views/daxpay/common/order/pay/PayOrderInfo.vue'
import TransferOrderInfo from '@/views/daxpay/common/order/transfer/TransferOrderInfo.vue'
import CallbackRecordList from './CallbackRecordList.vue'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -124,25 +122,17 @@
placeholder: '请选择通知类型',
selectList: tradeTypeList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const noticeRecordList = ref<any>()
const noticeTaskInfo = ref<any>()
const payOrderInfo = ref<any>()
@@ -159,32 +149,21 @@
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
/**
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
tradeTypeList.value = await dictDropDown('trade_type')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 分页查询

View File

@@ -38,9 +38,6 @@
<a-descriptions-item label="创建时间" :span="1">
{{ task.createTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="1">
{{ task.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="1">
{{ task.appId }}
</a-descriptions-item>

View File

@@ -44,7 +44,6 @@
<vxe-column field="delayCount" title="延迟重试次数" sortable :min-width="150" />
<vxe-column field="latestTime" title="最后发送时间" sortable :min-width="170" />
<vxe-column field="createTime" title="创建时间" sortable :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="180" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -91,7 +90,6 @@
import NotifyRecordList from './NotifyRecordList.vue'
import { NotifyContentTypeEnum } from '@/enums/daxpay/daxpayEnum'
import RefundOrderInfo from '@/views/daxpay/common/order/refund/RefundOrderInfo.vue'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -121,25 +119,17 @@
placeholder: '请选择通知类型',
selectList: noticeTypeList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const notifyRecordList = ref<any>()
const notifyTaskInfo = ref<any>()
const payOrderInfo = ref<any>()
@@ -156,32 +146,21 @@
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
/**
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
noticeTypeList.value = await dictDropDown('notify_content_type')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 分页查询

View File

@@ -80,9 +80,6 @@
<a-descriptions-item label="创建时间" :span="8">
{{ order.createTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="8">
{{ order.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="8">
{{ order.appId }}
</a-descriptions-item>

View File

@@ -72,7 +72,6 @@
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间" sortable :min-width="230" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="120" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -162,7 +161,6 @@
PayRefundStatusEnum,
PayStatusEnum,
} from '@/enums/daxpay/tradeStatusEnum'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -180,8 +178,7 @@
const { createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const channelList = ref<LabeledValue[]>([])
const methodList = ref<LabeledValue[]>([])
const payStatusList = ref<LabeledValue[]>([])
@@ -219,19 +216,12 @@
selectList: payRefundStatusList.value,
},
{ field: 'allocStatus', name: '分账状态', type: LIST, selectList: payAllocStatusList.value },
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -242,12 +232,6 @@
const refundModel = ref<any>()
const totalAmount = ref<number>(0.0)
// 提供一个 getter 函数
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
vxeBind()
@@ -261,28 +245,21 @@
* 初始化数据
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
channelList.value = await dictDropDown('channel')
methodList.value = await dictDropDown('pay_method')
payStatusList.value = await dictDropDown('pay_status')
payRefundStatusList.value = await dictDropDown('pay_refund_status')
payAllocStatusList.value = await dictDropDown('pay_alloc_status')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**

View File

@@ -45,9 +45,6 @@
<a-descriptions-item label="退款终端ip">
{{ order.clientIp }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="2">
{{ order.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="2">
{{ order.appId }}
</a-descriptions-item>

View File

@@ -60,8 +60,6 @@
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间" sortable :min-width="230" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="120" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -130,7 +128,6 @@
import ALink from '@/components/Link/Link.vue'
import { RefundStatusEnum } from '@/enums/daxpay/tradeStatusEnum'
import { Icon } from '@/components/Icon'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -148,8 +145,7 @@
const { createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const channelList = ref<LabeledValue[]>([])
const refundStatusList = ref<LabeledValue[]>([])
const totalAmount = ref<number>(0.0)
@@ -182,19 +178,12 @@
selectList: refundStatusList.value,
},
{ field: 'channel', name: '支付通道', type: LIST, selectList: channelList.value },
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -203,10 +192,6 @@
const xToolbar = ref<VxeToolbarInstance>()
const refundOrderInfo = ref<any>()
const payOrderInfo = ref<any>()
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
@@ -221,25 +206,18 @@
* 初始化数据
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
refundStatusList.value = await dictDropDown('RefundStatus')
channelList.value = await dictDropDown('channel')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**

View File

@@ -54,9 +54,6 @@
<a-descriptions-item label="终端ip" :span="4">
{{ order.clientIp }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="2">
{{ order.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="2">
{{ order.appId }}
</a-descriptions-item>

View File

@@ -55,8 +55,6 @@
</vxe-column>
<vxe-column field="reason" title="转账原因" :min-width="160" />
<vxe-column field="createTime" title="创建时间" sortable :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" :width="120" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -145,8 +143,7 @@
const { createMessage, createConfirm } = useMessage()
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let channelList = ref<LabeledValue[]>([])
let transferStatusList = ref<LabeledValue[]>([])
let totalAmount = ref<number>(0)
@@ -167,19 +164,12 @@
selectList: transferStatusList.value,
},
{ field: 'channel', name: '转账通道', type: LIST, selectList: channelList.value },
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -188,11 +178,6 @@
const xToolbar = ref<VxeToolbarInstance>()
const transferOrderInfo = ref<any>()
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
vxeBind()
@@ -206,25 +191,17 @@
* 初始化数据
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
transferStatusList.value = await dictDropDown('transfer_status')
channelList.value = await dictDropDown('channel')
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 分页查询

View File

@@ -62,10 +62,6 @@
<a-descriptions-item label="交易时间(通道)" :span="1">
{{ discrepancy.channelTradeTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="1">
{{ discrepancy.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="1">
{{ discrepancy.appId }}
</a-descriptions-item>

View File

@@ -124,7 +124,6 @@
import PayOrderInfo from '@/views/daxpay/common/order/pay/PayOrderInfo.vue'
import RefundOrderInfo from '@/views/daxpay/common/order/refund/RefundOrderInfo.vue'
import TransferOrderInfo from '@/views/daxpay/common/order/transfer/TransferOrderInfo.vue'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -141,8 +140,7 @@
} = useTablePage(queryPage)
const { dictDropDown, dictConvert } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let channelList = ref<LabeledValue[]>([])
let discrepancyTypeList = ref<LabeledValue[]>([])
let tradeStatusList = ref<LabeledValue[]>([])
@@ -213,19 +211,12 @@
placeholder: '请选择交易状态(通道)',
selectList: tradeStatusList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -246,35 +237,24 @@
initData()
init()
})
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
/**
* 初始化基础数据
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
discrepancyTypeList.value = await dictDropDown('reconcile_discrepancy_type')
channelList.value = await dictDropDown('channel')
tradeStatusList.value = await dictDropDown('trade_status')
tradeTypeList.value = await dictDropDown('trade_type')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 入口

View File

@@ -130,10 +130,6 @@ export interface ReconcileCreatParam {
/** 支付通道 */
channel?: string
/**
* 商户号
*/
mchNo?: string
/**
* 应用AppId
*/

View File

@@ -19,15 +19,6 @@
<a-form-item label="标题" name="title">
<a-input v-model:value="form.title" placeholder="请输入对账名称" />
</a-form-item>
<a-form-item label="商户" name="mchNo">
<a-select
:filter-option="search"
:options="merchantList"
v-model:value="form.mchNo"
placeholder="请选择商户"
@change="merchantChange"
/>
</a-form-item>
<a-form-item label="商户应用" name="appId" v-show="form.mchNo">
<a-select
:filter-option="search"
@@ -75,7 +66,6 @@
import dayjs, { Dayjs } from 'dayjs'
import XEUtils from 'xe-utils'
import { create, ReconcileCreatParam } from './ReconcileStatement.api'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
const {
@@ -119,18 +109,14 @@
async function initData() {
// 通道
channels.value = await dictDropDown('channel')
// 商户
merchantDropdown().then(({ data }) => {
merchantList.value = data
})
initMchApp()
}
/**
* 商户变动时刷新应用列表
*/
function merchantChange() {
form.appId = undefined
mchAppDropdown(form.mchNo).then(({ data }) => {
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}

View File

@@ -61,9 +61,6 @@
<a-descriptions-item v-if="statement.errorMsg" label="错误信息" :span="1">
{{ statement.errorMsg }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="1">
{{ statement.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="1">
{{ statement.appId }}
</a-descriptions-item>

View File

@@ -135,7 +135,6 @@
import ReconcileStatementCreate from './ReconcileStatementCreate.vue'
import ReconcileStatementInfo from './ReconcileStatementInfo.vue'
import { useFilePlatform } from '@/hooks/bootx/useFilePlatform'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -154,8 +153,7 @@
const { createMessage, createConfirm } = useMessage()
const { getFileUrl } = useFilePlatform()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let channelList = ref<LabeledValue[]>([])
let resultList = ref<LabeledValue[]>([])
@@ -186,19 +184,12 @@
{ label: '未完成', value: false },
],
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -211,10 +202,6 @@
nextTick(() => {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
})
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
init()
@@ -224,25 +211,18 @@
* 初始化基础数据
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
channelList.value = await dictDropDown('channel')
resultList.value = await dictDropDown('reconcile_result')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 入口

View File

@@ -31,9 +31,6 @@
<a-descriptions-item label="提示消息" v-if="form.errorMsg" :span="4">
{{ form.errorMsg }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="2">
{{ form.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="2">
{{ form.appId }}
</a-descriptions-item>

View File

@@ -47,7 +47,6 @@
</vxe-column>
<vxe-column field="msg" title="提示信息" :min-width="250" />
<vxe-column field="createTime" title="通知时间" sortable :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -88,7 +87,6 @@
import RefundOrderInfo from '@/views/daxpay/common/order/refund/RefundOrderInfo.vue'
import TransferOrderInfo from '@/views/daxpay/common/order/transfer/TransferOrderInfo.vue'
import { TradeTypeEnum } from '@/enums/daxpay/daxpayEnum'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -105,8 +103,7 @@
} = useTablePage(queryPage)
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let channelList = ref<LabeledValue[]>([])
let callbackTypeList = ref<LabeledValue[]>([])
let callbackStatusList = ref<LabeledValue[]>([])
@@ -137,19 +134,12 @@
placeholder: '请选择消息处理状态',
selectList: callbackStatusList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -160,10 +150,6 @@
const payOrderInfo = ref<any>()
const refundOrderInfo = ref<any>()
const transferOrderInfo = ref<any>()
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
vxeBind()
@@ -177,25 +163,18 @@
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
channelList.value = await dictDropDown('channel')
callbackTypeList.value = await dictDropDown('trade_type')
callbackStatusList.value = await dictDropDown('callback_status')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**

View File

@@ -37,9 +37,6 @@
<a-descriptions-item label="关闭时间">
{{ record.createTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号">
{{ record.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId">
{{ record.appId }}
</a-descriptions-item>

View File

@@ -48,7 +48,6 @@
<vxe-column field="errorMsg" title="错误消息" :min-width="180" />
<vxe-column field="clientIp" title="客户端IP" :min-width="120" />
<vxe-column field="createTime" title="创建时间" :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -84,7 +83,6 @@
import { LabeledValue } from 'ant-design-vue/lib/select'
import PayCloseRecordInfo from './PayCloseRecordInfo.vue'
import PayOrderInfo from '@/views/daxpay/common/order/pay/PayOrderInfo.vue'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -101,8 +99,7 @@
} = useTablePage(queryPage)
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let payChannelList = ref<LabeledValue[]>([])
let closeTypeList = ref<LabeledValue[]>([])
@@ -135,19 +132,12 @@
{ label: '失败', value: false },
],
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -156,10 +146,6 @@
const xToolbar = ref<VxeToolbarInstance>()
const payCloseRecordInfo = ref<any>()
const payOrderInfo = ref<any>()
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
onMounted(() => {
initData()
vxeBind()
@@ -173,24 +159,17 @@
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
payChannelList.value = await dictDropDown('channel')
closeTypeList.value = await dictDropDown('close_type')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**

View File

@@ -34,9 +34,6 @@
<a-descriptions-item label="创建时间">
{{ record.createTime }}
</a-descriptions-item>
<a-descriptions-item label="商户号">
{{ record.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId">
{{ record.appId }}
</a-descriptions-item>

View File

@@ -56,7 +56,6 @@
<vxe-column field="bizTradeNo" title="商户交易号" :min-width="230" />
<vxe-column field="outTradeNo" title="通道交易号" :min-width="230" />
<vxe-column field="createTime" title="时间" :min-width="170" sortable />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" :min-width="60" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -98,7 +97,6 @@
import ALink from '@/components/Link/Link.vue'
import TradeFlowRecordInfo from './TradeFlowRecordInfo.vue'
import { TradeTypeEnum } from '@/enums/daxpay/daxpayEnum'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -113,8 +111,7 @@
} = useTablePage(queryPage)
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
const payChannelList = ref<LabeledValue[]>([])
const tradeFlowRecordTypeList = ref<LabeledValue[]>([])
@@ -139,19 +136,12 @@
placeholder: '请选择交易通道',
selectList: payChannelList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -176,32 +166,21 @@
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
/**
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
tradeFlowRecordTypeList.value = await dictDropDown('trade_type')
payChannelList.value = await dictDropDown('channel')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 分页查询

View File

@@ -40,9 +40,6 @@
<a-descriptions-item label="错误信息" v-if="form.errorMsg" :span="2">
{{ form.errorMsg }}
</a-descriptions-item>
<a-descriptions-item label="商户号" :span="2">
{{ form.mchNo }}
</a-descriptions-item>
<a-descriptions-item label="应用AppId" :span="2">
{{ form.appId }}
</a-descriptions-item>

View File

@@ -48,7 +48,6 @@
</vxe-column>
<vxe-column field="errorMsg" title="错误消息" :min-width="160" />
<vxe-column field="createTime" title="同步时间" :min-width="170" />
<vxe-column field="mchNo" title="商户号" :min-width="150" />
<vxe-column field="appId" title="应用号" :min-width="150" />
<vxe-column fixed="right" :min-width="50" :showOverflow="false" title="操作">
<template #default="{ row }">
@@ -90,7 +89,6 @@
import TradeSyncRecordInfo from './TradeSyncRecordInfo.vue'
import RefundOrderInfo from '@/views/daxpay/common/order/refund/RefundOrderInfo.vue'
import TransferOrderInfo from '@/views/daxpay/common/order/transfer/TransferOrderInfo.vue'
import { merchantDropdown } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { mchAppDropdown } from '@/views/daxpay/common/merchant/app/MchApp.api'
// 使用hooks
@@ -105,8 +103,7 @@
} = useTablePage(queryPage)
const { dictConvert, dictDropDown } = useDict()
const mchNoOptions = ref<LabeledValue[]>([])
const mchAppOptions = ref<LabeledValue[]>([])
const mchAppList = ref<LabeledValue[]>([])
let syncStatusList = ref<LabeledValue[]>([])
let payChannelList = ref<LabeledValue[]>([])
let syncTypeList = ref<LabeledValue[]>([])
@@ -138,19 +135,12 @@
placeholder: '请选择同步通道',
selectList: payChannelList.value,
},
{
field: 'mchNo',
type: LIST,
name: '商户号',
placeholder: '请选择商户号',
selectList: mchNoOptions.value,
},
{
field: 'appId',
type: LIST,
name: '应用号',
placeholder: '请先选择商户后选择应用号',
selectList: mchAppOptions.value,
selectList: mchAppList.value,
},
] as QueryField[]
})
@@ -170,33 +160,22 @@
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
watch(
() => model.queryParam?.mchNo,
(value) => changeMch(value),
)
/**
* 初始化
*/
async function initData() {
merchantDropdown().then(({ data }) => {
mchNoOptions.value = data
})
syncStatusList.value = await dictDropDown('PaySyncStatus')
payChannelList.value = await dictDropDown('channel')
syncTypeList.value = await dictDropDown('PaymentType')
initMchApp()
}
/**
* 商户变动后更新应用列表
* 初始化商户应用列表
*/
function changeMch(mchNo) {
if (mchNo) {
mchAppDropdown(mchNo).then(({ data }) => {
mchAppOptions.value = data
})
} else {
mchAppOptions.value = []
model.queryParam.appId = undefined
}
function initMchApp() {
mchAppDropdown().then(({ data }) => {
mchAppList.value = data
})
}
/**
* 分页查询

View File

@@ -1,19 +0,0 @@
import { defHttp } from '@/utils/http/axios'
import { Result } from '#/axios'
import { Merchant } from '@/views/daxpay/admin/merchant/info/Merchant.api'
/**
* 获取商户信息
*/
export const get = () => {
return defHttp.get<Result<Merchant>>({
url: '/merchant/get',
})
}
export const update = (data: Merchant) => {
return defHttp.post<Result<Merchant>>({
url: '/merchant/update',
data,
})
}

View File

@@ -1,156 +0,0 @@
<template>
<div>
<div class="m-3 p-3 bg-white">
<a-spin :spinning="loading">
<a-form
ref="formRef"
:validate-trigger="['blur', 'change']"
:label-col="{ span: 12 }"
:model="form"
:rules="rules"
>
<a-row>
<a-col :span="20">
<a-form-item class="w-800px" label="商户名称" name="mchName">
<a-tag>{{ form.mchName }}</a-tag>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="商户号" name="mchNo">
<a-tag>{{ form.mchNo }}</a-tag>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="公司名称" name="companyName">
<a-input
placeholder="请输入公司名称"
v-model:value="form.companyName"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="公司联系方式" name="companyContact">
<a-input
placeholder="请输入公司联系方式"
v-model:value="form.companyContact"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="公司信用编码" name="companyCode">
<a-input
placeholder="请输入公司信用编码"
v-model:value="form.companyCode"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="公司地址" name="companyAddress">
<a-textarea
placeholder="请输入公司地址"
v-model:value="form.companyAddress"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="法人名称" name="legalPerson">
<a-input
placeholder="请输入法人名称"
v-model:value="form.legalPerson"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="法人证件号码" name="idNo">
<a-input
placeholder="请输入法人证件号码"
v-model:value="form.idNo"
:disabled="!edit"
/>
</a-form-item>
</a-col>
<a-col :span="20">
<a-form-item class="w-800px" label="法人联系方式" name="contact">
<a-input
placeholder="请输入法人联系方式"
v-model:value="form.contact"
:disabled="!edit"
/>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :push="8">
<a-button v-if="edit" @click="initData">取消</a-button>
<a-button v-if="edit" style="margin-left: 50px" type="primary" @click="updateInfo"
>更新</a-button
>
<a-button v-if="!edit" @click="edit = true">编辑信息</a-button>
</a-col>
</a-row>
</a-form>
</a-spin>
</div>
</div>
</template>
<script setup lang="ts">
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { onMounted, reactive, ref } from 'vue'
import { Merchant } from '@/views/daxpay/admin/merchant/info/Merchant.api'
import { get, update } from './MerchantInfo.api'
import { useMessage } from '@/hooks/web/useMessage'
const { createConfirm, createMessage } = useMessage()
let form = ref<Merchant>({})
let loading = ref(false)
const formRef = ref<FormInstance>()
let edit = ref(false)
// 校验
const rules = reactive({
mchName: [{ required: true, message: '请输入商户名称' }],
companyName: [{ required: true, message: '请输入公司名称' }],
} as Record<string, Rule[]>)
onMounted(() => initData())
/**
* 初始化数据
*/
function initData() {
edit.value = false
loading.value = true
get().then(({ data }) => {
form.value = data
loading.value = false
})
}
/**
* 更新信息
*/
function updateInfo() {
formRef.value?.validate().then(() => {
createConfirm({
iconType: 'warning',
title: '警告',
content: '是否更新商户信息',
onOk: () => {
update(form.value).then(() => {
createMessage.success('更新成功')
initData()
})
},
})
})
}
</script>
<style scoped lang="less"></style>

View File

@@ -1,104 +0,0 @@
import { defHttp } from '@/utils/http/axios'
import { PageResult, Result } from '#/axios'
import { UserInfo } from '@/views/iam/user/User.api'
import { Role } from '@/views/iam/role/Role.api'
/**
* 用户列表
*/
export function page(params) {
return defHttp.get<Result<PageResult<UserInfo[]>>>({
url: '/merchant/user/page',
params,
})
}
/**
* 用户详情
*/
export function get(id) {
return defHttp.get<Result<UserInfo>>({
url: '/merchant/user/findById',
params: { id },
})
}
/**
* 添加用户
*/
export function add(params) {
return defHttp.post<Result>({
url: '/merchant/user/add',
data: params,
})
}
/**
* 修改用户
*/
export function update(params) {
return defHttp.post<Result>({
url: '/merchant/user/update',
data: params,
})
}
/**
* 重置密码
*/
export function restartPassword(userId, newPassword) {
return defHttp.post({
url: '/merchant/user/restartPassword',
data: { userId, newPassword },
})
}
/**
* 批量重置密码
*/
export function restartPasswordBatch(userIds, newPassword) {
return defHttp.post({
url: '/merchant/user/restartPasswordBatch',
data: { userIds, newPassword },
})
}
/**
* 分配角色
*/
export function addUserRole(params) {
return defHttp.post<Result>({
url: '/merchant/user/assignRole',
data: params,
})
}
/**
* 分配角色 批量
*/
export function addUserRoleBatch(data) {
return defHttp.post({
url: `/merchant/user/assignRoleBatch`,
data: data,
})
}
/**
* 获取用户拥有角色id集合
*/
export function getRoleIds(userId) {
return defHttp.get<Result<string[]>>({
url: `/merchant/user/findRoleIdsByUser`,
params: { userId },
})
}
/**
* 获取用户拥有角色集合
*/
export function getRoles(userId) {
return defHttp.get<Result<Role[]>>({
url: `/merchant/user/findRolesByUser`,
params: { userId },
})
}

View File

@@ -1,232 +0,0 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query
:query-params="model.queryParam"
:fields="fields"
@query="queryPage"
@reset="resetQueryParams"
/>
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }">
<template #buttons>
<a-space>
<a-button type="primary" pre-icon="ant-design:plus-outlined" @click="add"
>新建</a-button
>
<a-dropdown v-if="batchOperateFlag">
<a-button post-icon="ant-design:down-outlined"> 批量操作 </a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<a @click="assignRolesBatch()">角色分配</a>
</a-menu-item>
<!-- <a-menu-item>-->
<!-- <a @click="lockUserConfirmBatch(true)">锁定账号</a>-->
<!-- </a-menu-item>-->
<!-- <a-menu-item>-->
<!-- <a @click="lockUserConfirmBatch(false)">解锁账号</a>-->
<!-- </a-menu-item>-->
<a-menu-item>
<a @click="resetPwdBatch()">重置密码</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-space>
</template>
</vxe-toolbar>
<div class="h-65vh">
<vxe-table
ref="xTable"
height="auto"
size="medium"
@checkbox-all="selectAllEvent"
@checkbox-change="selectChangeEvent"
:loading="loading"
:data="pagination.records"
>
<vxe-column type="checkbox" width="50" />
<vxe-column field="name" title="姓名" />
<vxe-column field="account" title="账号" />
<vxe-column field="phone" title="手机号" />
<vxe-column field="email" title="邮箱" />
<vxe-column field="avatar" title="头像" align="center">
<template #default="{ row }">
<Avatar size="large" :src="getFileUrl(row.avatar)" />
</template>
</vxe-column>
<vxe-column field="status" title="用户状态" align="center">
<template #default="{ row }">
{{ dictConvert('UserStatusCode', row.status) || '无' }}
</template>
</vxe-column>
<vxe-column fixed="right" width="170" :showOverflow="false" title="操作">
<template #default="{ row }">
<a href="javascript:" @click="show(row)">查看</a>
<a-divider type="vertical" />
<a href="javascript:" @click="edit(row)">编辑</a>
<a-divider type="vertical" />
<a-dropdown>
<a> 更多 <icon icon="ant-design:down-outlined" :size="12" /> </a>
<template #overlay>
<a-menu>
<a-menu-item>
<a-link @click="assignRoles(row)">角色分配</a-link>
</a-menu-item>
<a-menu-item>
<a-link @click="resetPwd(row)">重置密码</a-link>
</a-menu-item>
<a-menu-item v-if="[1, 3].includes(row.status)">
<a-link v-if="row.status === 1" @click="lockUserConfirm(row.id, true)"
>封禁账号</a-link
>
<a-link v-if="row.status === 3" @click="lockUserConfirm(row.id, false)"
>解锁账号</a-link
>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
</vxe-column>
</vxe-table>
</div>
<vxe-pager
size="medium"
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
<UserAdd ref="userAdd" @ok="queryPage" />
<UserEdit ref="userEdit" @ok="queryPage" />
<UserShow ref="userShow" />
<UserResetPwd ref="userResetPwd" />
<UserRoleAssign ref="userRoleAssign" />
</div>
</div>
</template>
<script lang="ts" setup>
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { Avatar } from 'ant-design-vue'
import useTablePage from '@/hooks/bootx/useTablePage'
import { useMessage } from '@/hooks/web/useMessage'
import { onMounted, ref } from 'vue'
import { QueryField, STRING } from '@/components/Bootx/Query/Query'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { useDict } from '@/hooks/bootx/useDict'
import { Icon } from '@/components/Icon'
import UserShow from './UserShow.vue'
import UserEdit from './UserEdit.vue'
import UserAdd from './UserAdd.vue'
import UserResetPwd from './UserResetPwd.vue'
import UserRoleAssign from './UserRoleAssign.vue'
import ALink from '@/components/Link/Link.vue'
import { useFilePlatform } from '@/hooks/bootx/useFilePlatform'
import { page } from './MerchantUser.api'
// 使用hooks
const {
handleTableChange,
pageQueryResHandel,
resetQueryParams,
pagination,
pages,
model,
loading,
batchOperateFlag,
} = useTablePage(queryPage)
const { dictConvert } = useDict()
const { getFileUrl } = useFilePlatform()
// 查询条件
const fields = [
{ field: 'account', type: STRING, name: '账号', placeholder: '请输入要查询的账号' },
{ field: 'name', type: STRING, name: '姓名', placeholder: '请输入要查询的姓名' },
] as QueryField[]
const xTable = ref<VxeTableInstance>()
const xToolbar = ref<VxeToolbarInstance>()
let userAdd = ref<any>()
let userEdit = ref<any>()
let userShow = ref<any>()
let userRoleAssign = ref<any>()
let userResetPwd = ref<any>()
onMounted(() => {
vxeBind()
queryPage()
})
function vxeBind() {
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
}
// 分页查询
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
}).then(({ data }) => {
pageQueryResHandel(data)
})
return Promise.resolve()
}
/**
* 选中全部
*/
function selectAllEvent() {
const records = xTable.value?.getCheckboxRecords()
batchOperateFlag.value = !!records?.length
}
/**
* 选中事件
*/
function selectChangeEvent() {
const records = xTable.value?.getCheckboxRecords()
batchOperateFlag.value = !!records?.length
}
// 分配角色
function assignRoles(record) {
userRoleAssign.value.init(false, record.id)
}
// 批量分配角色
function assignRolesBatch() {
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
userRoleAssign.value.init(true, userIds)
}
function add() {
userAdd.value.init()
}
/**
* 查看信息
*/
function show(record) {
userShow.value.init(record.id)
}
/**
* 信息编辑
*/
function edit(record) {
userEdit.value.init(record.id)
}
/**
* 重置密码
*/
function resetPwd(record) {
userResetPwd.value.init(false, record.id)
}
/**
* 重置密码
*/
function resetPwdBatch() {
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
userResetPwd.value.init(true, userIds)
}
</script>
<style scoped></style>

View File

@@ -1,184 +0,0 @@
<template>
<basic-drawer
showFooter
title="添加用户"
v-bind="$attrs"
:width="modalWidth"
:open="visible"
:mask-closable="false"
@close="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form
class="small-from-item"
ref="formRef"
:model="form"
:rules="rules"
:validate-trigger="['blur', 'change']"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="用户账号" name="account" validate-first>
<a-input v-model:value="form.account" placeholder="请输入用户账号" />
</a-form-item>
<a-form-item label="用户名称" name="name">
<a-input v-model:value="form.name" placeholder="请输入用户名称" />
</a-form-item>
<a-form-item label="登录密码" name="password" validate-first>
<strength-meter
v-model:value="form.password"
placeholder="请输入登录密码"
@change="validateToNextPassword"
/>
</a-form-item>
<a-form-item label="确认密码" name="confirmPassword" validate-first>
<a-input-password v-model:value="form.confirmPassword" placeholder="请重新输入登录密码" />
</a-form-item>
<a-form-item label="手机号" validate-first name="phone">
<a-input v-model:value="form.phone" placeholder="请输入用户手机号" />
</a-form-item>
<a-form-item label="邮箱" validate-first name="email">
<a-input v-model:value="form.email" placeholder="请输入用户邮箱" />
</a-form-item>
</a-form>
</a-spin>
<template #footer>
<a-space>
<a-button key="cancel" @click="handleCancel">取消</a-button>
<a-button key="forward" :loading="confirmLoading" type="primary" @click="handleOk"
>保存</a-button
>
</a-space>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import { BasicDrawer } from '@/components/Drawer'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { nextTick, reactive, ref } from 'vue'
import StrengthMeter from '/@/components/StrengthMeter/src/StrengthMeter.vue'
import { validateEmail, validateMobile } from '@/utils/validate'
import { existsAccount, existsEmail, existsPhone } from '@/api/sys/userAssist'
import { add } from './MerchantUser.api'
import { useMessage } from '@/hooks/web/useMessage'
import { UserInfo } from '@/views/iam/user/User.api'
const { handleCancel, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
const { createMessage } = useMessage()
const formRef = ref<FormInstance>()
let form = ref<UserInfo>({
name: '',
account: '',
phone: '',
email: '',
password: '',
confirmPassword: '',
})
// 校验
const rules = reactive({
name: [{ required: true, message: '请输入用户名称' }],
account: [
{ required: true, message: '请输入用户账号' },
{ validator: checkAccount, trigger: 'blur' },
],
password: [{ required: true, message: '请输入登录密码!' }],
confirmPassword: [
{ required: true, message: '请重新输入登录密码!' },
{ validator: compareToFirstPassword },
],
phone: [{ validator: validatePhone }, { validator: validateBindPhone, trigger: 'blur' }],
email: [{ validator: validateEmailRule }, { validator: validateBindEmail, trigger: 'blur' }],
} as Record<string, Rule[]>)
let confirmDirty = ref(false)
// 事件
const emits = defineEmits(['ok'])
function init() {
visible.value = true
confirmLoading.value = false
nextTick(() => {
formRef.value?.resetFields()
})
}
function handleOk() {
formRef.value?.validate().then(async () => {
confirmLoading.value = true
await add(form.value).finally(() => (confirmLoading.value = false))
createMessage.success('添加用户成功')
confirmLoading.value = false
emits('ok')
handleCancel()
})
}
/**
* 用户名检查
*/
async function checkAccount() {
const { data } = await existsAccount(form.value.account)
return data ? Promise.reject('用户名已存在!') : Promise.resolve()
}
/**
* 密码检查
*/
function validateToNextPassword() {
if (confirmDirty.value) {
formRef.value?.validateFields(['confirmPassword'])
}
}
function compareToFirstPassword() {
if (form.value.confirmPassword !== form.value.password) {
confirmDirty.value = true
return Promise.reject('密码不一致')
} else {
return Promise.resolve()
}
}
/**
* 校验邮箱号
*/
function validateEmailRule() {
const { email } = form.value
if (!email) {
return Promise.resolve()
}
const { msg, result } = validateEmail(email)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验邮箱号是否被使用
*/
async function validateBindEmail() {
const { email } = form.value
const { data } = await existsEmail(email)
return data ? Promise.reject('邮箱已被使用') : Promise.resolve()
}
/**
* 校验手机号
*/
function validatePhone() {
const { phone } = form.value
if (!phone) {
return Promise.resolve()
}
const { msg, result } = validateMobile(phone)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验手机号是否被使用
*/
async function validateBindPhone() {
const { phone } = form.value
const { data } = await existsPhone(phone)
return data ? Promise.reject('手机号已被使用') : Promise.resolve()
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -1,170 +0,0 @@
<template>
<basic-drawer
showFooter
title="用户信息修改"
v-bind="$attrs"
:width="modalWidth"
:open="visible"
:mask-closable="false"
@ok="handleOk"
@close="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form
class="small-from-item"
ref="formRef"
:model="form"
:rules="rules"
:validate-trigger="['blur', 'change']"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="用户账号" validate-first name="account">
<a-input v-model:value="form.account" placeholder="请输入用户账号" />
</a-form-item>
<a-form-item label="用户名称" name="name">
<a-input v-model:value="form.name" placeholder="请输入用户名称" />
</a-form-item>
<a-form-item label="手机号" validate-first name="phone">
<a-input v-model:value="form.phone" placeholder="请输入用户手机号" />
</a-form-item>
<a-form-item label="邮箱" validate-first name="email">
<a-input v-model:value="form.email" placeholder="请输入用户邮箱" />
</a-form-item>
</a-form>
</a-spin>
</basic-drawer>
</template>
<script lang="ts" setup>
import { BasicDrawer } from '@/components/Drawer'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { computed, nextTick, ref } from 'vue'
import { existsEmailNotId, existsPhoneNotId, existsAccountNotId } from '@/api/sys/userAssist'
import { validateEmail, validateMobile } from '@/utils/validate'
import { useMessage } from '@/hooks/web/useMessage'
import { get, update } from './MerchantUser.api'
import { UserInfo } from '@/views/iam/user/User.api'
const { handleCancel, diffForm, labelCol, wrapperCol, modalWidth, confirmLoading, visible } =
useFormEdit()
const { createMessage } = useMessage()
const formRef = ref<FormInstance>()
let form = ref<UserInfo>({
id: null,
name: '',
account: '',
phone: '',
email: '',
})
let rawForm: any = {}
// 校验
const rules = computed(() => {
return {
name: [{ required: true, message: '请输入名称' }],
account: [
{ required: true, message: '请输入账号' },
{ validator: checkAccount, trigger: 'blur' },
],
phone:
rawForm.phone !== form.value.phone
? [{ validator: validatePhone }, { validator: validateBindPhone, trigger: 'blur' }]
: [],
email:
rawForm.email !== form.value.email
? [{ validator: validateEmailRule }, { validator: validateBindEmail, trigger: 'blur' }]
: [],
} as Record<string, Rule[]>
})
// 事件
const emits = defineEmits(['ok'])
/**
* 入口
*/
function init(id) {
visible.value = true
confirmLoading.value = true
nextTick(() => {
formRef.value?.resetFields()
})
get(id).then(({ data }) => {
rawForm = { ...data }
form.value = data
confirmLoading.value = false
})
}
/**
* 更新
*/
function handleOk() {
formRef.value?.validate().then(async () => {
confirmLoading.value = true
await update({
...form.value,
...diffForm(form.value, rawForm, 'password'),
}).finally(() => (confirmLoading.value = false))
createMessage.success('用户更改成功')
confirmLoading.value = false
emits('ok')
handleCancel()
})
}
/**
* 用户名检查
*/
async function checkAccount() {
const { data } = await existsAccountNotId(form.value.account, form.value.id)
return data ? Promise.reject('用户名已存在!') : Promise.resolve()
}
/**
* 校验邮箱号
*/
function validateEmailRule() {
const { email } = form.value
if (!email) {
return Promise.resolve()
}
const { msg, result } = validateEmail(email)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验邮箱号是否被使用
*/
async function validateBindEmail() {
const { email, id } = form.value
if (rawForm.email === email) {
return Promise.resolve()
}
const { data } = await existsEmailNotId(email, id)
return data ? Promise.reject('邮箱已被使用') : Promise.resolve()
}
/**
* 校验手机号
*/
function validatePhone() {
const { phone } = form.value
if (!phone) {
return Promise.resolve()
}
const { msg, result } = validateMobile(phone)
return result ? Promise.resolve() : Promise.reject(msg)
}
/**
* 后台校验手机号是否被使用
*/
async function validateBindPhone() {
const { phone, id } = form.value
const { data } = await existsPhoneNotId(phone, id)
return data ? Promise.reject('手机号已被使用') : Promise.resolve()
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -1,92 +0,0 @@
<template>
<basic-modal
v-bind="$attrs"
title="重置密码"
:width="modalWidth"
:open="visible"
:confirmLoading="confirmLoading"
:maskClosable="false"
@cancel="handleCancel"
@ok="handleOk"
>
<a-spin :spinning="confirmLoading">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:validate-trigger="['blur', 'change']"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item name="newPassword" label="重置密码">
<a-input-password v-model:value="form.newPassword" placeholder="请输入密码" />
</a-form-item>
</a-form>
</a-spin>
</basic-modal>
</template>
<script setup lang="ts">
import BasicModal from '@/components/Modal/src/BasicModal.vue'
import useFormEdit from '@/hooks/bootx/useFormEdit'
import { restartPassword, restartPasswordBatch } from './MerchantUser.api'
import { useMessage } from '@/hooks/web/useMessage'
import { Rule } from 'ant-design-vue/lib/form'
import { ref } from 'vue'
const { handleCancel, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
const { createConfirm, createMessage } = useMessage()
// 用户id
const userId = ref('')
// 用户ids
const userIds = ref<string[]>([])
const batch = ref(false)
let form = ref<any>({
newPassword: '',
})
let formRef = ref<any>()
const rules = {
newPassword: [{ required: true, message: '重置密码不得为空' }],
} as Record<string, Rule[]>
/**
* 初始化
*/
function init(b: boolean, userIdOrIds: string | string[]) {
visible.value = true
batch.value = b
if (!b) {
userId.value = userIdOrIds as string
} else {
userIds.value = userIdOrIds as never[]
}
}
function handleOk() {
formRef.value?.validate().then(async () => {
createConfirm({
iconType: 'info',
title: '警告',
content: '是否重置用户的密码',
onOk: async () => {
confirmLoading.value = true
if (batch.value) {
await restartPasswordBatch(userIds.value, form.value.newPassword).finally(
() => (confirmLoading.value = false),
)
} else {
await restartPassword(userId.value, form.value.newPassword).finally(
() => (confirmLoading.value = false),
)
}
createMessage.success('保存成功')
handleCancel()
},
})
})
}
defineExpose({ init })
</script>
<style scoped lang="less"></style>

View File

@@ -1,269 +0,0 @@
<template>
<basic-drawer
showFooter
v-bind="$attrs"
:title="modal.title"
width="40%"
:open="modal.visible"
@close="handleCancel"
>
<a-spin :spinning="modal.loading">
<a-input
style="margin-bottom: 8px"
placeholder="筛选"
allowClear
v-model:value="modal.searchName"
@change="search"
/>
<a-tree
:checkable="true"
:checkStrictly="true"
v-model:checkedKeys="modal.checkedKeys"
v-model:expandedKeys="modal.expandedKeys"
:auto-expand-parent="true"
:tree-data="modal.treeData"
@check="onCheck"
@expand="onExpand"
>
<template #title="{ title }">
<span v-if="title?.toLowerCase()?.indexOf(modal.searchName.toLowerCase()) > -1">
{{ searchRenderStart(title, modal.searchName) }}
<span style="color: #f50">
{{ searchRenderMiddle(title, modal.searchName) }}
</span>
{{ searchRenderEnd(title, modal.searchName) }}
</span>
<span v-else>{{ title }}</span>
</template>
</a-tree>
</a-spin>
<template #footer>
<a-dropdown style="margin-left: 5px" :trigger="['click']" placement="top">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
<a-menu-item key="3" @click="expandAll">展开所有</a-menu-item>
<a-menu-item key="4" @click="closeAll">合并所有</a-menu-item>
</a-menu>
</template>
<a-button post-icon="ant-design:up-outlined"> 操作 </a-button>
</a-dropdown>
<a-button @click="modal.visible = false" style="margin-right: 0.8rem">取消</a-button>
<a-button
@click="handleSubmit()"
type="primary"
:loading="modal.loading"
style="margin-right: 0.8rem"
>保存</a-button
>
</template>
</basic-drawer>
</template>
<script setup lang="ts">
import { BasicDrawer } from '@/components/Drawer'
import { reactive } from 'vue'
import { Tree, treeDataTranslate } from '@/utils/dataUtil'
import XEUtils from 'xe-utils'
import { RoleTree, tree as roleTree } from '@/views/iam/role/Role.api'
import { useMessage } from '@/hooks/web/useMessage'
import { addUserRole, addUserRoleBatch, getRoleIds } from './MerchantUser.api'
const { createConfirm, createMessage } = useMessage()
const modal = reactive({
title: '角色分配',
visible: false,
batch: false,
loading: false,
searchName: '',
// 所有的key
allTreeKeys: [] as string[],
// 展开的key
expandedKeys: [] as string[],
// 被选中的key
checkedKeys: [] as string[],
// 后台获取的角色树
treeData: [] as Tree[],
// 转换后的树数据
treeList: [] as RoleTree[],
// 用户id
userId: '',
// 用户ids
userIds: [],
// 角色Ids
roleIds: [],
})
/**
* 初始化
*/
async function init(batch: boolean, userIdOrIds: string | string[]) {
modal.visible = true
modal.batch = batch
modal.loading = true
// 初始化角色树
await initRoles()
if (!batch) {
modal.userId = userIdOrIds as string
// 初始化分配角色
await initAssign()
} else {
modal.userIds = userIdOrIds as never[]
}
modal.loading = false
}
/**
* 初始化菜单
*/
async function initRoles() {
modal.searchName = ''
modal.expandedKeys = []
// 角色树
await roleTree().then((res) => {
modal.treeData = treeDataTranslate(res.data, 'id', 'name')
generateTreeList(res.data)
})
}
/**
* 初始化权限码分配信息
*/
async function initAssign() {
// 当前用户已经选择的角色Id
await getRoleIds(modal.userId).then((res) => {
modal.checkedKeys = res.data
})
// 选中的的key值
modal.allTreeKeys = modal.treeList.map((item) => item.id) as string[]
}
/**
* 保存
*/
function handleSubmit() {
createConfirm({
iconType: 'info',
title: '警告',
content: '是否要保存角色分配信息',
onOk: async () => {
modal.loading = true
if (modal.batch) {
await addUserRoleBatch({
userIds: modal.userIds,
roleIds: modal.checkedKeys,
})
} else {
await addUserRole({
userId: modal.userId,
roleIds: modal.checkedKeys,
})
}
createMessage.success('保存成功')
modal.loading = false
modal.visible = false
},
})
}
/**
* 取消
*/
function handleCancel() {
modal.visible = false
}
/**
* 树数据铺平
*/
function generateTreeList(treeData) {
if (!treeData) {
return
}
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i]
modal.treeList.push(node)
if (node.children) {
generateTreeList(node.children)
}
}
}
/**
* 搜索
*/
function search() {
const value = XEUtils.toValueString(modal.searchName).toLowerCase()
modal.expandedKeys = modal.treeList
.map((node) => {
if (
modal.searchName &&
node.pid &&
XEUtils.toValueString(node.name)?.toLowerCase()?.indexOf(value) > -1
) {
return node.pid
}
})
.filter((item, i, self) => item && self.indexOf(item) === i) as string[]
}
/**
* 渲染搜索项目数据开始段
*/
function searchRenderStart(title, searchName) {
return title.substring(0, title.toLowerCase().indexOf(searchName.toLowerCase()))
}
/**
* 渲染搜索项目数据中间段
*/
function searchRenderMiddle(title, searchName) {
return title.substring(
title.toLowerCase().indexOf(searchName.toLowerCase()),
title.toLowerCase().indexOf(searchName.toLowerCase()) + searchName.length,
)
}
/**
* 渲染搜索项目数据结束段
*/
function searchRenderEnd(title, searchName) {
return title.substring(
title.toLowerCase().indexOf(searchName.toLowerCase()) + searchName.length,
)
}
/**
* 展开/收起节点时触发
*/
function onExpand(keys) {
modal.expandedKeys = keys
}
/**
* 点击复选框触发
*/
function onCheck(key) {
modal.checkedKeys = key.checked
}
/**
* 展开全部
*/
function expandAll() {
modal.expandedKeys = modal.allTreeKeys
}
/**
* 合并全部
*/
function closeAll() {
modal.expandedKeys = []
}
/**
* 全选
*/
function checkALL() {
modal.checkedKeys = modal.allTreeKeys
}
/**
* 全不选
*/
function cancelCheckALL() {
modal.checkedKeys = []
}
defineExpose({ init })
</script>
<style scoped lang="less"></style>

View File

@@ -1,85 +0,0 @@
<template>
<basic-drawer
show-footer
title="用户信息"
v-bind="$attrs"
:width="modalWidth"
:open="visible"
:mask-closable="false"
@close="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form
shio
class="small-from-item"
ref="formRef"
:model="form"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="用户账号" name="account">
<a-input disabled v-model:value="form.account" />
</a-form-item>
<a-form-item label="用户名称" name="name">
<a-input disabled v-model:value="form.name" />
</a-form-item>
<a-form-item label="手机号" name="phone">
<a-input disabled v-model:value="form.phone" />
</a-form-item>
<a-form-item label="邮箱">
<a-input disabled v-model:value="form.email" />
</a-form-item>
<a-form-item label="管理员">
<a-tag v-if="form.administrator" color="green"></a-tag>
<a-tag v-else></a-tag>
</a-form-item>
<a-form-item label="用户状态">
<a-tag>{{ dictConvert('UserStatusCode', form.status) || '无' }}</a-tag>
</a-form-item>
<a-form-item label="角色列表">
<a-tag color="green" v-for="o in roles" :key="o.id">{{ o.name }}</a-tag>
</a-form-item>
</a-form>
</a-spin>
<template #footer>
<a-button key="cancel" @click="handleCancel">取消</a-button>
</template>
</basic-drawer>
</template>
<script lang="ts" setup>
import useFormEdit from '@/hooks/bootx/useFormEdit'
import BasicDrawer from '/@/components/Drawer/src/BasicDrawer.vue'
import { get, getRoles } from './MerchantUser.api'
import { useDict } from '@/hooks/bootx/useDict'
import { ref } from 'vue'
import { Role } from '@/views/iam/role/Role.api'
import { UserInfo } from '@/views/iam/user/User.api'
const { handleCancel, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
const { dictConvert } = useDict()
let form = ref<UserInfo>({
name: '',
account: '',
})
let roles = ref<Role[]>([])
async function init(id) {
confirmLoading.value = true
visible.value = true
Promise.all([
get(id).then((res) => {
form.value = res.data
}),
getRoles(id).then((res) => {
roles.value = res.data
}),
]).then(() => (confirmLoading.value = false))
}
defineExpose({ init })
</script>
<style scoped></style>

View File

@@ -3,7 +3,7 @@
<div class="m-3 p-3 pt-5 bg-white">
<a-form class="page-query">
<a-row :gutter="10">
<a-col :md="4" :sm="24" v-if="isAdmin()">
<a-col :md="4" :sm="24">
<a-form-item label="终端">
<a-select
v-model:value="clientCode"
@@ -78,7 +78,7 @@
import PermPathInfo from './PermPathInfo.vue'
import { Client, findAll } from '@/views/iam/client/Client.api'
import XEUtils from 'xe-utils'
import { getAppEnvConfig, isAdmin } from '@/utils/env'
import { getAppEnvConfig } from '@/utils/env'
const { createMessage, createConfirm } = useMessage()

View File

@@ -42,7 +42,6 @@
style="min-width: 100px"
@change="clientSwitch"
v-model:value="clientCode"
v-if="isAdmin()"
>
<a-select-option v-for="o in clients" :key="o.code">{{ o.name }}</a-select-option>
</a-select>
@@ -72,7 +71,7 @@
<script lang="ts" setup>
import { BasicDrawer } from '@/components/Drawer'
import { findAll as findClients, Client } from '@/views/iam/client/Client.api'
import { getAppEnvConfig, isAdmin } from '@/utils/env'
import { getAppEnvConfig } from '@/utils/env'
import { RoleTree } from './Role.api'
import { Tree, treeDataTranslate } from '@/utils/dataUtil'
import XEUtils from 'xe-utils'

View File

@@ -38,7 +38,6 @@
</a-spin>
<template #footer>
<a-select
v-if="isAdmin()"
style="min-width: 100px"
@change="clientSwitch"
v-model:value="clientCode"
@@ -71,7 +70,7 @@
<script lang="ts" setup>
import { BasicDrawer } from '@/components/Drawer'
import { findAll as findClients, Client } from '@/views/iam/client/Client.api'
import { getAppEnvConfig, isAdmin } from "@/utils/env";
import { getAppEnvConfig } from "@/utils/env";
import { RoleTree } from './Role.api'
import { Tree, treeDataTranslate } from '@/utils/dataUtil'
import XEUtils from 'xe-utils'

View File

@@ -4,7 +4,7 @@
<div class="flex justify-between items-center">
<span class="flex-1">
<a :href="GITHUB_URL" target="_blank">{{ name }}</a>
是DaxPay商户支付管理系统的前端项目基于Vue3.0Vite Ant-Design-Vue TypeScript实现
是DaxPay商户支付管理系统的前端项目基于Vue3.0Vite Ant-Design-Vue TypeScript实现
</span>
</div>
</template>

2
types/web.d.ts vendored
View File

@@ -34,8 +34,6 @@ export interface BaseEntity {
* 商户应用基础实体对象
*/
export interface MchEntity extends BaseEntity {
// 商户号
mchNo?: string
// 应用号
appId?: string
}

View File

@@ -19,20 +19,11 @@ export default defineApplicationConfig({
port: 3300,
proxy: {
// 运营管理端
'/admin': {
'/server': {
target: 'http://localhost:9999',
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp(`^/admin`), ''),
// only https
// secure: false
},
// 商户端
'/merchant': {
target: 'http://localhost:8888',
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp(`^/merchant`), ''),
rewrite: (path) => path.replace(new RegExp(`^/server`), ''),
// only https
// secure: false
},