180 lines
3.9 KiB
Vue
180 lines
3.9 KiB
Vue
<template>
|
||
<el-card class="channel-card" shadow="hover" :body-style="{ padding: '18px 20px' }">
|
||
<div class="card-head">
|
||
<div class="head-left">
|
||
<div class="icon-wrap" :class="statusClass">
|
||
<el-icon :size="22">
|
||
<component :is="iconComp" />
|
||
</el-icon>
|
||
</div>
|
||
<div class="title-wrap">
|
||
<div class="channel-name">{{ name }}</div>
|
||
<div class="merchant-no">{{ idLabel }}:{{ merchantNo || (status === 'unconfigured' ? '未配置' : '已配置') }}</div>
|
||
</div>
|
||
</div>
|
||
<StatusTag :status="status" dict="channel" />
|
||
</div>
|
||
|
||
<div v-if="desc" class="card-desc">{{ desc }}</div>
|
||
|
||
<div class="card-foot">
|
||
<el-button size="small" type="primary" plain @click="emit('config')">配置</el-button>
|
||
<el-button v-if="status === 'enabled'" size="small" type="danger" plain @click="emit('disable')">
|
||
停用
|
||
</el-button>
|
||
<el-button
|
||
v-else
|
||
size="small"
|
||
type="success"
|
||
plain
|
||
:disabled="status === 'unconfigured'"
|
||
@click="emit('enable')"
|
||
>
|
||
启用
|
||
</el-button>
|
||
</div>
|
||
</el-card>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed } from 'vue'
|
||
import {
|
||
ChatDotRound,
|
||
Wallet,
|
||
CreditCard,
|
||
Lightning,
|
||
Money,
|
||
PriceTag
|
||
} from '@element-plus/icons-vue'
|
||
import StatusTag from './StatusTag.vue'
|
||
|
||
/** 常用渠道图标映射:微信 / 支付宝 / 银联 / 云闪付 / PayPal / 兜底 */
|
||
const ICONS: Record<string, any> = {
|
||
ChatDotRound,
|
||
Wallet,
|
||
CreditCard,
|
||
Lightning,
|
||
Money,
|
||
PriceTag
|
||
}
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
/** 渠道标识,如 wechat / alipay / paypal */
|
||
channel?: string
|
||
/** 渠道名称,如「微信支付」 */
|
||
name: string
|
||
/** 渠道状态:enabled 已启用 / disabled 已停用 / unconfigured 未配置 */
|
||
status?: string
|
||
/** 商户号,未配置时显示「未配置」 */
|
||
merchantNo?: string
|
||
/** 图标名:ChatDotRound / Wallet / CreditCard / Lightning / Money */
|
||
icon?: string
|
||
/** 卡片补充说明 */
|
||
desc?: string
|
||
}>(),
|
||
{
|
||
channel: '',
|
||
status: 'unconfigured',
|
||
merchantNo: '',
|
||
icon: 'PriceTag',
|
||
desc: ''
|
||
}
|
||
)
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'config'): void
|
||
(e: 'enable'): void
|
||
(e: 'disable'): void
|
||
}>()
|
||
|
||
const idLabel = computed(() => {
|
||
if (props.channel === 'paypal') return 'Client ID'
|
||
if (props.channel === 'cloudpay') return '银联商户号'
|
||
return '商户号'
|
||
})
|
||
|
||
const iconComp = computed(() => ICONS[props.icon] || PriceTag)
|
||
|
||
const statusClass = computed(() => {
|
||
if (props.status === 'enabled') return 'is-enabled'
|
||
if (props.status === 'unconfigured') return 'is-unconfigured'
|
||
return 'is-disabled'
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.channel-card {
|
||
margin-bottom: 0;
|
||
|
||
.card-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
|
||
.head-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.icon-wrap {
|
||
width: 42px;
|
||
height: 42px;
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
flex-shrink: 0;
|
||
|
||
&.is-enabled {
|
||
background: linear-gradient(135deg, #52c41a, #95de64);
|
||
}
|
||
|
||
&.is-disabled {
|
||
background: linear-gradient(135deg, #909399, #b1b3b8);
|
||
}
|
||
|
||
&.is-unconfigured {
|
||
background: linear-gradient(135deg, #e6a23c, #f3d19e);
|
||
}
|
||
}
|
||
|
||
.title-wrap {
|
||
min-width: 0;
|
||
}
|
||
|
||
.channel-name {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
|
||
.merchant-no {
|
||
margin-top: 4px;
|
||
font-size: 12px;
|
||
color: #909399;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.card-desc {
|
||
margin-top: 12px;
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
color: #909399;
|
||
}
|
||
|
||
.card-foot {
|
||
margin-top: 16px;
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
}
|
||
</style>
|