Handy_Cao 2 лет назад
Родитель
Сommit
008c2174f8

+ 30 - 1
src/business/user/address.ts

@@ -1,11 +1,39 @@
 import { shallowRef, reactive, computed } from 'vue'
+import { useDataTable } from '@/hooks/datatable'
 import { useLoginStore } from '@/stores'
-import { userReceiveInfo, delUserReceiveInfo, userReceiveIsDefault } from '@/services/api/user'
+import { queryUserReceiveInfo, userReceiveInfo, delUserReceiveInfo, userReceiveIsDefault } from '@/services/api/user'
+import { getCertificateTypeList } from '@/constants/certificate'
 
 const loginStore = useLoginStore()
 
+export function useAddress() {
+    const { dataList, total, pageIndex, pageSize } = useDataTable<Model.UserReceiveInfoRsp>()
+    const loading = shallowRef(false)
+
+    const getUserAddressList = async () => {
+        try {
+            loading.value = true
+            const res = await queryUserReceiveInfo()
+            total.value = res.total
+            dataList.value = res.data
+        } finally {
+            loading.value = false
+        }
+    }
+
+    return {
+        loading,
+        dataList,
+        total,
+        pageIndex,
+        pageSize,
+        getUserAddressList,
+    }
+}
+
 export function useAddressForm(selectedRow?: Model.UserReceiveInfoRsp) {
     const loading = shallowRef(false)
+    const certificateTypeList = getCertificateTypeList()
 
     const formData = reactive<Proto.UserReceiveInfoReq>({
         ReceiveInfoId: 0,
@@ -82,6 +110,7 @@ export function useAddressForm(selectedRow?: Model.UserReceiveInfoRsp) {
 
     return {
         loading,
+        certificateTypeList,
         formData,
         regionName,
         addOrUpdate,

+ 27 - 1
src/business/user/invoice.ts

@@ -1,11 +1,37 @@
 import { shallowRef, reactive } from 'vue'
-import { userReceiptInfo, delUserReceiptInfo } from '@/services/api/user'
+import { userReceiptInfo, queryWrUserReceiptInfo, delUserReceiptInfo } from '@/services/api/user'
 import { useLoginStore } from '@/stores'
 import { getCertificateTypeList } from '@/constants/certificate'
+import { useDataTable } from '@/hooks/datatable'
 
 const loginStore = useLoginStore()
 const { userId } = loginStore.$toRefs()
 
+export function useInvoice() {
+    const { dataList, total, pageIndex, pageSize } = useDataTable<Model.WrUserReceiptInfoRsp>()
+    const loading = shallowRef(false)
+
+    const getUserInvoiceList = async () => {
+        try {
+            loading.value = true
+            const res = await queryWrUserReceiptInfo({})
+            total.value = res.total
+            dataList.value = res.data
+        } finally {
+            loading.value = false
+        }
+    }
+
+    return {
+        loading,
+        dataList,
+        total,
+        pageIndex,
+        pageSize,
+        getUserInvoiceList,
+    }
+}
+
 export function useInvoiceForm(selectedRow?: Model.WrUserReceiptInfoRsp) {
     const loading = shallowRef(false)
     const certificateTypeList = getCertificateTypeList()

+ 67 - 0
src/mock/router.ts

@@ -428,6 +428,73 @@ const appmenu = {
                         urlType: 1,
                         component: 'views/account/sign/index.vue',
                     },
+                    {
+                        authType: 1,
+                        sort: 2,
+                        title: '收获地址管理',
+                        code: 'account_address',
+                        url: 'address',
+                        urlType: 1,
+                        component: 'views/account/address/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '新增地址',
+                                code: 'account_address_add',
+                                component: 'views/account/address/components/edit/index.vue',
+                                className: 'el-button--primary',
+                            },
+                            {
+                                authType: 3,
+                                title: '修改',
+                                code: 'account_address_edit',
+                                component: 'views/account/address/components/edit/index.vue',
+                            },
+                            {
+                                authType: 3,
+                                title: '默认',
+                                code: 'account_address_default',
+                                component: 'views/account/address/components/default/index.vue',
+                            },
+                            {
+                                authType: 3,
+                                title: '删除',
+                                code: 'account_address_delete',
+                                component: 'views/account/address/components/delete/index.vue',
+                            },
+                        ]
+                    },
+                    {
+                        authType: 1,
+                        sort: 3,
+                        title: '发票信息管理',
+                        code: 'account_receipt',
+                        url: 'receipt',
+                        urlType: 1,
+                        component: 'views/account/receipt/index.vue',
+                        children: [
+                            {
+                                authType: 3,
+                                title: '新增发票',
+                                code: 'account_receipt_add',
+                                component: 'views/account/receipt/components/edit/index.vue',
+                                className: 'el-button--primary',
+
+                            },
+                            {
+                                authType: 3,
+                                title: '修改',
+                                code: 'account_receipt_edit',
+                                component: 'views/account/receipt/components/edit/index.vue',
+                            },
+                            {
+                                authType: 3,
+                                title: '删除',
+                                code: 'account_receipt_delete',
+                                component: 'views/account/receipt/components/delete/index.vue',
+                            }
+                        ]
+                    },
                 ]
             },
         ]

+ 97 - 0
src/packages/pc/components/base/region/index.ts

@@ -0,0 +1,97 @@
+import { shallowRef, computed, getCurrentInstance } from 'vue'
+import axios from 'axios'
+
+interface Region {
+    autoid: number;
+    divisioncode: string;
+    divisionlevel: string;
+    divisionname: string;
+    modifierid: number;
+    modifytime: string;
+    parentcode: string;
+    pathname: string;
+    postcode: string;
+    separablename: string;
+    shortcode: string;
+}
+
+export function useRegion(defaultValue: (number | undefined)[]) {
+    const instance = getCurrentInstance()
+
+    const region: { province: Region[]; city: Region[]; district: Region[]; } = {
+        province: [],
+        city: [],
+        district: []
+    }
+
+    const provinceList = shallowRef<Region[]>([])
+    const provinceId = shallowRef(defaultValue[0])
+    const cityId = shallowRef(defaultValue[1])
+    const districtId = shallowRef(defaultValue[2])
+
+    const cityList = computed(() => {
+        const province = provinceList.value.find((e) => e.autoid === provinceId.value)
+        if (province) {
+            return region.city.filter((e) => e.parentcode === province.divisioncode)
+        }
+        return []
+    })
+
+    const districtList = computed(() => {
+        const city = cityList.value.find((e) => e.autoid === cityId.value)
+        if (city) {
+            return region.district.filter((e) => e.parentcode === city.divisioncode)
+        }
+        return []
+    })
+
+    const regionChage = () => {
+        const value = [provinceId.value, cityId.value, districtId.value]
+        instance?.emit('update:province', value[0])
+        instance?.emit('update:city', value[1])
+        instance?.emit('update:district', value[2])
+        instance?.emit('change', value)
+    }
+
+    const provinceChange = () => {
+        cityId.value = undefined
+        districtId.value = undefined
+        regionChage()
+    }
+
+    const cityChange = () => {
+        districtId.value = undefined
+        regionChage()
+    }
+
+    const districtChange = () => {
+        regionChage()
+    }
+
+    axios('./config/address.json').then((res) => {
+        res.data.forEach((e: Region) => {
+            if (e.divisionlevel === 'province') {
+                region.province.push(e)
+            }
+            if (e.divisionlevel === 'city') {
+                region.city.push(e)
+            }
+            if (e.divisionlevel === 'district') {
+                region.district.push(e)
+            }
+        })
+        provinceList.value = region.province
+    })
+
+    return {
+        provinceList,
+        cityList,
+        districtList,
+        provinceId,
+        cityId,
+        districtId,
+        provinceChange,
+        cityChange,
+        districtChange,
+    }
+}

+ 27 - 0
src/packages/pc/components/base/region/index.vue

@@ -0,0 +1,27 @@
+<template>
+    <div class="app-region">
+        <el-select v-model="provinceId" @change="provinceChange">
+            <el-option :label="item.divisionname" :value="item.autoid" v-for="(item, index) in provinceList"
+                :key="index" />
+        </el-select>
+        <el-select v-model="cityId" @change="cityChange">
+            <el-option :label="item.divisionname" :value="item.autoid" v-for="(item, index) in cityList" :key="index" />
+        </el-select>
+        <el-select v-model="districtId" @change="districtChange">
+            <el-option :label="item.divisionname" :value="item.autoid" v-for="(item, index) in districtList"
+                :key="index" />
+        </el-select>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { useRegion } from './index'
+
+const props = defineProps({
+    province: Number,
+    city: Number,
+    district: Number
+})
+
+const { provinceList, cityList, districtList, provinceId, cityId, districtId, provinceChange, cityChange, districtChange } = useRegion([props.province, props.city, props.district])
+</script>

+ 42 - 0
src/packages/pc/views/account/address/components/default/index.vue

@@ -0,0 +1,42 @@
+<!-- 账户管理-收货地址管理-设为默认 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div style="font-size:16px;text-align:center">该地址是否设为默认?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useAddressForm } from '@/business/user/address'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.UserReceiveInfoRsp>,
+        default: () => ({})
+    }
+})
+
+const { loading, updateAddressIsDefault } = useAddressForm(props.selectedRow)
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    updateAddressIsDefault().then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+    })
+}
+</script>

