txw/txw-mhzc-web/src/pages/index/views/fwsc/jrsc.vue
2026-04-06 14:45:39 +08:00

1530 lines
35 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="jrsc-page">
<!-- 面包屑导航 -->
<BreadcrumbNav currentPage="碳金融市场" />
<!-- 二级菜单 -->
<div class="secondary-nav">
<div class="secondary-nav-content">
<div class="nav-tabs">
<button
v-for="tab in navTabs"
:key="tab.path"
:class="['nav-tab', { active: isActiveTab(tab.path) }]"
@click="goToTab(tab.path)"
>
{{ tab.label }}
</button>
</div>
<button class="publish-btn" @click="handlePublish">免费发布金融产品</button>
</div>
</div>
<!-- 页面主体 -->
<main class="jrsc-main">
<div class="content-wrapper">
<!-- 左侧筛选栏 -->
<aside class="filter-sidebar">
<div class="filter-toggle" @click="filterCollapsed = !filterCollapsed">
<span class="toggle-text">筛选</span>
<span class="toggle-icon">{{ filterCollapsed ? '▼' : '▲' }}</span>
</div>
<div :class="['filter-sidebar-content', { collapsed: filterCollapsed }]">
<!-- 内容搜索 -->
<div class="filter-section">
<div class="filter-title">关键词搜索</div>
<t-input v-model="searchKeyword" placeholder="请输入关键词" @enter="handleSearch" />
<!-- 按钮 -->
<div class="filter-buttons">
<t-button theme="primary" @click="handleSearch">查询</t-button>
<t-button theme="default" @click="handleReset">重置</t-button>
</div>
</div>
<!-- 服务类型切换 -->
<div class="filter-section">
<div class="filter-title">产品类型</div>
<div class="product-type-cards">
<div
v-for="item in productTypes"
:key="item.value"
:class="['type-card', { active: selectedProductType === item.value }]"
@click="handleTypeChange(item.value)"
>
<span class="type-icon">{{ item.value === 'xd' ? '💰' : '🛡️' }}</span>
<span class="type-label">{{ item.label }}</span>
</div>
</div>
</div>
<!-- 机构筛选 -->
<div class="filter-section enterprise-section">
<div class="filter-title">{{ selectedProductType === 'xd' ? '合作银行' : '合作保险机构' }}</div>
<div class="filter-options enterprise-options">
<div
v-for="item in filteredInstitutions"
:key="item.value"
:class="['filter-item', { active: selectedInstitutions.includes(item.value) }]"
@click="toggleInstitution(item.value)"
>
<span class="check-icon">{{ selectedInstitutions.includes(item.value) ? '✓' : '' }}</span>
{{ item.label }}
</div>
</div>
</div>
</div>
</aside>
<!-- 右侧金融产品列表 -->
<div class="product-list">
<div class="list-header">
<div class="list-title-box">
<span class="list-icon">💹</span>
<span class="list-title">碳金融市场</span>
</div>
<div class="list-right">
<span class="list-count"><span class="count-dot"></span>共 {{ total }} 条产品</span>
</div>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-state">
<div class="loading-spinner"></div>
<p>加载中...</p>
</div>
<div class="product-grid" v-else>
<div
v-for="card in productList"
:key="card.cpuuid"
class="product-card"
>
<!-- 卡片顶部渐变边框 -->
<div class="card-gradient-top"></div>
<!-- 卡片头部 -->
<div class="card-header">
<div class="bank-info">
<div class="logo-wrapper">
<img v-if="card.yxlogo" class="bank-logo" :src="card.yxlogo" :alt="card.qymc" />
<div v-else class="bank-logo-placeholder">{{ card.qymc ? card.qymc.charAt(0) : '🏦' }}</div>
</div>
<div class="bank-detail">
<span class="bank-name">{{ card.qymc }}</span>
<span class="bank-tag">{{ selectedProductType === 'xd' ? '绿色信贷' : '绿色保险' }}</span>
</div>
</div>
</div>
<!-- 产品名称 -->
<div class="product-name">{{ card.cpmc }}</div>
<!-- 产品信息 -->
<div class="product-info" v-if="selectedProductType === 'xd'">
<div class="info-item">
<div class="info-icon">📊</div>
<div class="info-content">
<div class="info-label">贷款额度</div>
<div class="info-value">{{ card.edfw || '面议' }}</div>
</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-icon">📅</div>
<div class="info-content">
<div class="info-label">贷款期限</div>
<div class="info-value">{{ card.dkqxfw || '面议' }}</div>
</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-icon">💵</div>
<div class="info-content">
<div class="info-label">利率</div>
<div class="info-value rate">{{ card.llfw || '面议' }}</div>
</div>
</div>
</div>
<div class="product-info" v-else>
<div class="info-item">
<div class="info-icon">🛡️</div>
<div class="info-content">
<div class="info-label">保障期限</div>
<div class="info-value">{{ card.bzqxfw || '面议' }}</div>
</div>
</div>
<div class="info-divider"></div>
<div class="info-item">
<div class="info-icon">💳</div>
<div class="info-content">
<div class="info-label">保费方式</div>
<div class="info-value">{{ card.bfjsfs || '面议' }}</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="card-actions">
<t-button theme="default" size="small" variant="outline" @click="handleDetail(card)">查看详情</t-button>
<t-button theme="primary" size="small" @click="handleApply(card)">立即申请</t-button>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="!loading && productList.length === 0" class="empty-state">
<div class="empty-illustration">💰</div>
<p class="empty-text">暂无金融产品</p>
<p class="empty-hint">敬请期待更多优质金融产品上线</p>
</div>
<!-- 分页 -->
<div class="pagination-box" v-if="total > 0">
<t-pagination
v-model="page.pageNo"
:total="total"
:page-size.sync="page.pageSize"
:page-size-options="[3, 6, 9, 18]"
@change="onPageChange"
/>
</div>
</div>
</div>
</main>
<Footer />
<!-- 产品详情弹窗 -->
<t-dialog
:header="selectedProductType === 'xd' ? '💰 信贷产品详情' : '🛡️ 保险产品详情'"
:visible.sync="detailVisible"
width="50%"
:closeOnOverlayClick="false"
:onClose="onDetailClose"
class="global-dialog detail-dialog"
>
<div class="detail-content" v-if="selectedProduct">
<div class="detail-header">
<div class="detail-product-name">{{ selectedProduct.cpmc }}</div>
</div>
<table class="info-table">
<tbody v-if="selectedProductType === 'xd'">
<tr class="table-row">
<td class="label-cell">金融机构</td>
<td class="value-cell">{{ selectedProduct.qymc }}</td>
<td class="label-cell">业务类型</td>
<td class="value-cell">{{ selectedProduct.ywlxmc }}</td>
</tr>
<tr class="table-row">
<td class="label-cell">额度范围</td>
<td class="value-cell highlight">{{ selectedProduct.edfw || '面议' }}</td>
<td class="label-cell">利率范围</td>
<td class="value-cell highlight rate">{{ selectedProduct.llfw || '面议' }}</td>
</tr>
<tr class="table-row">
<td class="label-cell">贷款期限</td>
<td class="value-cell">{{ selectedProduct.dkqxfw || '面议' }}</td>
<td class="label-cell"></td>
<td class="value-cell"></td>
</tr>
</tbody>
<tbody v-else>
<tr class="table-row">
<td class="label-cell">保险公司</td>
<td class="value-cell">{{ selectedProduct.qymc }}</td>
<td class="label-cell">保险类型</td>
<td class="value-cell">{{ selectedProduct.ywlxmc }}</td>
</tr>
<tr class="table-row">
<td class="label-cell">保障期限</td>
<td class="value-cell highlight">{{ selectedProduct.bzqxfw || '面议' }}</td>
<td class="label-cell">保费方式</td>
<td class="value-cell highlight">{{ selectedProduct.bfjsfs || '面议' }}</td>
</tr>
</tbody>
</table>
<div class="product-description">
<h4 class="description-title">产品说明</h4>
<div class="description-content">
<p>{{ selectedProduct.fwcpms || '暂无产品说明,请联系金融机构了解详情。' }}</p>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<t-button theme="default" variant="outline" @click="onDetailClose">关闭</t-button>
<t-button theme="primary" @click="handleDetailApply">立即申请 💡</t-button>
</div>
</template>
</t-dialog>
<!-- 申请弹窗 -->
<t-dialog
header="申请信息"
:visible.sync="applyVisible"
width="50%"
:closeOnOverlayClick="false"
:onClose="onApplyClose"
class="global-dialog"
>
<div class="apply-form" v-if="!submitSuccess">
<t-form :data="applyForm" labelAlign="top" ref="applyFormRef">
<t-form-item label="企业名称">
<t-input v-model="applyForm.qymc" placeholder="请输入企业名称" disabled />
</t-form-item>
<t-form-item label="联系人">
<t-input v-model="applyForm.lxr" placeholder="请输入联系人" />
</t-form-item>
<t-form-item label="联系电话">
<t-input v-model="applyForm.lxdh" placeholder="请输入联系电话" />
</t-form-item>
<t-form-item v-if="selectedProductType === 'xd'" label="申请金额(万元)">
<t-select v-model="applyForm.sqdkJe" placeholder="请选择" clearable>
<t-option value="50" label="50万元" />
<t-option value="100" label="100万元" />
<t-option value="200" label="200万元" />
<t-option value="500" label="500万元" />
</t-select>
</t-form-item>
<t-form-item v-else label="投保金额(万元)">
<t-input v-model="applyForm.tbje" placeholder="请输入" type="number" />
</t-form-item>
<t-form-item v-if="selectedProductType === 'xd'" label="贷款用途">
<t-textarea v-model="applyForm.sqdkyt" placeholder="请输入贷款用途" />
</t-form-item>
</t-form>
</div>
<div class="submit-success" v-else>
<div class="success-icon">✓</div>
<div class="success-text">提交成功,请等待审核</div>
</div>
<template #footer>
<div class="dialog-footer" v-if="!submitSuccess">
<t-button theme="default" @click="onApplyClose">取消</t-button>
<t-button theme="primary" @click="handleSubmitApply" :loading="submitLoading">提交</t-button>
</div>
<div class="dialog-footer" v-else>
<t-button theme="primary" @click="onApplyClose">确定</t-button>
</div>
</template>
</t-dialog>
<!-- 提示弹窗 -->
<t-dialog
:closeOnOverlayClick="false"
header="提示"
body="请先进行企业入驻"
:visible.sync="rzVisible"
@confirm="onRzConfirm"
:onClose="onRzClose"
:cancelBtn="null"
class="global-dialog"
/>
</div>
</template>
<script>
import BreadcrumbNav from '@/pages/index/components/breadcrumb/index.vue';
import Footer from '@/pages/index/components/footer/index.vue';
import api from '@/pages/index/api/fwsc/index.js';
export default {
name: 'JrscPage',
components: {
BreadcrumbNav,
Footer,
},
data() {
return {
navTabs: [
{ label: '碳服务市场', path: '/tfwsc' },
{ label: '碳需求市场', path: '/txqsc' },
{ label: '碳金融市场', path: '/tjrsc' },
{ label: '碳数据市场', path: '/tsjsc' },
],
// 产品类型选项
productTypes: [
{ label: '绿色信贷', value: 'xd' },
{ label: '绿色保险', value: 'bx' },
],
// 选中产品类型
selectedProductType: 'xd',
// 机构选项
institutionOptions: [],
// 选中的机构
selectedInstitutions: [],
// 搜索关键词
searchKeyword: '',
// 产品列表
productList: [],
// 机构列表
total: 0,
// 分页
page: {
pageNo: 1,
pageSize: 6,
},
// 加载状态
loading: false,
// 详情弹窗
detailVisible: false,
selectedProduct: null,
// 申请弹窗
applyVisible: false,
submitSuccess: false,
submitLoading: false,
applyForm: {
qymc: '',
lxr: '',
lxdh: '',
sqdkJe: '',
sqdkyt: '',
tbje: '',
},
// 入驻提示弹窗
rzVisible: false,
// 当前申请的产品UUID
currentProductUuid: '',
// 用户信息
yhxx: {},
// 移动端筛选折叠状态
filterCollapsed: true,
};
},
computed: {
filteredInstitutions() {
return this.institutionOptions;
},
},
watch: {
// 监听机构选择变化,自动刷新产品列表
selectedInstitutions: {
handler() {
this.page.pageNo = 1;
this.loadProductList();
},
deep: true,
},
},
mounted() {
this.initUser();
this.loadInstitutionList();
this.loadProductList();
},
methods: {
// 初始化用户信息
async initUser() {
try {
const { data } = await api.init();
this.yhxx = data || {};
window.sessionStorage.setItem('yhxx', JSON.stringify(data));
this.applyForm.qymc = this.yhxx.qymc || '';
} catch (error) {
console.error('获取用户信息失败', error);
}
},
// 加载机构列表
async loadInstitutionList() {
try {
console.log('加载机构列表, type:', this.selectedProductType);
const { data, code } = await api.queryJgList(this.selectedProductType);
console.log('机构列表响应:', code, data);
if (code === 1 && data) {
// 兼容两种数据格式value/label 或 qyid/qymc
if (data.length > 0 && data[0].qyid !== undefined) {
this.institutionOptions = data.map((item) => ({
value: item.qyid,
label: item.qymc,
}));
} else {
this.institutionOptions = data;
}
}
} catch (error) {
console.error('加载机构列表失败', error);
this.institutionOptions = [];
}
},
// 加载产品列表
async loadProductList() {
this.loading = true;
try {
const params = {
type: this.selectedProductType,
pageNum: this.page.pageNo,
pageSize: this.page.pageSize,
cpmc: this.searchKeyword,
qyidList: this.selectedInstitutions,
};
console.log('加载产品列表, params:', params);
const { data, code } = await api.queryXdbxcpList(params);
console.log('产品列表响应:', code, data);
if (code === 1) {
this.productList = data.list || [];
this.total = Number(data.total || 0);
} else {
this.productList = [];
this.total = 0;
}
} catch (error) {
console.error('获取产品列表失败', error);
this.productList = [];
this.total = 0;
} finally {
this.loading = false;
}
},
// 切换产品类型
handleTypeChange(type) {
this.selectedProductType = type;
this.selectedInstitutions = [];
this.page.pageNo = 1;
this.loadInstitutionList();
this.loadProductList();
},
// 切换机构选择
toggleInstitution(value) {
const index = this.selectedInstitutions.indexOf(value);
if (index > -1) {
this.selectedInstitutions.splice(index, 1);
} else {
this.selectedInstitutions.push(value);
}
},
// 搜索
handleSearch() {
this.page.pageNo = 1;
this.loadProductList();
},
// 重置
handleReset() {
this.selectedInstitutions = [];
this.searchKeyword = '';
this.page.pageNo = 1;
this.loadProductList();
},
// 分页变化
onPageChange(pageInfo) {
this.page.pageNo = pageInfo.current;
this.page.pageSize = pageInfo.pageSize;
this.loadProductList();
},
// 查看详情
async handleDetail(card) {
try {
const { data, code } = await api.queryXdbxcpxq(card.cpuuid);
if (code === 1) {
this.selectedProduct = data;
this.detailVisible = true;
}
} catch (error) {
console.error('获取产品详情失败', error);
}
},
onDetailClose() {
this.detailVisible = false;
},
handleDetailApply() {
this.detailVisible = false;
this.handleApply(this.selectedProduct);
},
// 立即申请
handleApply(card) {
const yhxx = window.sessionStorage.getItem('yhxx');
if (yhxx) {
const yhxxData = JSON.parse(yhxx);
if (yhxxData.gxdtRzbz === 'Y') {
this.currentProductUuid = card.cpuuid;
this.applyVisible = true;
this.submitSuccess = false;
} else {
this.rzVisible = true;
}
} else {
this.rzVisible = true;
}
},
onApplyClose() {
this.applyVisible = false;
this.submitSuccess = false;
this.applyForm = {
qymc: this.yhxx.qymc || '',
lxr: '',
lxdh: '',
sqdkJe: '',
sqdkyt: '',
tbje: '',
};
},
async handleSubmitApply() {
if (!this.applyForm.lxr || !this.applyForm.lxdh) {
this.$message.warning('请填写完整信息');
return;
}
if (this.selectedProductType === 'xd' && !this.applyForm.sqdkJe) {
this.$message.warning('请选择申请金额');
return;
}
if (this.selectedProductType === 'bx' && !this.applyForm.tbje) {
this.$message.warning('请输入投保金额');
return;
}
this.submitLoading = true;
try {
// 模拟提交成功
await new Promise((resolve) => setTimeout(resolve, 1000));
this.submitSuccess = true;
this.$message.success('提交成功');
} catch (error) {
this.$message.error('提交失败');
} finally {
this.submitLoading = false;
}
},
onRzConfirm() {
this.rzVisible = false;
},
onRzClose() {
this.rzVisible = false;
},
// 发布
handlePublish() {
this.$message.info('请联系客服发布金融产品');
},
// 导航相关
isActiveTab(path) {
return this.$route.path === path;
},
goToTab(path) {
this.$router.push(path);
},
},
};
</script>
<style scoped lang="less">
// 变量定义
@primary-color: #009a29;
@primary-light: #4caf50;
@primary-bg: #e8f5e9;
@secondary-color: #d25f00;
@text-dark: #333;
@text-light: #666;
@text-gray: #999;
@border-color: #e5e7eb;
@bg-gray: #f5f5f5;
@bg-white: #fff;
.jrsc-page {
min-height: 100vh;
background: @bg-gray;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.jrsc-main {
width: 100%;
max-width: 1400px;
padding: 20px;
margin: 0 auto;
}
// 二级菜单
.secondary-nav {
background: @bg-white;
border-bottom: 1px solid #eee;
}
.secondary-nav-content {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1400px;
padding: 0 20px;
margin: 0 auto;
}
.nav-tabs {
display: flex;
gap: 8px;
}
.nav-tab {
padding: 12px 20px;
font-size: 14px;
color: @text-light;
cursor: pointer;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: @primary-color;
}
&.active {
color: @primary-color;
border-bottom-color: @primary-color;
}
}
.publish-btn {
padding: 8px 20px;
font-size: 14px;
color: #fff;
cursor: pointer;
background: linear-gradient(135deg, @primary-color 0%, @primary-light 100%);
border: none;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 154, 41, 0.3);
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 154, 41, 0.4);
}
}
// 内容区域
.content-wrapper {
display: flex;
gap: 20px;
}
// 左侧筛选栏
.filter-sidebar {
position: sticky;
top: 104px;
width: 240px;
height: fit-content;
flex-shrink: 0;
}
.filter-sidebar-content {
padding: 20px;
background: @bg-white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
// 移动端筛选栏折叠
.filter-toggle {
display: none;
}
@media (max-width: 768px) {
.filter-toggle {
display: flex;
padding: 12px;
margin-bottom: 8px;
cursor: pointer;
background: #fff;
border-radius: 8px;
justify-content: space-between;
align-items: center;
.toggle-text {
font-size: 14px;
font-weight: 600;
color: #333;
}
.toggle-icon {
font-size: 18px;
color: #666;
transition: transform 0.3s;
}
&.collapsed .toggle-icon {
transform: rotate(-90deg);
}
}
.filter-sidebar-content {
max-height: 1000px;
padding: 20px;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
}
.filter-sidebar-content.collapsed {
max-height: 0;
padding-top: 0;
padding-bottom: 0;
}
}
.filter-section {
padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px dashed #e0e0e0;
&:last-child {
padding-bottom: 0;
margin-bottom: 0;
border-bottom: none;
}
}
.filter-title {
display: flex;
margin-bottom: 12px;
font-size: 14px;
font-weight: 600;
color: @text-dark;
align-items: center;
gap: 6px;
&::before {
width: 4px;
height: 14px;
background: linear-gradient(180deg, @primary-color, @primary-light);
border-radius: 2px;
content: '';
}
}
// 产品类型切换卡片
.product-type-cards {
display: flex;
gap: 12px;
}
.type-card {
display: flex;
padding: 16px 8px;
cursor: pointer;
background: @bg-gray;
border: 2px solid transparent;
border-radius: 8px;
transition: all 0.3s;
flex: 1;
flex-direction: column;
align-items: center;
&:hover {
background: @primary-bg;
border-color: @primary-bg;
}
&.active {
background: @primary-bg;
border-color: @primary-color;
box-shadow: 0 2px 8px rgba(0, 154, 41, 0.2);
.type-label {
font-weight: 600;
color: @primary-color;
}
}
.type-icon {
margin-bottom: 8px;
font-size: 24px;
}
.type-label {
font-size: 13px;
color: @text-light;
transition: all 0.3s;
}
}
// 机构筛选
.enterprise-section {
.filter-options {
flex-direction: column;
gap: 6px;
}
.filter-item {
display: flex;
padding: 10px 12px;
font-size: 14px;
color: @text-light;
cursor: pointer;
background: @bg-gray;
border-radius: 6px;
transition: all 0.3s;
align-items: center;
gap: 8px;
.check-icon {
display: flex;
width: 18px;
height: 18px;
font-size: 12px;
color: #fff;
background: #ccc;
border-radius: 4px;
transition: all 0.3s;
align-items: center;
justify-content: center;
}
&:hover {
color: @primary-color;
background: @primary-bg;
}
&.active {
color: @primary-color;
background: @primary-bg;
.check-icon {
background: @primary-color;
}
}
}
}
.enterprise-options {
max-height: 200px;
padding-right: 4px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 2px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
}
.filter-buttons {
display: flex;
gap: 8px;
margin-top: 16px;
.t-button {
flex: 1;
}
}
// 右侧产品列表
.product-list {
flex: 1;
min-width: 0;
}
.list-header {
display: flex;
padding: 0 8px;
margin-bottom: 20px;
justify-content: space-between;
align-items: center;
}
.list-title-box {
display: flex;
align-items: center;
gap: 10px;
.list-icon {
font-size: 24px;
}
.list-title {
font-size: 22px;
font-weight: 600;
color: @text-dark;
background: linear-gradient(135deg, @text-dark 0%, @primary-color 100%);
background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
}
.list-right {
display: flex;
align-items: center;
}
.list-count {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: @text-gray;
.count-dot {
width: 8px;
height: 8px;
background: linear-gradient(135deg, @primary-color, @primary-light);
border-radius: 50%;
animation: pulse 2s infinite;
}
}
@keyframes pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
// 产品卡片网格
.product-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
// 产品卡片
.product-card {
position: relative;
display: flex;
padding: 20px;
padding-top: 0;
overflow: hidden;
background: @bg-white;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
transition: all 0.3s;
flex-direction: column;
&:hover {
transform: translateY(-6px);
box-shadow: 0 12px 32px rgba(0, 154, 41, 0.15);
.card-gradient-top {
height: 4px;
}
}
}
.card-gradient-top {
height: 0;
margin: 0 -20px 16px;
background: linear-gradient(90deg, @primary-color, @primary-light, @primary-color);
background-size: 200% 100%;
border-radius: 0 0 8px 8px;
animation: gradientMove 3s ease infinite;
transition: height 0.3s;
}
@keyframes gradientMove {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.card-header {
display: flex;
padding-bottom: 16px;
margin-bottom: 12px;
border-bottom: 1px solid #f0f0f0;
justify-content: space-between;
align-items: center;
}
.bank-info {
display: flex;
align-items: center;
gap: 12px;
}
.logo-wrapper {
display: flex;
width: 48px;
height: 48px;
overflow: hidden;
background: linear-gradient(135deg, @primary-bg 0%, #f0f9f0 100%);
border-radius: 12px;
align-items: center;
justify-content: center;
}
.bank-logo {
width: 32px;
height: 32px;
object-fit: contain;
}
.bank-logo-placeholder {
display: flex;
width: 48px;
height: 48px;
font-size: 20px;
font-weight: 600;
color: @primary-color;
background: linear-gradient(135deg, @primary-bg 0%, #f0f9f0 100%);
border-radius: 12px;
align-items: center;
justify-content: center;
}
.bank-detail {
display: flex;
flex-direction: column;
gap: 4px;
}
.bank-name {
font-size: 15px;
font-weight: 600;
color: @text-dark;
}
.bank-tag {
display: inline-block;
padding: 2px 8px;
font-size: 11px;
color: @primary-color;
background: @primary-bg;
border-radius: 4px;
}
.product-name {
padding: 12px 16px;
margin-bottom: 16px;
font-size: 16px;
font-weight: 600;
color: @text-dark;
text-align: center;
background: linear-gradient(135deg, #f8f9fa 0%, #f0f0f0 100%);
border-radius: 8px;
}
.product-info {
display: flex;
padding: 16px 0;
margin-bottom: 16px;
border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0;
justify-content: space-between;
align-items: center;
}
.info-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.info-icon {
font-size: 18px;
}
.info-content {
display: flex;
flex-direction: column;
gap: 4px;
}
.info-label {
font-size: 12px;
color: @text-gray;
}
.info-value {
font-size: 14px;
font-weight: 600;
color: @text-dark;
&.rate {
color: @secondary-color;
}
}
.info-divider {
width: 1px;
height: 32px;
background: #e0e0e0;
}
.card-actions {
display: flex;
gap: 12px;
margin-top: auto;
.t-button {
flex: 1;
}
}
// 加载状态
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400px;
padding: 40px;
background: @bg-white;
border-radius: 12px;
.loading-spinner {
width: 48px;
height: 48px;
margin-bottom: 16px;
border: 4px solid @primary-bg;
border-top-color: @primary-color;
border-radius: 50%;
animation: spin 1s linear infinite;
}
p {
margin: 0;
font-size: 14px;
color: @text-gray;
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
// 空状态
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400px;
padding: 40px;
background: @bg-white;
border-radius: 12px;
animation: fadeIn 0.5s ease;
.empty-illustration {
margin-bottom: 20px;
font-size: 64px;
}
.empty-text {
margin: 0 0 8px;
font-size: 18px;
font-weight: 600;
color: @text-dark;
}
.empty-hint {
margin: 0;
font-size: 14px;
color: @text-gray;
}
}
// 分页
.pagination-box {
display: flex;
justify-content: center;
padding-top: 32px;
}
// 详情弹窗
.detail-dialog {
/deep/.t-dialog__header {
padding: 16px 24px;
background: linear-gradient(135deg, #e8f5e9 0%, #f0f9f0 100%);
border-radius: 8px 8px 0 0;
}
}
.detail-content {
padding: 8px;
animation: fadeIn 0.3s ease;
}
.detail-header {
padding: 16px 20px;
margin-bottom: 20px;
background: linear-gradient(135deg, #f8f9fa 0%, #f0f0f0 100%);
border-radius: 8px;
}
.detail-product-name {
font-size: 18px;
font-weight: 600;
color: #333;
text-align: center;
}
.info-table {
width: 100%;
margin-bottom: 24px;
overflow: hidden;
border: 1px solid @border-color;
border-collapse: collapse;
border-radius: 8px;
.table-row {
border-bottom: 1px solid @border-color;
&:last-child {
border-bottom: none;
}
}
.label-cell {
width: 100px;
padding: 14px 16px;
font-size: 14px;
font-weight: 500;
color: @text-light;
background: linear-gradient(135deg, #f8f9fa 0%, #f5f5f5 100%);
border-right: 1px solid @border-color;
}
.value-cell {
padding: 14px 16px;
font-size: 14px;
color: @text-dark;
&.highlight {
font-weight: 600;
color: @primary-color;
}
&.rate {
color: @secondary-color;
}
}
}
.product-description {
padding: 20px;
background: linear-gradient(135deg, #f8f9fa 0%, #f0f0f0 100%);
border-radius: 8px;
.description-title {
display: flex;
margin-bottom: 12px;
font-size: 15px;
font-weight: 600;
color: @text-dark;
align-items: center;
gap: 8px;
&::before {
content: '📋';
}
}
.description-content {
padding: 0;
p {
margin: 0;
font-size: 14px;
line-height: 1.8;
color: @text-light;
}
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
}
// 申请表单
.apply-form {
padding: 8px;
animation: fadeIn 0.3s ease;
}
.submit-success {
display: flex;
flex-direction: column;
align-items: center;
padding: 60px 0;
animation: scaleIn 0.4s ease;
.success-icon {
display: flex;
width: 80px;
height: 80px;
margin-bottom: 24px;
font-size: 40px;
color: #fff;
background: linear-gradient(135deg, @primary-color 0%, @primary-light 100%);
border-radius: 50%;
align-items: center;
justify-content: center;
animation: successPop 0.5s ease 0.2s both;
}
.success-text {
font-size: 18px;
font-weight: 600;
color: @text-dark;
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes successPop {
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
@media (max-width: 1200px) {
.product-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.jrsc-main {
padding: 12px;
}
.secondary-nav-content {
flex-direction: column;
padding: 12px 16px;
gap: 12px;
}
.nav-tabs {
width: 100%;
padding-bottom: 4px;
overflow-x: auto;
gap: 4px;
}
.nav-tab {
padding: 10px 12px;
font-size: 13px;
white-space: nowrap;
}
.publish-btn {
width: 100%;
padding: 10px;
}
.content-wrapper {
flex-direction: column;
}
.filter-sidebar {
position: relative;
top: 0;
width: 100%;
}
.filter-sidebar-content {
padding: 12px;
}
.product-list {
width: 100%;
}
.list-header {
flex-direction: column;
gap: 12px;
align-items: flex-start;
}
.product-grid {
grid-template-columns: 1fr;
gap: 12px;
}
.product-card {
padding: 16px;
}
.product-info {
flex-direction: column;
gap: 12px;
}
.info-divider {
display: none;
}
.info-item {
justify-content: flex-start;
}
.card-actions {
flex-direction: column;
gap: 8px;
}
.pagination-box {
padding-top: 20px;
}
}
@media (max-width: 480px) {
.jrsc-main {
padding: 8px;
}
.secondary-nav-content {
padding: 8px 12px;
}
.nav-tab {
padding: 8px 10px;
font-size: 12px;
}
.publish-btn {
padding: 8px;
font-size: 13px;
}
.list-title-box .list-title {
font-size: 18px;
}
.product-name {
padding: 10px;
font-size: 14px;
}
}
</style>