Browse Source

feat: 账户中心表单控件切换到 TDesign

main
xiaosi 3 weeks ago
parent
commit
4c154bbf76
  1. 65
      src/views/AccountView/AccountView.vue

65
src/views/AccountView/AccountView.vue

@ -51,7 +51,7 @@
<div class="business-panel account-panel" :class="{ active: tab === 'traffic' }" style="padding:18px"> <div class="business-panel account-panel" :class="{ active: tab === 'traffic' }" style="padding:18px">
<div class="traffic-balance-card"><span>当前云媒体流量余额</span><strong>{{ balance }} <small>GB</small></strong><p>流量用于直播回放与原始素材下载</p></div> <div class="traffic-balance-card"><span>当前云媒体流量余额</span><strong>{{ balance }} <small>GB</small></strong><p>流量用于直播回放与原始素材下载</p></div>
<div class="traffic-purchase-layout" style="margin-top:16px"> <div class="traffic-purchase-layout" style="margin-top:16px">
<div class="traffic-amount-block"><label><span>购买流量GB</span><div><input v-model.number="trafficAmount" type="number" min="1" /><b>GB</b></div></label></div>
<div class="traffic-amount-block"><label><span>购买流量GB</span><div class="traffic-amount-input"><t-input-number v-model="trafficAmount" theme="normal" :min="1" /><b>GB</b></div></label></div>
<div class="traffic-order-summary"><span>订单概要</span><strong>云媒体流量订单</strong><small>订单创建后由管理员人工确认金额以服务端订单为准</small><button class="primary-command" @click="createOrder">创建订单</button></div> <div class="traffic-order-summary"><span>订单概要</span><strong>云媒体流量订单</strong><small>订单创建后由管理员人工确认金额以服务端订单为准</small><button class="primary-command" @click="createOrder">创建订单</button></div>
</div> </div>
<div class="account-subsection-title"><h3>订单记录</h3><span> {{ orderTotal }} </span></div> <div class="account-subsection-title"><h3>订单记录</h3><span> {{ orderTotal }} </span></div>
@ -77,11 +77,11 @@
<div class="business-panel account-panel" :class="{ active: tab === 'security' }" style="padding:18px"><div class="account-section-heading"><h2>账号安全</h2><span>修改密码后将退出所有设备</span></div><div class="security-list"><div><span><strong>登录手机号</strong><small>{{ maskPhone(profilePhone) }}</small></span></div><div><span><strong>绑定邮箱</strong><small>{{ profileEmail }}</small></span></div><div><span><strong>登录会话</strong><small> {{ sessions.length }} 个有效会话</small></span><button class="plain-command" @click="revokeOthers">退出其他设备</button></div></div><div class="account-order-table"><div class="order-head"><span>设备</span><span>IP</span><span>最近活跃</span><span>过期时间</span><span>操作</span></div><div v-for="session in sessions" :key="session.id"><span>{{ session.userAgent || '未知设备' }}{{ session.current ? '(当前)' : '' }}</span><span>{{ session.ip || '--' }}</span><span>{{ fmtTime(session.lastActiveAt) }}</span><span>{{ fmtTime(session.expiresAt) }}</span><button v-if="!session.current" class="table-text-action" @click="revokeSession(session.id)">退出</button><span v-else>当前会话</span></div></div><div v-if="!sessions.length" class="table-empty">暂无有效会话</div><div class="account-card-actions"><button class="primary-command" @click="passwordOpen = true">修改密码</button></div></div> <div class="business-panel account-panel" :class="{ active: tab === 'security' }" style="padding:18px"><div class="account-section-heading"><h2>账号安全</h2><span>修改密码后将退出所有设备</span></div><div class="security-list"><div><span><strong>登录手机号</strong><small>{{ maskPhone(profilePhone) }}</small></span></div><div><span><strong>绑定邮箱</strong><small>{{ profileEmail }}</small></span></div><div><span><strong>登录会话</strong><small> {{ sessions.length }} 个有效会话</small></span><button class="plain-command" @click="revokeOthers">退出其他设备</button></div></div><div class="account-order-table"><div class="order-head"><span>设备</span><span>IP</span><span>最近活跃</span><span>过期时间</span><span>操作</span></div><div v-for="session in sessions" :key="session.id"><span>{{ session.userAgent || '未知设备' }}{{ session.current ? '(当前)' : '' }}</span><span>{{ session.ip || '--' }}</span><span>{{ fmtTime(session.lastActiveAt) }}</span><span>{{ fmtTime(session.expiresAt) }}</span><button v-if="!session.current" class="table-text-action" @click="revokeSession(session.id)">退出</button><span v-else>当前会话</span></div></div><div v-if="!sessions.length" class="table-empty">暂无有效会话</div><div class="account-card-actions"><button class="primary-command" @click="passwordOpen = true">修改密码</button></div></div>
<div class="business-panel account-panel" :class="{ active: tab === 'invoice' }" style="padding:18px"><div class="account-section-heading"><h2>发票资料与申请</h2><span>仅对已人工确认的流量订单开放申请</span></div><div class="traffic-purchase-layout"><div class="traffic-amount-block"><label><span>发票抬头</span><input v-model.trim="invoiceForm.title" maxlength="128" /></label><label><span>纳税人识别号</span><input v-model.trim="invoiceForm.taxpayerNumber" maxlength="64" /></label><label><span>接收邮箱</span><input v-model.trim="invoiceForm.email" type="email" /></label><button class="primary-command" @click="saveInvoiceProfile">保存默认发票资料</button></div><div class="traffic-order-summary"><span>可申请订单</span><select v-model.number="invoiceOrderId"><option :value="0">请选择已支付订单</option><option v-for="order in invoiceOrders" :key="order.id" :value="order.id">{{ order.id }} · {{ money(order.totalPrice) }}</option></select><button class="primary-command" :disabled="!invoiceOrderId" @click="createInvoiceRequest">提交人工申请</button></div></div><div class="account-subsection-title"><h3>申请记录</h3><span>人工处理,不自动开票</span></div><div class="account-order-table"><div class="order-head"><span>订单号</span><span>金额</span><span>抬头</span><span>状态</span><span>申请时间</span></div><div v-for="request in invoiceRequests" :key="request.id"><span>{{ request.orderId }}</span><strong>{{ money(request.amount) }}</strong><span>{{ request.title }}</span><em :class="{ processing: request.status === 'pending' }">{{ invoiceStatusName(request.status) }}</em><span>{{ fmtTime(request.requestedAt) }}</span></div></div><div v-if="!invoiceRequests.length" class="table-empty">暂无发票申请</div></div>
<div class="business-panel account-panel" :class="{ active: tab === 'invoice' }" style="padding:18px"><div class="account-section-heading"><h2>发票资料与申请</h2><span>仅对已人工确认的流量订单开放申请</span></div><div class="traffic-purchase-layout"><div class="traffic-amount-block"><label><span>发票抬头</span><t-input v-model.trim="invoiceForm.title" :maxlength="128" /></label><label><span>纳税人识别号</span><t-input v-model.trim="invoiceForm.taxpayerNumber" :maxlength="64" /></label><label><span>接收邮箱</span><t-input v-model.trim="invoiceForm.email" type="email" /></label><button class="primary-command" @click="saveInvoiceProfile">保存默认发票资料</button></div><div class="traffic-order-summary"><span>可申请订单</span><t-select v-model="invoiceOrderId" :options="invoiceOrderOptions" style="width: 100%" /><button class="primary-command" :disabled="!invoiceOrderId" @click="createInvoiceRequest">提交开具发票</button></div></div><div class="account-subsection-title"><h3>发票记录</h3><span>仅展示已提交的开具申请</span></div><div class="account-order-table"><div class="order-head"><span>订单号</span><span>金额</span><span>抬头</span><span>状态</span><span>申请时间</span></div><div v-for="request in invoiceRequests" :key="request.id"><span>{{ request.orderId }}</span><strong>{{ money(request.amount) }}</strong><span>{{ request.title }}</span><em :class="{ processing: request.status === 'pending' }">{{ invoiceStatusName(request.status) }}</em><span>{{ fmtTime(request.requestedAt) }}</span></div></div><div v-if="!invoiceRequests.length" class="table-empty">暂无发票申请</div></div>
</div> </div>
<div class="modal-backdrop" :class="{ open: editOpen }" @click.self="editOpen = false"><div class="recharge-modal"><h3>编辑账户资料</h3><label>账户名称<input v-model.trim="editForm.name" maxlength="32" /></label><label>邮箱<input v-model.trim="editForm.email" type="email" /></label><div class="recharge-modal-footer"><button class="cancel" @click="editOpen = false">取消</button><button class="confirm" :disabled="saving" @click="saveProfile">{{ saving ? '保存中' : '保存' }}</button></div></div></div>
<div class="modal-backdrop" :class="{ open: passwordOpen }" @click.self="passwordOpen = false"><div class="recharge-modal"><h3>修改密码</h3><label>当前密码<input v-model="passwordForm.oldPassword" type="password" /></label><label>新密码<input v-model="passwordForm.newPassword" type="password" minlength="6" /></label><div class="recharge-modal-footer"><button class="cancel" @click="passwordOpen = false">取消</button><button class="confirm" @click="changePassword">确认修改</button></div></div></div>
<div class="modal-backdrop" :class="{ open: editOpen }" @click.self="editOpen = false"><div class="recharge-modal"><h3>编辑账户资料</h3><label><span>账户名称</span><t-input v-model.trim="editForm.name" :maxlength="32" /></label><label><span>邮箱</span><t-input v-model.trim="editForm.email" type="email" /></label><div class="recharge-modal-footer"><button class="cancel" @click="editOpen = false">取消</button><button class="confirm" :disabled="saving" @click="saveProfile">{{ saving ? '保存中' : '保存' }}</button></div></div></div>
<div class="modal-backdrop" :class="{ open: passwordOpen }" @click.self="passwordOpen = false"><div class="recharge-modal"><h3>修改密码</h3><label><span>当前密码</span><t-input v-model="passwordForm.oldPassword" type="password" /></label><label><span>新密码</span><t-input v-model="passwordForm.newPassword" type="password" /></label><div class="recharge-modal-footer"><button class="cancel" @click="passwordOpen = false">取消</button><button class="confirm" @click="changePassword">确认修改</button></div></div></div>
</section> </section>
</template> </template>
@ -123,6 +123,7 @@ const profileRole = computed(() => profile.value?.role === 'admin' ? '管理员'
const accountStatus = computed(() => profile.value?.status === 1 ? '正常' : profile.value?.status === 0 ? '已禁用' : '--') const accountStatus = computed(() => profile.value?.status === 1 ? '正常' : profile.value?.status === 0 ? '已禁用' : '--')
const createdAt = computed(() => profile.value?.createdAt ? fmtTime(profile.value.createdAt) : '--') const createdAt = computed(() => profile.value?.createdAt ? fmtTime(profile.value.createdAt) : '--')
const profileInitial = computed(() => profileName.value === '--' ? '-' : profileName.value.charAt(0)) const profileInitial = computed(() => profileName.value === '--' ? '-' : profileName.value.charAt(0))
const invoiceOrderOptions = computed(() => [{ label: '请选择已支付订单', value: 0 }, ...invoiceOrders.value.map((order) => ({ label: `${order.id} · ${money(order.totalPrice)}`, value: order.id }))])
const activeSimCount = computed(() => simCards.value.filter((card) => simStatus(card).cls === 'normal').length) const activeSimCount = computed(() => simCards.value.filter((card) => simStatus(card).cls === 'normal').length)
const warnSimCount = computed(() => simTotal.value - activeSimCount.value) const warnSimCount = computed(() => simTotal.value - activeSimCount.value)
@ -169,3 +170,59 @@ async function createOrder() { try { const order = await request.post(urls.TRAFF
async function saveProfile() { saving.value = true; try { const updated = await request.put(urls.ACCOUNT_PROFILE, editForm.value); profile.value = updated; userStore.user = { ...(userStore.user || {}), ...updated }; localStorage.setItem('user', JSON.stringify(userStore.user)); editOpen.value = false; ui.toast('账户资料已保存') } catch (error) { ui.toast(error.message || '保存账户资料失败') } finally { saving.value = false } } async function saveProfile() { saving.value = true; try { const updated = await request.put(urls.ACCOUNT_PROFILE, editForm.value); profile.value = updated; userStore.user = { ...(userStore.user || {}), ...updated }; localStorage.setItem('user', JSON.stringify(userStore.user)); editOpen.value = false; ui.toast('账户资料已保存') } catch (error) { ui.toast(error.message || '保存账户资料失败') } finally { saving.value = false } }
onMounted(load) onMounted(load)
</script> </script>
<style scoped>
.traffic-amount-input {
height: 46px;
display: flex;
align-items: center;
border: 1px solid #cfdae2;
border-radius: 4px;
overflow: hidden;
}
.traffic-amount-input :deep(.t-input-number) {
flex: 1;
width: auto;
height: 100%;
}
.traffic-amount-input :deep(.t-input) {
height: 100%;
border: 0;
border-radius: 0;
box-shadow: none;
font-size: 19px;
}
.traffic-amount-input :deep(.t-input:focus),
.traffic-amount-input :deep(.t-is-focused) {
box-shadow: none;
border-color: transparent;
}
.traffic-amount-input b {
padding: 0 13px;
color: #6c7d88;
font-size: 12px;
font-weight: 500;
flex-shrink: 0;
}
.traffic-amount-block :deep(.t-input),
.traffic-amount-block :deep(.t-select),
.traffic-order-summary :deep(.t-select),
.recharge-modal :deep(.t-input) {
width: 100%;
}
.traffic-amount-block > label {
display: block;
margin-bottom: 12px;
}
.traffic-order-summary :deep(.t-select) {
margin: 10px 0 14px;
}
.recharge-modal label {
display: flex;
flex-direction: column;
gap: 8px;
margin: 12px 0 0;
color: #4e5f6b;
font-size: 12px;
}
</style>

Loading…
Cancel
Save