feat: 抬头管理

This commit is contained in:
hhm 2025-11-24 18:01:39 +08:00
parent 62d9fb8516
commit c19b0167e4
4 changed files with 179 additions and 106 deletions

View File

@ -76,4 +76,10 @@ export default {
createPolicy: (data = {}) => request.post('/policy/create', data), createPolicy: (data = {}) => request.post('/policy/create', data),
updatePolicy: (data = {}) => request.post('/policy/update', data), updatePolicy: (data = {}) => request.post('/policy/update', data),
deletePolicy: (params = {}) => request.delete('/policy/delete', { params }), deletePolicy: (params = {}) => request.delete('/policy/delete', { params }),
//发票`/valuations/${data.id}`
getInvoiceHeaders: () => request.get('/app-invoices/headers'),
addInvoiceHeaders: (data = {}) => request.post('/app-invoices/headers', data),
updateInvoiceHeaders: (data = {}) => request.put(`/app-invoices/headers/${data.id}`, data),
deleteInvoiceHeaders: (id) => request.delete(`/app-invoices/headers/${id}`),
} }

View File

@ -62,26 +62,48 @@
v-model:show="showAgreement" v-model:show="showAgreement"
preset="card" preset="card"
title="用户服务协议" title="用户服务协议"
style="width: 800px; max-width: 90vw;" style="width: 800px; max-width: 90vw"
:bordered="false" :bordered="false"
> >
<div class="agreement-content" style="max-height: 60vh; overflow-y: auto; padding: 0 10px;"> <div
class="agreement-content"
style="max-height: 60vh; overflow-y: auto; padding: 0 10px"
>
<h3>特别提示</h3> <h3>特别提示</h3>
<p>在此特别提醒您用户在注册成为用户之前请认真阅读本用户协议以下简称协议确保您充分理解本协议中各条款请您审慎阅读并选择接受或不接受本协议除非您接受本协议所有条款否则您无权注册登录或使用本协议所涉服务您的注册登录使用等行为将视为对本协议的接受并同意接受本协议各项条款的约束</p> <p>
<p>本协议约定成都文化产权交易所有限公司以下简称成都文交所与用户之间关于IP文产通平台服务以下简称服务的权利义务用户是指注册登录使用本服务的个人本协议可由成都文交所随时更新更新后的协议条款一旦公布即代替原来的协议条款恕不另行通知用户可在本网站查阅最新版协议条款在成都文交所修改协议条款后如果用户不接受修改后的条款请立即停止使用成都文交所提供的服务用户继续使用成都文交所提供的服务将被视为接受修改后的协议</p> 在此特别提醒您用户在注册成为用户之前请认真阅读本用户协议以下简称协议确保您充分理解本协议中各条款请您审慎阅读并选择接受或不接受本协议除非您接受本协议所有条款否则您无权注册登录或使用本协议所涉服务您的注册登录使用等行为将视为对本协议的接受并同意接受本协议各项条款的约束
</p>
<p>
本协议约定成都文化产权交易所有限公司以下简称成都文交所与用户之间关于IP文产通平台服务以下简称服务的权利义务用户是指注册登录使用本服务的个人本协议可由成都文交所随时更新更新后的协议条款一旦公布即代替原来的协议条款恕不另行通知用户可在本网站查阅最新版协议条款在成都文交所修改协议条款后如果用户不接受修改后的条款请立即停止使用成都文交所提供的服务用户继续使用成都文交所提供的服务将被视为接受修改后的协议
</p>
<h3>服务内容</h3> <h3>服务内容</h3>
<p>1.1 本服务的具体内容由成都文交所根据实际情况提供包括但不限于授权用户通过其账号进行相关操作</p> <p>
<p>1.2 成都文交所提供的服务仅限于平台上的相关功能用户在使用服务时应遵守相关法律法规及本协议的规定</p> 1.1
本服务的具体内容由成都文交所根据实际情况提供包括但不限于授权用户通过其账号进行相关操作
</p>
<p>
1.2
成都文交所提供的服务仅限于平台上的相关功能用户在使用服务时应遵守相关法律法规及本协议的规定
</p>
<h3>用户账号</h3> <h3>用户账号</h3>
<p>2.1 用户在使用本服务前需要注册一个账号账号注册过程中用户应提供真实准确完整的个人资料</p> <p>
<p>2.2 用户有责任妥善保管注册账号信息及账号密码的安全因用户保管不善可能导致遭受盗号或密码失窃责任由用户自行承担</p> 2.1
用户在使用本服务前需要注册一个账号账号注册过程中用户应提供真实准确完整的个人资料
</p>
<p>
2.2
用户有责任妥善保管注册账号信息及账号密码的安全因用户保管不善可能导致遭受盗号或密码失窃责任由用户自行承担
</p>
<h3>用户个人信息保护</h3> <h3>用户个人信息保护</h3>
<p>3.1 保护用户个人信息是成都文交所的一项基本原则成都文交所将会采取合理的措施保护用户的个人信息除法律法规规定的情形外未经用户许可成都文交所不会向第三方公开透露用户个人信息</p> <p>
3.1
保护用户个人信息是成都文交所的一项基本原则成都文交所将会采取合理的措施保护用户的个人信息除法律法规规定的情形外未经用户许可成都文交所不会向第三方公开透露用户个人信息
</p>
<br/> <br />
<!-- <p style="color: #999; text-align: center; font-size: 12px;">(以上内容为示例请替换为完整版用户服务协议暂行)</p> --> <!-- <p style="color: #999; text-align: center; font-size: 12px;">(以上内容为示例请替换为完整版用户服务协议暂行)</p> -->
</div> </div>
</n-modal> </n-modal>
@ -133,7 +155,6 @@ function handleOpenAgreement() {
showAgreement.value = true showAgreement.value = true
} }
// Initialize login info // Initialize login info
if (localStorage.getItem('phone')) { if (localStorage.getItem('phone')) {
loginInfo.value.phone = localStorage.getItem('phone') loginInfo.value.phone = localStorage.getItem('phone')
@ -210,6 +231,7 @@ async function handleLogin() {
if (res.data?.token?.access_token) { if (res.data?.token?.access_token) {
setToken(res.data.token.access_token) setToken(res.data.token.access_token)
localStorage.setItem('phone', phone) localStorage.setItem('phone', phone)
localStorage.setItem('app_user_id', res.data.user.id)
if (query.redirect) { if (query.redirect) {
const path = query.redirect const path = query.redirect

View File

@ -43,66 +43,46 @@
> >
<n-grid :cols="2" :x-gap="16"> <n-grid :cols="2" :x-gap="16">
<!-- 公司名称 --> <!-- 公司名称 -->
<n-form-item-gi :span="1" path="companyName" label="公司名称"> <n-form-item-gi :span="1" path="company_name" label="公司名称">
<n-input <n-input v-model:value="formData.company_name" placeholder="请输入公司名称" clearable />
v-model:value="formData.companyName"
placeholder="请输入公司名称"
clearable
/>
</n-form-item-gi> </n-form-item-gi>
<!-- 公司税号 --> <!-- 公司税号 -->
<n-form-item-gi :span="1" path="taxNumber" label="公司税号"> <n-form-item-gi :span="1" path="tax_number" label="公司税号">
<n-input <n-input v-model:value="formData.tax_number" placeholder="请输入公司税号" clearable />
v-model:value="formData.taxNumber"
placeholder="请输入公司税号"
clearable
/>
</n-form-item-gi> </n-form-item-gi>
<!-- 注册地址 --> <!-- 注册地址 -->
<n-form-item-gi :span="2" path="registeredAddress" label="注册地址"> <n-form-item-gi :span="2" path="register_address" label="注册地址">
<n-input <n-input
v-model:value="formData.registeredAddress" v-model:value="formData.register_address"
placeholder="请输入注册地址" placeholder="请输入注册地址"
clearable clearable
/> />
</n-form-item-gi> </n-form-item-gi>
<!-- 注册电话 --> <!-- 注册电话 -->
<n-form-item-gi :span="2" path="registeredPhone" label="注册电话"> <n-form-item-gi :span="2" path="register_phone" label="注册电话">
<n-input <n-input
v-model:value="formData.registeredPhone" v-model:value="formData.register_phone"
placeholder="请输入注册电话" placeholder="请输入注册电话"
clearable clearable
/> />
</n-form-item-gi> </n-form-item-gi>
<!-- 开户银行 --> <!-- 开户银行 -->
<n-form-item-gi :span="1" path="bankName" label="开户银行"> <n-form-item-gi :span="1" path="bank_name" label="开户银行">
<n-input <n-input v-model:value="formData.bank_name" placeholder="请输入开户银行" clearable />
v-model:value="formData.bankName"
placeholder="请输入开户银行"
clearable
/>
</n-form-item-gi> </n-form-item-gi>
<!-- 银行账号 --> <!-- 银行账号 -->
<n-form-item-gi :span="1" path="bankAccount" label="银行账号"> <n-form-item-gi :span="1" path="bank_account" label="银行账号">
<n-input <n-input v-model:value="formData.bank_account" placeholder="请输入银行账号" clearable />
v-model:value="formData.bankAccount"
placeholder="请输入银行账号"
clearable
/>
</n-form-item-gi> </n-form-item-gi>
<!-- 电子邮箱 --> <!-- 电子邮箱 -->
<n-form-item-gi :span="2" path="email" label="电子邮箱"> <n-form-item-gi :span="2" path="email" label="电子邮箱">
<n-input <n-input v-model:value="formData.email" placeholder="请输入邮箱" clearable />
v-model:value="formData.email"
placeholder="请输入邮箱"
clearable
/>
<template #feedback> <template #feedback>
<span class="email-hint">此邮箱用于接收发票请填写正确</span> <span class="email-hint">此邮箱用于接收发票请填写正确</span>
</template> </template>
@ -122,13 +102,24 @@
<script setup> <script setup>
import { h, ref, watch } from 'vue' import { h, ref, watch } from 'vue'
import { NButton, NDataTable, NSpace, NModal, NForm, NFormItemGi, NGrid, NInput } from 'naive-ui' import {
NButton,
NDataTable,
NSpace,
NModal,
NForm,
NFormItemGi,
NGrid,
NInput,
NPopconfirm,
} from 'naive-ui'
import { renderIcon } from '@/utils'
const props = defineProps({ const props = defineProps({
invoiceList: { invoiceList: {
type: Array, type: Array,
default: () => [] default: () => [],
} },
}) })
const emit = defineEmits(['add-invoice', 'delete-invoice', 'update-invoice']) const emit = defineEmits(['add-invoice', 'delete-invoice', 'update-invoice'])
@ -139,31 +130,27 @@ const formRef = ref(null)
// //
const formData = ref({ const formData = ref({
companyName: '', company_name: '',
taxNumber: '', tax_number: '',
registeredAddress: '', register_address: '',
registeredPhone: '', register_phone: '',
bankName: '', bank_name: '',
bankAccount: '', bank_account: '',
email: '' email: '',
}) })
// //
const formRules = { const formRules = {
companyName: [ company_name: [{ required: true, message: '请输入公司名称', trigger: 'blur' }],
{ required: true, message: '请输入公司名称', trigger: 'blur' } tax_number: [{ required: true, message: '请输入公司税号', trigger: 'blur' }],
],
taxNumber: [
{ required: true, message: '请输入公司税号', trigger: 'blur' }
],
email: [ email: [
{ required: true, message: '请输入电子邮箱', trigger: 'blur' }, { required: true, message: '请输入电子邮箱', trigger: 'blur' },
{ {
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
message: '请输入正确的邮箱格式', message: '请输入正确的邮箱格式',
trigger: 'blur' trigger: 'blur',
} },
] ],
} }
// , // ,
@ -175,13 +162,13 @@ watch(showModal, (newVal) => {
} else { } else {
// , // ,
formData.value = { formData.value = {
companyName: '', company_name: '',
taxNumber: '', tax_number: '',
registeredAddress: '', register_address: '',
registeredPhone: '', register_phone: '',
bankName: '', bank_name: '',
bankAccount: '', bank_account: '',
email: '' email: '',
} }
} }
} }
@ -238,7 +225,7 @@ const columns = [
ellipsis: true, ellipsis: true,
align: 'center', align: 'center',
titleAlign: 'center', titleAlign: 'center',
render: (row) => row.name || row.companyName || '-' render: (row) => row.name || row.company_name || '-',
}, },
{ {
title: '税号', title: '税号',
@ -246,7 +233,7 @@ const columns = [
minWidth: 200, minWidth: 200,
align: 'center', align: 'center',
titleAlign: 'center', titleAlign: 'center',
render: (row) => row.taxId || row.taxNumber || '123456789012345678' render: (row) => row.taxId || row.tax_number || '123456789012345678',
}, },
{ {
title: '操作', title: '操作',
@ -266,27 +253,44 @@ const columns = [
text: true, text: true,
type: 'primary', type: 'primary',
size: 'small', size: 'small',
onClick: () => handleEditInvoice(row) onClick: () => handleEditInvoice(row),
}, },
{ default: () => '编辑' } {
default: () => '编辑',
icon: renderIcon('material-symbols:edit', { size: 16 }),
}
), ),
h( h(
NButton, NPopconfirm,
{ {
text: true, onPositiveClick: () => handleDeleteInvoice(row),
type: 'error', negativeText: '取消',
size: 'small', positiveText: '确定',
onClick: () => handleDeleteInvoice(row)
}, },
{ default: () => '删除' } {
) trigger: () =>
] h(
NButton,
{
text: true,
type: 'error',
size: 'small',
},
{
default: () => '删除',
icon: renderIcon('material-symbols:delete-outline', { size: 16 }),
}
),
default: () => '确定删除该发票抬头吗?',
}
),
],
} }
) ),
} },
] ]
const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? row.taxNumber const rowKey = (row) => row.id ?? row.name ?? row.company_name ?? row.taxId ?? row.tax_number
</script> </script>
<style scoped> <style scoped>
@ -313,7 +317,7 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
.title-bar { .title-bar {
width: 4px; width: 4px;
height: 16px; height: 16px;
background: #A30113; background: #a30113;
border-radius: 2px; border-radius: 2px;
} }
@ -328,7 +332,7 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
align-items: center; align-items: center;
gap: 4px; gap: 4px;
padding: 8px 16px; padding: 8px 16px;
background: #A30113; background: #a30113;
color: white; color: white;
border-radius: 4px; border-radius: 4px;
font-size: 14px; font-size: 14px;
@ -337,7 +341,7 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
} }
.add-btn:hover { .add-btn:hover {
background: #880C22; background: #880c22;
} }
.plus-icon { .plus-icon {
@ -375,7 +379,7 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
} }
:deep(.n-form-item-label__asterisk) { :deep(.n-form-item-label__asterisk) {
color: #A30113; color: #a30113;
} }
:deep(.n-input) { :deep(.n-input) {
@ -383,12 +387,12 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
} }
:deep(.n-input__input-el::placeholder) { :deep(.n-input__input-el::placeholder) {
color: #C0C4CC; color: #c0c4cc;
} }
.email-hint { .email-hint {
font-size: 12px; font-size: 12px;
color: #A30113; color: #a30113;
margin-top: 4px; margin-top: 4px;
display: inline-block; display: inline-block;
} }
@ -402,7 +406,7 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
.cancel-btn { .cancel-btn {
padding: 8px 24px; padding: 8px 24px;
border: 1px solid #DCDFE6; border: 1px solid #dcdfe6;
background: white; background: white;
color: #606266; color: #606266;
border-radius: 4px; border-radius: 4px;
@ -412,13 +416,13 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
} }
.cancel-btn:hover { .cancel-btn:hover {
border-color: #C0C4CC; border-color: #c0c4cc;
background: #F5F7FA; background: #f5f7fa;
} }
.save-btn { .save-btn {
padding: 8px 24px; padding: 8px 24px;
background: #A30113; background: #a30113;
color: white; color: white;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
@ -428,6 +432,6 @@ const rowKey = (row) => row.id ?? row.name ?? row.companyName ?? row.taxId ?? ro
} }
.save-btn:hover { .save-btn:hover {
background: #880C22; background: #880c22;
} }
</style> </style>

