大改三角色逻辑:超级管理员、企业管理员、开票员
This commit is contained in:
@@ -74,10 +74,23 @@
|
||||
</n-form>
|
||||
</n-modal>
|
||||
|
||||
<n-modal v-model:show="showSms" preset="card" title="短信登录" class="sms-card">
|
||||
<n-space vertical>
|
||||
<n-alert v-if="smsTip" type="info">{{ smsTip }}</n-alert>
|
||||
<n-input v-model:value="smsCode" placeholder="请输入短信验证码" />
|
||||
<n-modal
|
||||
v-model:show="showSms"
|
||||
preset="card"
|
||||
title="短信登录"
|
||||
:style="{ width: '360px', maxWidth: '88vw' }"
|
||||
content-style="padding: 14px 18px 18px"
|
||||
>
|
||||
<n-space vertical size="small" class="auth-panel">
|
||||
<div class="auth-account">
|
||||
<span>税局账号</span>
|
||||
<strong>{{ selected?.account || '-' }}</strong>
|
||||
</div>
|
||||
<n-alert v-if="smsTip" type="info" :show-icon="false">{{ smsTip }}</n-alert>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="smsCode" placeholder="请输入短信验证码" />
|
||||
<n-button :loading="smsCodeLoading" @click="sendSmsCode">发送验证码</n-button>
|
||||
</n-input-group>
|
||||
<div class="modal-actions">
|
||||
<n-button @click="showSms = false">取消</n-button>
|
||||
<n-button type="primary" :loading="smsLoading" @click="submitSms">确认登录</n-button>
|
||||
@@ -85,12 +98,36 @@
|
||||
</n-space>
|
||||
</n-modal>
|
||||
|
||||
<n-modal v-model:show="showQrcode" preset="card" title="风险认证" class="sms-card">
|
||||
<div class="qrcode-wrap">
|
||||
<img v-if="qrcodeImg" :src="qrcodeImg" alt="认证二维码" />
|
||||
<n-empty v-else description="暂无二维码" />
|
||||
<n-button size="small" :loading="qrLoading" @click="loadQrcode">刷新二维码</n-button>
|
||||
</div>
|
||||
<n-modal
|
||||
v-model:show="showQrcode"
|
||||
preset="card"
|
||||
title="风险认证"
|
||||
:style="{ width: '400px', maxWidth: '88vw' }"
|
||||
content-style="padding: 14px 18px 18px"
|
||||
>
|
||||
<n-space vertical size="small" class="auth-panel">
|
||||
<div class="auth-account">
|
||||
<span>税局账号</span>
|
||||
<strong>{{ selected?.account || '-' }}</strong>
|
||||
</div>
|
||||
<n-radio-group v-model:value="qrcodeType" size="small" @update:value="loadQrcode">
|
||||
<n-radio-button value="1">电子税务局 APP</n-radio-button>
|
||||
<n-radio-button value="2">国家网络身份认证 APP</n-radio-button>
|
||||
</n-radio-group>
|
||||
<div class="qrcode-wrap">
|
||||
<img v-if="qrcodeImg" :src="qrcodeImg" :alt="qrcodeTypeLabel" />
|
||||
<n-empty v-else description="暂无二维码" />
|
||||
</div>
|
||||
<div class="qrcode-meta">
|
||||
<span>{{ qrcodeTypeLabel }}</span>
|
||||
<small v-if="qrcodeGenTime">生成时间:{{ qrcodeGenTime }}</small>
|
||||
<small v-if="qrcodeTip">{{ qrcodeTip }}</small>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<n-button @click="showQrcode = false">关闭</n-button>
|
||||
<n-button type="primary" :loading="qrLoading" @click="loadQrcode">刷新二维码</n-button>
|
||||
</div>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -109,11 +146,15 @@ import {
|
||||
NGrid,
|
||||
NIcon,
|
||||
NInput,
|
||||
NInputGroup,
|
||||
NModal,
|
||||
NPopconfirm,
|
||||
NRadioButton,
|
||||
NRadioGroup,
|
||||
NSelect,
|
||||
NSpace,
|
||||
NTag,
|
||||
NTooltip,
|
||||
useMessage
|
||||
} from 'naive-ui'
|
||||
import { KeyRound, Plus, RefreshCw, ShieldCheck } from 'lucide-vue-next'
|
||||
@@ -138,15 +179,22 @@ const showCreate = ref(false)
|
||||
const showSms = ref(false)
|
||||
const showQrcode = ref(false)
|
||||
const smsLoading = ref(false)
|
||||
const smsCodeLoading = ref(false)
|
||||
const qrLoading = ref(false)
|
||||
const smsCode = ref('')
|
||||
const smsTip = ref('')
|
||||
const qrcodeImg = ref('')
|
||||
const qrcodeType = ref('1')
|
||||
const qrcodeGenTime = ref('')
|
||||
const qrcodeTip = ref('')
|
||||
const selected = ref<DigitalAccountItem | null>(null)
|
||||
const createFormRef = ref<FormInst | null>(null)
|
||||
|
||||
const canManage = computed(() => authStore.user?.userType !== 'DIGITAL_OPERATOR')
|
||||
const canUpdateStatus = computed(() => authStore.hasPermission('digital-account:status'))
|
||||
const qrcodeTypeLabel = computed(() =>
|
||||
qrcodeType.value === '2' ? '国家网络身份认证 APP' : '电子税务局 APP'
|
||||
)
|
||||
|
||||
const createForm = reactive({
|
||||
account: '',
|
||||
@@ -175,7 +223,13 @@ const identityOptions = [
|
||||
|
||||
const columns: DataTableColumns<DigitalAccountItem> = [
|
||||
{ title: '税局账号', key: 'account', minWidth: 140 },
|
||||
{ title: '平台登录账号', key: 'platformUsername', minWidth: 180, render: (row) => row.platformUsername || '-' },
|
||||
{
|
||||
title: '平台登录账号',
|
||||
key: 'platformUsername',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
render: (row) => renderEllipsisText(row.platformUsername)
|
||||
},
|
||||
{ title: '姓名', key: 'name', minWidth: 100 },
|
||||
{ title: '登录身份', key: 'identityType', render: (row) => identityLabel(row.identityType) },
|
||||
{ title: '账号状态', key: 'authStatus', render: (row) => authStatusLabel(row.authStatus) },
|
||||
@@ -214,8 +268,9 @@ const columns: DataTableColumns<DigitalAccountItem> = [
|
||||
{
|
||||
title: 'API Key',
|
||||
key: 'apiKey',
|
||||
minWidth: 180,
|
||||
render: (row) => row.apiKey || '-'
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
render: (row) => renderEllipsisText(row.apiKey)
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
@@ -282,6 +337,18 @@ function authStatusLabel(value?: string | null) {
|
||||
return value ? map[value] || value : '-'
|
||||
}
|
||||
|
||||
function renderEllipsisText(value?: string | null) {
|
||||
if (!value) return '-'
|
||||
return h(
|
||||
NTooltip,
|
||||
{ trigger: 'hover' },
|
||||
{
|
||||
trigger: () => h('span', { class: 'cell-ellipsis' }, value),
|
||||
default: () => value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -324,13 +391,21 @@ async function updateAccountStatus(row: DigitalAccountItem) {
|
||||
async function openSms(row: DigitalAccountItem) {
|
||||
selected.value = row
|
||||
smsCode.value = ''
|
||||
smsLoading.value = true
|
||||
smsTip.value = ''
|
||||
showSms.value = true
|
||||
}
|
||||
|
||||
async function sendSmsCode() {
|
||||
if (!selected.value) return
|
||||
smsCodeLoading.value = true
|
||||
try {
|
||||
const res = await sendLoginSmsCodeApi({ taxpayerNum: row.taxpayerNum, account: row.account })
|
||||
const res = await sendLoginSmsCodeApi({
|
||||
taxpayerNum: selected.value.taxpayerNum,
|
||||
account: selected.value.account
|
||||
})
|
||||
smsTip.value = res.phoneNum ? `验证码已发送至 ${res.phoneNum}` : res.resultMsg
|
||||
} finally {
|
||||
smsLoading.value = false
|
||||
smsCodeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,6 +428,10 @@ async function submitSms() {
|
||||
|
||||
async function openQrcode(row: DigitalAccountItem) {
|
||||
selected.value = row
|
||||
qrcodeType.value = '1'
|
||||
qrcodeImg.value = ''
|
||||
qrcodeGenTime.value = ''
|
||||
qrcodeTip.value = ''
|
||||
showQrcode.value = true
|
||||
await loadQrcode()
|
||||
}
|
||||
@@ -361,8 +440,11 @@ async function loadQrcode() {
|
||||
if (!selected.value) return
|
||||
qrLoading.value = true
|
||||
try {
|
||||
const res = await getAuthQrcodeApi('1', selected.value.id)
|
||||
const res = await getAuthQrcodeApi(qrcodeType.value, selected.value.id)
|
||||
qrcodeImg.value = res.qrcodeImg ? `data:image/png;base64,${res.qrcodeImg}` : ''
|
||||
qrcodeType.value = res.qrcodeType || qrcodeType.value
|
||||
qrcodeGenTime.value = res.genTime || ''
|
||||
qrcodeTip.value = res.resultMsg || ''
|
||||
} finally {
|
||||
qrLoading.value = false
|
||||
}
|
||||
@@ -388,27 +470,81 @@ onMounted(load)
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cell-ellipsis {
|
||||
display: inline-block;
|
||||
width: 148px;
|
||||
max-width: 148px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.modal-card {
|
||||
width: min(720px, 92vw);
|
||||
}
|
||||
|
||||
.sms-card {
|
||||
width: min(420px, 92vw);
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #eef1f5;
|
||||
}
|
||||
|
||||
.auth-panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.auth-account {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #eef1f5;
|
||||
border-radius: 8px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.auth-account span {
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.auth-account strong {
|
||||
color: #111827;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.qrcode-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
min-height: 236px;
|
||||
border: 1px solid #eef1f5;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.qrcode-wrap img {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.qrcode-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qrcode-meta span {
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user