+ 42 - 0
src/packages/pc/views/account/address/components/delete/index.vue

@@ -0,0 +1,42 @@
+<!-- 账户管理-收货地址管理-删除 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div style="font-size:16px;text-align:center">是否删除该地址?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useAddressForm } from '@/business/user/address'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.UserReceiveInfoRsp>,
+        default: () => ({})
+    }
+})
+
+const { loading, deleteAddress } = useAddressForm(props.selectedRow)
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    deleteAddress().then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+    })
+}
+</script>

+ 94 - 0
src/packages/pc/views/account/address/components/edit/index.vue

@@ -0,0 +1,94 @@
+<!-- 账户管理-收货地址管理-编辑 -->
+<template>
+    <app-drawer :title="selectedRow?.autoid ? '修改地址' : '新增地址'" :width="880" v-model:show="show" :loading="loading"
+        :refresh="refresh">
+        <el-form ref="formRef" class="el-form--horizontal" label-width="100px" :model="formData" :rules="formRules">
+            <el-form-item label="收货人" prop="ReceiverName">
+                <el-input placeholder="请输入" v-model="formData.ReceiverName" />
+            </el-form-item>
+            <el-form-item label="证件类型" prop="CardTypeID">
+                <el-select v-model="formData.CardTypeID">
+                    <el-option :label="item.label" :value="item.value" v-for="(item, index) in certificateTypeList"
+                        :key="index" />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="联系电话" prop="PhoneNum">
+                <el-input placeholder="请输入" v-model="formData.PhoneNum" />
+            </el-form-item>
+            <el-form-item label="证件号码" prop="CardNum">
+                <el-input placeholder="请输入" v-model="formData.CardNum" />
+            </el-form-item>
+            <el-form-item class="el-form-item--row" label="收货地址" prop="area">
+                <app-region class="el-form-item--col" v-model:province="formData.ProvinceID"
+                    v-model:city="formData.CityID" v-model:district="formData.DistrictID" />
+            </el-form-item>
+            <el-form-item class="el-form-item--row" prop="Address">
+                <el-input placeholder="请输入" v-model="formData.Address" />
+            </el-form-item>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import type { FormInstance, FormRules } from 'element-plus'
+import { useAddressForm } from '@/business/user/address'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+import AppRegion from '@pc/components/base/region/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.UserReceiveInfoRsp>,
+        default: () => ({})
+    }
+})
+
+const { loading, formData, certificateTypeList, addOrUpdate } = useAddressForm(props.selectedRow)
+const show = ref(true)
+const refresh = ref(false)
+const formRef = ref<FormInstance>()
+
+const formRules: FormRules = {
+    ReceiverName: [{ required: true, message: '请输入收货人', trigger: 'blur' }],
+    CardTypeID: [{ required: true, message: '请选择证件类型' }],
+    PhoneNum: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
+    CardNum: [{ required: true, message: '请输入证件号码', trigger: 'blur' }],
+    Address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+    area: [
+        {
+            required: true,
+            validator: (rule, value, callback) => {
+                const ids = [10, 18, 34] // 香港、台湾、澳门没有市区选择
+                if ((formData.ProvinceID && formData.CityID && formData.DistrictID) || ids.includes(formData.ProvinceID ?? 0)) {
+                    callback()
+                } else {
+                    callback(new Error('请选择收货地区'))
+                }
+            }
+        }
+    ],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            addOrUpdate().then(() => {
+                ElMessage.success('提交成功')
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error('提交失败:' + err)
+            })
+        }
+    })
+}
+</script>