View File

@ -29,6 +29,9 @@
:asset-list="assetList" :asset-list="assetList"
:invoice-list="invoiceList" :invoice-list="invoiceList"
@return-home="handleBackToHome" @return-home="handleBackToHome"
@add-invoice="addInvoice"
@update-invoice="updateInvoice"
@delete-invoice="deleteInvoice"
/> />
</div> </div>
</div> </div>
@ -62,10 +65,7 @@ const valuationCount = ref(0)
const assetList = ref([]) const assetList = ref([])
// //
const invoiceList = ref([ const invoiceList = ref([])
{ id: 1, name: '某某公司', status: '待审' },
{ id: 2, name: '某某公司', status: '待审' },
])
// //
const menuList = ref([ const menuList = ref([
@ -116,9 +116,50 @@ async function loadData() {
$message.error('加载估值记录失败,请稍后重试') $message.error('加载估值记录失败,请稍后重试')
} }
} }
//
async function loadInvoiceList() {
try {
const res = await api.getInvoiceHeaders()
invoiceList.value = res.data
} catch (error) {
console.error('发票抬头获取失败:', error)
}
}
//
async function addInvoice(data) {
try {
await api.addInvoiceHeaders(data)
$message.success('添加成功')
loadInvoiceList()
} catch (error) {
console.error('新增发票抬头失败:', error)
}
}
//
async function updateInvoice(data) {
try {
await api.updateInvoiceHeaders(data)
$message.success('编辑成功')
loadInvoiceList()
} catch (error) {
console.error('更新发票抬头失败:', error)
}
}
//
async function deleteInvoice(data) {
try {
await api.deleteInvoiceHeaders(data.id)
$message.success('删除成功')
loadInvoiceList()
} catch (error) {
console.error('删除发票抬头失败:', error)
}
}
onMounted(() => { onMounted(() => {
loadData() loadData()
loadInvoiceList()
}) })
</script> </script>