| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | :title="dialogTitle" |
| | | :before-close="handleClose" |
| | | destroy-on-close |
| | | class="product-price-dialog" |
| | | :width="dialogWidth" |
| | | > |
| | | <div> |
| | | <div class="price-viewer-container" v-loading="loading"> |
| | | <!-- 价格对比表格 --> |
| | | <div class="pricing-table-container" v-if="showPricePanel && priceList.length > 0"> |
| | |
| | | > |
| | | <div class="pricing-table-wrapper"> |
| | | <table class="pricing-table"> |
| | | <thead> |
| | | <thead> |
| | | <tr> |
| | | <th class="feature-column">功能对比</th> |
| | | <th |
| | |
| | | <span class="label">产品名称:</span><span class="value strong">{{ productHeader.name }}</span> |
| | | </div> |
| | | <div class="grid-item"> |
| | | <span class="label">行业板块:</span><span class="value">{{ productHeader.industry }}</span> |
| | | <span class="label">行业板块:</span><span class="value">{{ productHeader.industrialChainName }}</span> |
| | | </div> |
| | | <div class="grid-item"> |
| | | <span class="label">提供者:</span><span class="value">{{ productHeader.provider }}</span> |
| | | <span class="label">提供者:</span><span class="value">{{ productHeader.submissionUnit }}</span> |
| | | </div> |
| | | <div class="grid-item"> |
| | | <span class="label">用户姓名:</span><span class="value">{{ userInfo.name }}</span> |
| | | </div> |
| | | <div class="grid-item"> |
| | | <span class="label">单位:</span><span class="value">{{ userInfo.unit }}</span> |
| | | <span class="label">单位:</span><span class="value">{{ userInfo.unitName }}</span> |
| | | </div> |
| | | <div class="grid-item"> |
| | | <span class="label">部门:</span><span class="value">{{ userInfo.department }}</span> |
| | | <span class="label">部门:</span><span class="value">{{ userInfo.departmentName }}</span> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | |
| | | </div> |
| | | </td> |
| | | <td class="th-center"> |
| | | <el-input-number v-model="suite.quantity" :min="1" :max="999" :controls="false" size="small" /> |
| | | <el-input-number |
| | | v-model="suite.quantity" |
| | | :min="1" |
| | | :max="999" |
| | | :controls="true" |
| | | size="large" |
| | | @change="(value) => handleQuantityChange(suite.id, value?value:1)" |
| | | /> |
| | | </td> |
| | | <td class="th-center"> |
| | | <el-input-number v-model="suite.duration" :min="1" :max="10" :controls="false" size="small" /> |
| | | <el-input-number |
| | | v-model="suite.duration" |
| | | :min="1" |
| | | :max="100" |
| | | :controls="true" |
| | | size="large" |
| | | :disabled="suite.priceType === 'FREE'" |
| | | @change="(value) => handleDurationChange(suite.id, value?value:1)" |
| | | /> |
| | | </td> |
| | | <td class="th-center"> |
| | | <el-button type="danger" link @click="removeSuite(idx)">删除</el-button> |
| | |
| | | <el-empty description="暂无价格信息" /> |
| | | </div> |
| | | </div> |
| | | |
| | | <template #footer v-if="!showOrderStatus"> |
| | | <span class="dialog-footer"> |
| | | <template v-if="showPricePanel"> |
| | | <el-button @click="handleClose">关闭</el-button> |
| | | <el-button type="primary" @click="handleOrder">立即订购</el-button> |
| | | </template> |
| | | <template v-else> |
| | | <el-button @click="showOrderPanel = false">返回价格对比</el-button> |
| | | <el-button type="primary" @click="submitOrder">提交申请</el-button> |
| | | </template> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <div class="footer" v-if="showPricePanel"> |
| | | <el-button type="primary" @click="handleOrder">立即订购</el-button> |
| | | </div> |
| | | <div class="footer" v-else> |
| | | <el-button @click="returnPricePanel">返回价格对比</el-button> |
| | | <el-button type="primary" @click="submitOrder">提交申请</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 产品订购对话框移除,改为内嵌展示 --> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, watch, computed } from 'vue' |
| | | import { ref, watch, computed, onMounted } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import { useRoute } from 'vue-router' |
| | | import productPricingApi from '@/api/productPricingApi' |
| | | import cartApi from '@/api/cartApi' |
| | | import orderApi from '@/api/orderApi' |
| | | import { ShoppingCart, Coin, Money } from '@element-plus/icons-vue' |
| | | import { useUserInfo } from '@/stores/modules/userInfo' |
| | | import { queryUserDetail } from '@/api/userInfo' |
| | | import productApi from '@/api/productApi' |
| | | import workFlowApi from '@/api/workFlowApi' |
| | | |
| | | const route = useRoute() |
| | | |
| | |
| | | enableStatus: 'ENABLED' | 'DISABLED' |
| | | } |
| | | |
| | | interface Props { |
| | | modelValue: boolean |
| | | productId?: string |
| | | width?: string |
| | | } |
| | | |
| | | interface Emits { |
| | | (e: 'update:modelValue', value: boolean): void |
| | | (e: 'order', selectedItems: PriceItem[]): void |
| | | } |
| | | |
| | | // 兼容 path 参数 productId 与 query 参数 id/productId |
| | | const currentProductId = computed<string | undefined>(() => { |
| | | return (route.params.productId as string) || (route.query.productId as string) || (route.query.id as string) |
| | | }) |
| | | |
| | | |
| | | const props = withDefaults(defineProps<Props>(), { |
| | | modelValue: false, |
| | | productId: '', |
| | | width: '90%' |
| | | }) |
| | | |
| | | |
| | | const emit = defineEmits<Emits>() |
| | | |
| | | const visible = computed({ |
| | | get: () => props.modelValue, |
| | | set: (value) => emit('update:modelValue', value) |
| | | }) |
| | | |
| | | const loading = ref(false) |
| | | const activeTab = ref('enterprise') |
| | |
| | | const showOrderPanel = ref(false) |
| | | const showPricePanel = ref(true) |
| | | const showOrderStatus = ref(false) |
| | | // 模拟用户信息(实际应从用户状态获取) |
| | | const userStore = useUserInfo() |
| | | let currentUserId = computed(() => userStore.getUserId || userStore.getUserInfo?.userId) |
| | | const currentUnitId = computed(() => userStore.getUnitId || userStore.getUserInfo?.unitId || '') |
| | | |
| | | onMounted(async () => { |
| | | if (!currentUserId.value) { |
| | | try { |
| | | const res: any = await queryUserDetail() |
| | | if (res?.code === 200 && res.data) { |
| | | userStore.updateUserDetail(res.data) |
| | | currentUserId = res.data.userId || res.data.id |
| | | userInfo.value = res.data |
| | | } else { |
| | | ElMessage.error(res?.msg || '无法获取用户信息,请先登录') |
| | | return |
| | | } |
| | | } catch (e) { |
| | | console.error('获取用户详情失败:', e) |
| | | ElMessage.error('获取用户信息失败,请稍后重试') |
| | | return |
| | | } |
| | | }else{ |
| | | userInfo.value = userStore.getUserInfos |
| | | } |
| | | |
| | | }) |
| | | type PriceTypeKey = 'POINTS' | 'CURRENCY' | 'AGREEMENT' | 'FREE' |
| | | interface OrderSuite extends PriceItem { |
| | | selected: boolean |
| | |
| | | priceType?: PriceTypeKey |
| | | } |
| | | const orderSuites = ref<OrderSuite[]>([]) |
| | | |
| | | // 购物车相关状态 |
| | | const cartItems = ref<any[]>([]) |
| | | const cartLoading = ref(false) |
| | | const idempotencyToken = ref<string>('') |
| | | |
| | | // 订单状态相关 |
| | | type OrderStatus = 'SUBMITTED' | 'AUTHORIZED' | 'CONFIRMED' | 'EVALUATED' |
| | |
| | | |
| | | // 产品信息/用户信息(静态) |
| | | const productHeader = ref({ |
| | | name: '中交方远智能实测实量管理系统', |
| | | industry: '公路,市政,建筑', |
| | | provider: '中交建筑集团第一工程有限公司' |
| | | name: '', |
| | | industrialChainName: '', |
| | | submissionUnit: '', |
| | | createUserId: '' |
| | | }) |
| | | const userInfo = ref({ |
| | | name: '张静', |
| | | unit: '信科集团', |
| | | department: '门户系统临时组' |
| | | name: '', |
| | | departmentName: '', |
| | | unitName: '' |
| | | }) |
| | | |
| | | // 全选 |
| | |
| | | const map: Record<string, string> = { SET: '/套', SET_PER_YEAR: '/套/年', YEAR: '/年' } |
| | | return map[unit || ''] || '' |
| | | } |
| | | const removeSuite = (index: number) => { orderSuites.value.splice(index, 1) } |
| | | const removeSuite = async (index: number) => { |
| | | const suite = orderSuites.value[index] |
| | | if (!suite) return |
| | | try { |
| | | await removeFromCart(String(suite.id)) |
| | | orderSuites.value.splice(index, 1) |
| | | } catch (e) { |
| | | } |
| | | } |
| | | |
| | | // 订购成功回调 |
| | | const handleOrderSuccess = (orderData: any) => { |
| | | console.log('订购成功:', orderData) |
| | | ElMessage.success('订购申请提交成功!') |
| | | // 清空选择状态 |
| | | selectedSuiteIds.value.clear() |
| | | } |
| | | |
| | | // 弹窗标题 |
| | | const dialogTitle = computed(() => { |
| | | return `【${productName.value}】产品定价` |
| | | }) |
| | | |
| | | // 弹窗宽度 |
| | | const dialogWidth = computed(() => { |
| | | return props.width |
| | | }) |
| | | |
| | | // 按客户对象分组的价格数据 |
| | | const groupedPriceData = computed(() => { |
| | |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | //获取产品详情信息 |
| | | try { |
| | | // productDetail.value = mockProductMap[productId] || null |
| | | const data = { |
| | | id: productId |
| | | } |
| | | const detailRes: any = await productApi.getProductById(data) |
| | | if (detailRes?.code === 200) { |
| | | productHeader.value = detailRes.data || { name: '', industrialChainName: '', submissionUnit: '', createUserId: '' } |
| | | } else { |
| | | productHeader.value = { name: '', industrialChainName: '', submissionUnit: '', createUserId: '' } |
| | | ElMessage.error(detailRes?.msg || '获取产品详情失败') |
| | | } |
| | | } catch (e) { |
| | | productHeader.value = { name: '', industrialChainName: '', submissionUnit: '', createUserId: '' } |
| | | ElMessage.error('获取产品详情失败') |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // 监听产品ID变化 |
| | | watch(() => props.productId, (newProductId) => { |
| | | if (newProductId && visible.value) { |
| | | watch(currentProductId, (newProductId) => { |
| | | if (newProductId) { |
| | | fetchProductData(newProductId) |
| | | } |
| | | }) |
| | | |
| | | // 监听弹窗显示状态 |
| | | watch(() => visible.value, (newVisible) => { |
| | | if (newVisible && props.productId) { |
| | | fetchProductData(props.productId) |
| | | } |
| | | }) |
| | | |
| | | // 关闭弹窗 |
| | | const handleClose = () => { |
| | | visible.value = false |
| | | showOrderPanel.value = false |
| | | showOrderStatus.value = false |
| | | showPricePanel.value = true |
| | | orderSuites.value = [] |
| | | selectedSuiteIds.value.clear() |
| | | } |
| | | },{ immediate: true }) |
| | | |
| | | // 套件选择处理 |
| | | const handleSuiteSelect = (suiteId: number, checked: any) => { |
| | | const isChecked = Boolean(checked) |
| | | if (isChecked) { |
| | | selectedSuiteIds.value.add(suiteId) |
| | | // 添加到购物车 |
| | | const priceItem = priceList.value.find(item => item.id === suiteId) |
| | | if (priceItem) { |
| | | addToCart(priceItem) |
| | | } |
| | | } else { |
| | | selectedSuiteIds.value.delete(suiteId) |
| | | // 从购物车移除 |
| | | removeFromCart(String(suiteId)) |
| | | } |
| | | } |
| | | |
| | | // 立即订购 |
| | | const handleOrder = () => { |
| | | if (selectedSuiteIds.value.size === 0) { |
| | | ElMessage.warning('请选择要订购的软件套件') |
| | | return |
| | | } |
| | | const selectedItems = priceList.value.filter(item => selectedSuiteIds.value.has(item.id)) |
| | | // 构建内嵌订购列表 |
| | | orderSuites.value = selectedItems.map(it => ({ |
| | | ...it, |
| | | selected: true, |
| | | quantity: 1, |
| | | duration: 1, |
| | | priceType: getDefaultPriceType(it as any) |
| | | })) as any |
| | | // 查询购物车信息进行展示 |
| | | fetchCartItems() |
| | | // 获取一次性防重复提交token |
| | | orderApi.getIdempotencyToken(currentUserId.value).then((res: any) => { |
| | | if (res?.code === 200) { |
| | | idempotencyToken.value = res.data as string |
| | | } |
| | | }).catch(() => {}) |
| | | showOrderPanel.value = true |
| | | showPricePanel.value = false |
| | | } |
| | |
| | | // 启用/停用按钮 |
| | | function handleToggleEnableStatus(row: any) { |
| | | // ... existing code ... |
| | | } |
| | | |
| | | function returnPricePanel() { |
| | | showOrderPanel.value = false |
| | | showOrderStatus.value = false |
| | | showPricePanel.value = true |
| | | } |
| | | |
| | | async function submitOrder() { |
| | |
| | | return |
| | | } |
| | | |
| | | // 这里可对接实际下单接口;先做前端提示 |
| | | // emit('order', items as any) |
| | | |
| | | // 模拟订单状态数据 |
| | | orderStatus.value = { |
| | | id: '4348442557619205545', |
| | | productName: productHeader.value.name, |
| | | provider: productHeader.value.provider, |
| | | status: 'SUBMITTED', |
| | | submitTime: new Date().toLocaleString(), |
| | | applyTime: new Date().toLocaleString() |
| | | if (!idempotencyToken.value) { |
| | | ElMessage.error('下单Token获取失败,请返回重试') |
| | | return |
| | | } |
| | | |
| | | // 显示订单状态面板 |
| | | showOrderPanel.value = false |
| | | showPricePanel.value = false |
| | | showOrderStatus.value = true |
| | | const hasPoints = items.some(item => item.priceType === 'POINTS') |
| | | const hasAGREEMENT = items.some(item => item.priceType === 'AGREEMENT') |
| | | let paymentType = '' |
| | | if(hasPoints){ |
| | | paymentType = '积分' |
| | | }else{ |
| | | paymentType = '协议' |
| | | } |
| | | // 组装创建订单参数(CreateOrderDTO) |
| | | const payload = { |
| | | userId: currentUserId.value, |
| | | unitId: currentUnitId.value, |
| | | productName: productHeader.value.name, |
| | | providerName: productHeader.value.submissionUnit, |
| | | providerId: productHeader.value.createUserId, |
| | | paymentType: paymentType, |
| | | buyerRemarks: '', |
| | | items: items.map(it => ({ |
| | | pricingId: it.id, |
| | | productId: it.productId, |
| | | suiteName: getProductSuiteText(it.productSuite), |
| | | salesForm: getSalesFormText(it.salesForm), |
| | | customerType: getCustomerObjectText(it.customerObject), |
| | | accountLimit: it.accountQuantityUnlimited ? '不限' : String(it.accountQuantity), |
| | | concurrentNodes: it.concurrentNodeQuantityUnlimited ? '不限' : String(it.concurrentNodeQuantity), |
| | | priceType: (it.priceType === 'POINTS' ? '积分' : it.priceType === 'CURRENCY' ? '货币' : it.priceType === 'AGREEMENT' ? '协议' : '免费'), |
| | | priceUnit: getPriceUnitText(it.priceUnit), |
| | | unitPrice: (it.priceType === 'POINTS' ? it.pointsAmount : it.currencyAmount) || 0, |
| | | quantity: it.quantity, |
| | | duration: it.duration, |
| | | totalPrice: undefined, |
| | | providerId: productHeader.value.createUserId, |
| | | providerName: productHeader.value.submissionUnit, |
| | | remarks: '' |
| | | })) |
| | | } |
| | | |
| | | try { |
| | | const res: any = await orderApi.createOrder(payload, idempotencyToken.value) |
| | | if (res?.code === 200) { |
| | | ElMessage.success('订单创建成功') |
| | | const data = res.data || {} |
| | | orderStatus.value = { |
| | | id: data.orderId || '—', |
| | | productName: data.productName || productHeader.value.name, |
| | | provider: data.providerName || productHeader.value.submissionUnit, |
| | | status: 'SUBMITTED', |
| | | submitTime: data.applyTime ? String(data.applyTime) : new Date().toLocaleString(), |
| | | applyTime: data.applyTime ? String(data.applyTime) : new Date().toLocaleString() |
| | | } |
| | | // 调用工作流接口发起审批流程,拿到流程实例ID后回写订单workflow_id |
| | | try { |
| | | // 根据是否包含协议明细,配置不同流程定义与业务Key(先用静态值占位) |
| | | // const processdefId = hasAGREEMENT ? 'Process_Agreement_Static' : 'Process_Points_Static' |
| | | const businessKey = hasAGREEMENT ? 'agreement_biz_key' : 'points_biz_key' |
| | | const type = hasAGREEMENT ? 'trade_agreement' : 'trade_point'; |
| | | // 获取工作流参数 |
| | | const wkParamsRes: any = await workFlowApi.getWorkFlowParams({ |
| | | type: type, |
| | | unitId: '1' |
| | | }) |
| | | if(wkParamsRes?.code === 200 && wkParamsRes.data?.processTemplateId){ |
| | | const wfRes: any = await orderApi.startWorkflowAndComplete({ |
| | | processdefId: wkParamsRes.data.processTemplateId, |
| | | userid: String(currentUserId.value || ''), |
| | | businessKey: businessKey |
| | | }) |
| | | if (wfRes?.code === 200 && wfRes.data?.processinstId) { |
| | | await orderApi.updateWorkflowId(data.orderId, wfRes.data.processinstId) |
| | | } |
| | | } |
| | | |
| | | } catch (e) { |
| | | console.warn('启动工作流失败或更新workflow_id失败', e) |
| | | } |
| | | |
| | | // 清空购物车(后端 + 本地状态) |
| | | try { |
| | | const clearRes: any = await cartApi.clearCart(currentUserId.value, currentUnitId.value) |
| | | if (clearRes?.code === 200) { |
| | | cartItems.value = [] |
| | | orderSuites.value = [] |
| | | selectedSuiteIds.value.clear() |
| | | selectAllChecked.value = false |
| | | } |
| | | } catch (e) { /* ignore */ } |
| | | // 显示订单状态面板 |
| | | showOrderPanel.value = false |
| | | showPricePanel.value = false |
| | | showOrderStatus.value = true |
| | | } else { |
| | | ElMessage.error(res?.msg || '创建订单失败') |
| | | } |
| | | } catch (e) { |
| | | ElMessage.error('创建订单失败') |
| | | } |
| | | } |
| | | |
| | | // 订购成功回调 |
| | | const handleOrderSuccess = (orderData: any) => { |
| | | console.log('订购成功:', orderData) |
| | | ElMessage.success('订购申请提交成功!') |
| | | // 清空选择状态 |
| | | selectedSuiteIds.value.clear() |
| | | // 关闭价格查看器 |
| | | visible.value = false |
| | | // 购物车相关方法 |
| | | const addToCart = async (priceItem: PriceItem) => { |
| | | try { |
| | | const cartData = { |
| | | pricingId: priceItem.id, |
| | | productId: priceItem.productId, |
| | | productName: productName.value, |
| | | suiteName: getProductSuiteText(priceItem.productSuite), |
| | | salesForm: getSalesFormText(priceItem.salesForm), |
| | | customerType: getCustomerObjectText(priceItem.customerObject), |
| | | accountLimit: priceItem.accountQuantityUnlimited ? '不限' : String(priceItem.accountQuantity), |
| | | concurrentNodes: priceItem.concurrentNodeQuantityUnlimited ? '不限' : String(priceItem.concurrentNodeQuantity), |
| | | priceType: priceItem.priceSettings.map(item => getPriceSettingText(item)).join(','), |
| | | priceUnit: getPriceUnitText(priceItem.priceUnit), |
| | | unitPrice: priceItem.pointsAmount || priceItem.currencyAmount || 0, |
| | | quantity: 1, |
| | | duration: 1 |
| | | } |
| | | |
| | | const res: any = await cartApi.addToCart(cartData, currentUserId.value, currentUnitId.value) |
| | | if (res?.code === 200) { |
| | | ElMessage.success('已添加到购物车') |
| | | } else { |
| | | ElMessage.error(res?.msg || '添加到购物车失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('添加到购物车失败:', error) |
| | | ElMessage.error('添加到购物车失败') |
| | | } |
| | | } |
| | | |
| | | const removeFromCart = async (pricingId: string) => { |
| | | try { |
| | | const res: any = await cartApi.removeFromCart(currentUserId.value, currentUnitId.value, pricingId) |
| | | if (res?.code === 200) { |
| | | ElMessage.success('已从购物车移除') |
| | | } else { |
| | | ElMessage.error(res?.msg || '从购物车移除失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('从购物车移除失败:', error) |
| | | ElMessage.error('从购物车移除失败') |
| | | } |
| | | } |
| | | |
| | | const updateCartItem = async (pricingId: number, quantity: number, duration: number) => { |
| | | try { |
| | | // 这里需要根据实际接口调整,可能需要传递更多参数 |
| | | const res: any = await cartApi.updateCartItem(currentUserId.value, currentUnitId.value, pricingId, quantity) |
| | | if (res?.code === 200) { |
| | | ElMessage.success('购物车已更新') |
| | | } else { |
| | | ElMessage.error(res?.msg || '更新购物车失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('更新购物车失败:', error) |
| | | ElMessage.error('更新购物车失败') |
| | | } |
| | | } |
| | | |
| | | const fetchCartItems = async () => { |
| | | cartLoading.value = true |
| | | try { |
| | | const res: any = await cartApi.getCartItems(currentUserId.value, currentUnitId.value) |
| | | if (res?.code === 200) { |
| | | cartItems.value = res.data || [] |
| | | // 将购物车数据转换为订单套件格式 |
| | | orderSuites.value = cartItems.value.map((item: any) => ({ |
| | | id: item.pricingId, |
| | | productId: String(item.productId), |
| | | productSuite: item.suiteName, |
| | | salesForm: mapSalesFormFromCN(item.salesForm), |
| | | customerObject: mapCustomerFromCN(item.customerType), |
| | | accountQuantity: item.accountLimit === '不限' ? 0 : Number(item.accountLimit), |
| | | accountQuantityUnlimited: item.accountLimit === '不限', |
| | | concurrentNodeQuantity: item.concurrentNodes === '不限' ? 0 : Number(item.concurrentNodes), |
| | | concurrentNodeQuantityUnlimited: item.concurrentNodes === '不限', |
| | | priceSettings: item.priceType.split(',').map((t: string) => mapPriceTypeFromCN(t)).filter(Boolean), |
| | | pointsAmount: item.priceType.includes('积分') ? item.unitPrice : 0, |
| | | currencyAmount: item.priceType.includes('货币') ? item.unitPrice : 0, |
| | | priceUnit: mapUnitFromCN(item.priceUnit), |
| | | enableStatus: 'ENABLED', |
| | | selected: true, |
| | | quantity: item.quantity || 1, |
| | | duration: item.duration || 1, |
| | | priceType: getDefaultPriceType({ |
| | | priceSettings: item.priceType.split(',').map((t: string) => mapPriceTypeFromCN(t)).filter(Boolean) |
| | | } as any) |
| | | })) as any |
| | | } else { |
| | | orderSuites.value = [] |
| | | ElMessage.error(res?.msg || '获取购物车信息失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('获取购物车信息失败:', error) |
| | | orderSuites.value = [] |
| | | ElMessage.error('获取购物车信息失败') |
| | | } finally { |
| | | cartLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 处理数量变化 |
| | | const handleQuantityChange = async (pricingId: number, quantity: number) => { |
| | | try { |
| | | await updateCartItem(pricingId, quantity, 1) // 暂时传递默认duration为1 |
| | | } catch (error) { |
| | | console.error('更新数量失败:', error) |
| | | } |
| | | } |
| | | |
| | | // 处理年限变化 |
| | | const handleDurationChange = async (pricingId: number, duration: number) => { |
| | | try { |
| | | // 这里可能需要根据实际接口调整,传递duration参数 |
| | | await updateCartItem(pricingId, 1, duration) // 暂时传递默认quantity为1 |
| | | } catch (error) { |
| | | console.error('更新年限失败:', error) |
| | | } |
| | | } |
| | | |
| | | // 获取销售形式文本 |
| | |
| | | .pricing-table-container { |
| | | .pricing-tabs { |
| | | :deep(.el-tabs__header) { |
| | | margin-bottom: 5px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | /* 居中 tabs 导航 */ |
| | | :deep(.el-tabs__nav-wrap) { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | :deep(.el-tabs__nav) { |
| | | margin: 0 auto; |
| | | border: none !important; |
| | | } |
| | | /* 卡片型 tabs 美化为圆角胶囊效果 */ |
| | | :deep(.el-tabs--card > .el-tabs__header .el-tabs__nav) { |
| | | border: none; |
| | | } |
| | | :deep(.el-tabs--card > .el-tabs__header .el-tabs__item) { |
| | | border: none; |
| | | } |
| | | :deep(.el-tabs__item) { |
| | | border-radius: 999px; |
| | | padding: 8px 18px; |
| | | margin: 0 6px; |
| | | color: #606266; |
| | | background: #f6f8fb; |
| | | transition: all .2s ease; |
| | | } |
| | | :deep(.el-tabs__item:hover) { |
| | | color: #3a7afe; |
| | | background: #eff4ff; |
| | | } |
| | | :deep(.el-tabs__item.is-active) { |
| | | font-weight: bold; |
| | | font-weight: 600; |
| | | color: #fff; |
| | | background: #3a7afe; |
| | | box-shadow: 0 6px 16px rgba(58, 122, 254, 0.25); |
| | | } |
| | | } |
| | | |
| | | .pricing-table-wrapper { |
| | | overflow-x: auto; |
| | | background: #fff; |
| | | border-radius: 12px; |
| | | box-shadow: 0 6px 24px rgba(0, 0, 0, 0.06); |
| | | padding: 8px; |
| | | |
| | | .pricing-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #e4e7ed; |
| | | border-collapse: separate; |
| | | border-spacing: 0; |
| | | background: #fff; |
| | | border-radius: 10px; |
| | | |
| | | th, td { |
| | | border: 1px solid #e4e7ed; |
| | | padding: 6px 8px; |
| | | border-bottom: 1px solid #eef2f7; |
| | | border-right: 1px solid #f3f5f7; |
| | | padding: 12px 14px; |
| | | text-align: center; |
| | | vertical-align: middle; |
| | | font-size: 16px; |
| | | font-size: 14px; |
| | | } |
| | | tr th:first-child, td:first-child{ |
| | | font-weight: 700; |
| | |
| | | } |
| | | |
| | | th { |
| | | background-color: #f5f7fa; |
| | | background: linear-gradient(180deg, #f7f9fc 0%, #eef2f7 100%); |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | |
| | | |
| | | .sub-header { |
| | | th { |
| | | background-color: #fafafa; |
| | | background-color: #f8fafc; |
| | | font-weight: 500; |
| | | font-size: 16px; |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | .feature-value { |
| | | color: #606266; |
| | | background: #fafafa; /* 行为灰色 */ |
| | | color: #303133; |
| | | background: #fff; |
| | | } |
| | | |
| | | tbody tr:hover td { |
| | | background: #fafcff; |
| | | } |
| | | |
| | | .order-methods { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | gap: 6px; |
| | | align-items: center; |
| | | |
| | | .method-item { |
| | | font-size: 16px; |
| | | color: #409eff; |
| | | font-size: 12px; |
| | | color: #3a7afe; |
| | | background: #f4f7ff; |
| | | border: 1px solid #e3ebff; |
| | | border-radius: 999px; |
| | | padding: 2px 10px; |
| | | } |
| | | } |
| | | |
| | | .price-info { |
| | | display: flex; |
| | | flex-direction: column; /* 竖排 */ |
| | | gap: 8px; |
| | | gap: 10px; |
| | | align-items: center; |
| | | |
| | | .price-item { |
| | |
| | | align-items: flex-start; |
| | | flex-direction: column; |
| | | gap: 6px; |
| | | padding: 10px 12px; |
| | | border: 1px solid #f0f2f5; |
| | | border-radius: 10px; |
| | | background: #fff; |
| | | box-shadow: inset 0 -1px 0 rgba(0,0,0,0.02); |
| | | .price-lable-icon{ |
| | | display: flex; |
| | | gap: 6px; |
| | | } |
| | | .price-label { |
| | | font-size: 16px; |
| | | color: #606266; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .price-value { |
| | | font-weight: 500; |
| | | font-size: 20px; |
| | | font-weight: 600; |
| | | font-size: 18px; |
| | | &.points { |
| | | color: #e7900d; |
| | | } |
| | | |
| | | &.currency { |
| | | color: #f56c6c; |
| | | color: #10b981; |
| | | } |
| | | |
| | | &.free { |
| | |
| | | } |
| | | } |
| | | .price-icon.points { color: #e6a23c; } |
| | | .price-icon.currency { color: #f56c6c; } |
| | | .price-icon.currency { color: #16a34a; } |
| | | } |
| | | |
| | | .add-checkbox { |
| | |
| | | justify-content: center; |
| | | align-items: center; |
| | | padding: 8px 0; |
| | | .add-cart-icon { color: #409eff; font-size:22px} |
| | | .add-cart-icon { color: #3a7afe; font-size:22px} |
| | | } |
| | | } |
| | | } |
| | |
| | | .order-summary .summary-value.highlight{ color:#409eff; } |
| | | .order-summary .summary-value.total{ color:#e6a23c; } |
| | | .order-summary .summary-value.currency{ color:#f56c6c; } |
| | | .footer { display: flex; flex-direction: row-reverse; margin-right: 50px; gap: 50px; margin-top: 20px;} |
| | | </style> |