+ 78 - 0
src/packages/pc/views/account/address/index.vue

@@ -0,0 +1,78 @@
+<!-- 账户管理-收货地址管理 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey" :expand-row-keys="expandKeys"  @row-click="rowClick">
+        <template #header>
+            <div class="buttonbar">
+                <el-button type="danger" size="small" @click="showComponent('edit')">新增收货地址</el-button>
+            </div>
+        </template>
+        <!-- 证件类型 -->
+        <template #cardtypeid="{ value }">
+            {{ getCertificateTypeName(value) }}
+        </template>
+        <!-- 收货地址 -->
+        <template #address="{ row }">
+            {{ [row.provincename, row.cityname, row.districtname, row.address].join(' ') }}
+        </template>
+        <!-- 是否默认 -->
+        <template #isdefault="{ value }">
+            {{ value? '是': '否' }}
+        </template>
+        <!-- 操作 -->
+        <template #expand="{ row }">
+            <div class="buttonbar">
+                <el-button type="primary" size="small" @click="showComponent('edit', row)">编辑</el-button>
+                <el-button type="success" size="small" @click="showComponent('default', row)">设置默认</el-button>
+                <el-button type="danger" size="small" @click="showComponent('delete', row)">删除</el-button>
+            </div>
+        </template>
+    </app-table>
+    <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)" @closed="closeComponent"
+            v-if="componentId" />
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useAddress } from '@/business/user/address'
+import { getCertificateTypeName } from '@/constants/certificate'
+import { useComponent } from '@/hooks/component'
+import { useComposeTable } from '@pc/components/base/table'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const componentMap = new Map<string, unknown>([
+    ['edit', defineAsyncComponent(() => import('./components/edit/index.vue'))],
+    ['default', defineAsyncComponent(() => import('./components/default/index.vue'))],
+    ['delete', defineAsyncComponent(() => import('./components/delete/index.vue'))],
+])
+
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.UserReceiveInfoRsp>({ rowKey: 'autoid' })
+const selectedRow = shallowRef<Model.UserReceiveInfoRsp>()
+
+defineProps({
+    code: String
+})
+
+const { loading, dataList, getUserAddressList } = useAddress()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    getUserAddressList()
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { prop: 'receivername', label: '收货人' },
+    { prop: 'cardtypeid', label: '证件类型' },
+    { prop: 'cardnum', label: '证件号码' },
+    { prop: 'phonenum', label: '联系电话' },
+    { prop: 'address', label: '收货地址' },
+    { prop: 'isdefault', label: '是否默认' },
+])
+
+getUserAddressList().catch((err) => ElMessage.error(err))
+
+const showComponent = (componentName: string, row?: Model.UserReceiveInfoRsp) => {
+    selectedRow.value = row
+    openComponent(componentName)
+}
+
+</script>

+ 42 - 0
src/packages/pc/views/account/receipt/components/delete/index.vue

@@ -0,0 +1,42 @@
+<!-- 账户管理-发票信息管理-删除 -->
+<template>
+    <app-drawer title="提示" v-model:show="show" :loading="loading" :refresh="refresh">
+        <div style="font-size:16px;text-align:center">是否删除该发票?</div>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">确认</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useInvoiceForm } from '@/business/user/invoice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.WrUserReceiptInfoRsp>,
+        default: () => ({})
+    }
+})
+
+const { loading, deleteInvoice } = useInvoiceForm(props.selectedRow)
+const show = shallowRef(true)
+const refresh = shallowRef(false)
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    deleteInvoice().then(() => {
+        ElMessage.success('提交成功')
+        onCancel(true)
+    }).catch((err) => {
+        ElMessage.error('提交失败:' + err)
+    })
+}
+</script>

+ 86 - 0
src/packages/pc/views/account/receipt/components/edit/index.vue

@@ -0,0 +1,86 @@
+<!-- 账户管理-发票信息管理-编辑 -->
+<template>
+    <app-drawer :title="selectedRow?.autoid ? '修改发票' : '新增发票'" :width="460" v-model:show="show" :loading="loading"
+        :refresh="refresh">
+        <el-form ref="formRef" label-width="100px" :model="formData" :rules="formRules">
+            <el-form-item label="发票类型" prop="ReceiptType">
+                <el-radio-group v-model="formData.ReceiptType">
+                    <el-radio :label="1">个人</el-radio>
+                    <el-radio :label="2">企业</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="发票抬头" prop="UserName">
+                <el-input placeholder="请输入" v-model="formData.UserName" />
+            </el-form-item>
+            <template v-if="formData.ReceiptType === 2">
+                <el-form-item label="税号" prop="TaxpayerID">
+                    <el-input placeholder="请输入" v-model="formData.TaxpayerID" />
+                </el-form-item>
+                <el-form-item label="开户银行" prop="ReceiptBank">
+                    <el-input placeholder="请输入" v-model="formData.ReceiptBank" />
+                </el-form-item>
+                <el-form-item label="银行账号" prop="ReceiptAccount">
+                    <el-input placeholder="请输入" v-model="formData.ReceiptAccount" />
+                </el-form-item>
+                <el-form-item label="企业地址" prop="Address">
+                    <el-input placeholder="请输入" v-model="formData.Address" />
+                </el-form-item>
+                <el-form-item label="企业电话" prop="ContactInfo">
+                    <el-input placeholder="请输入" v-model="formData.ContactInfo" />
+                </el-form-item>
+            </template>
+        </el-form>
+        <template #footer>
+            <el-button @click="onCancel(false)" plain>取消</el-button>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+        </template>
+    </app-drawer>
+</template>
+
+<script lang="ts" setup>
+import { ref, PropType } from 'vue'
+import { ElMessage } from 'element-plus'
+import type { FormInstance, FormRules } from 'element-plus'
+import { useInvoiceForm } from '@/business/user/invoice'
+import AppDrawer from '@pc/components/base/drawer/index.vue'
+
+const props = defineProps({
+    selectedRow: {
+        type: Object as PropType<Model.WrUserReceiptInfoRsp>,
+        default: () => ({})
+    }
+})
+
+const { loading, formData, addOrUpdate } = useInvoiceForm(props.selectedRow)
+const show = ref(true)
+const refresh = ref(false)
+const formRef = ref<FormInstance>()
+
+const formRules: FormRules = {
+    ReceiptType: [{ required: true, message: '请选择发票类型' }],
+    UserName: [{ required: true, message: '请输入发票抬头', trigger: 'blur' }],
+    TaxpayerID: [{ required: true, message: '请输入税号', trigger: 'blur' }],
+    ReceiptBank: [{ required: true, message: '请输入开户银行', trigger: 'blur' }],
+    ReceiptAccount: [{ required: true, message: '请输入银行账号', trigger: 'blur' }],
+    Address: [{ required: true, message: '请输入企业地址', trigger: 'blur' }],
+    ContactInfo: [{ required: true, message: '请输入企业电话', trigger: 'blur' }],
+}
+
+const onCancel = (isRefresh = false) => {
+    show.value = false
+    refresh.value = isRefresh
+}
+
+const onSubmit = () => {
+    formRef.value?.validate((valid) => {
+        if (valid) {
+            addOrUpdate().then(() => {
+                ElMessage.success('提交成功')
+                onCancel(true)
+            }).catch((err) => {
+                ElMessage.error('提交失败:' + err)
+            })
+        }
+    })
+}
+</script>

+ 64 - 0
src/packages/pc/views/account/receipt/index.vue

@@ -0,0 +1,64 @@
+<!-- 账户管理-发票信息管理 -->
+<template>
+    <app-table :data="dataList" v-model:columns="tableColumns" :loading="loading" :row-key="rowKey" :expand-row-keys="expandKeys"  @row-click="rowClick">
+        <template #header>
+            <el-button type="danger" size="small" @click="showComponent('edit')">新增收货地址</el-button>
+        </template>
+        <!-- 发票类型 -->
+        <template #receipttype="{ value }">
+            {{ getReceiptTypeName(value) }}
+        </template>
+        <!-- 操作 -->
+        <template #expand="{ row }">
+            <div class="buttonbar">
+                <el-button type="primary" size="small" @click="showComponent('edit', row)">编辑</el-button>
+                <el-button type="danger" size="small" @click="showComponent('delete', row)">删除</el-button>
+            </div>
+        </template>
+    </app-table>
+    <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)" @closed="closeComponent"
+        v-if="componentId" />
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { ElMessage } from 'element-plus'
+import { useInvoice } from '@/business/user/invoice'
+import { getReceiptTypeName } from '@/constants/receipt'
+import { useComponent } from '@/hooks/component'
+import { useComposeTable } from '@pc/components/base/table'
+import AppTable from '@pc/components/base/table/index.vue'
+
+const componentMap = new Map<string, unknown>([
+    ['edit', defineAsyncComponent(() => import('./components/edit/index.vue'))],
+    ['delete', defineAsyncComponent(() => import('./components/delete/index.vue'))],
+])
+
+const { rowKey, expandKeys, rowClick } = useComposeTable<Model.WrUserReceiptInfoRsp>({ rowKey: 'autoid' })
+const selectedRow = shallowRef<Model.WrUserReceiptInfoRsp>()
+
+defineProps({
+    code: String
+})
+
+const { loading, dataList, getUserInvoiceList } = useInvoice()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent(() => {
+    getUserInvoiceList()
+})
+
+const tableColumns = shallowRef<Model.TableColumn[]>([
+    { prop: 'receipttype', label: '发票类型' },
+    { prop: 'username', label: '发票抬头' },
+    { prop: 'taxpayerid', label: '税号' },
+    { prop: 'contactinfo', label: '企业电话' },
+    { prop: 'information', label: '企业信息' },
+])
+
+getUserInvoiceList().catch((err) => ElMessage.error(err))
+
+const showComponent = (componentName: string, row?: Model.WrUserReceiptInfoRsp) => {
+    selectedRow.value = row
+    openComponent(componentName)
+}
+</script>