style: 修改服务中心样式
This commit is contained in:
parent
cfeb920294
commit
f8ff99786d
@ -10,7 +10,8 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const ROOT = __dirname;
|
const ROOT = __dirname;
|
||||||
const WEBS = ['txw-gxzx-web', 'txw-kxtfwzx-web', 'txw-mhzc-web', 'txw-tzzx-web', 'txw-ytzx-web', 'txw-yygl-web'];
|
// const WEBS = ['txw-gxzx-web', 'txw-kxtfwzx-web', 'txw-mhzc-web', 'txw-tzzx-web', 'txw-ytzx-web', 'txw-yygl-web'];
|
||||||
|
const WEBS = ['txw-mhzc-web'];
|
||||||
const LOCAL_PKGS = [
|
const LOCAL_PKGS = [
|
||||||
'local-nodemodules/@cssyq/ggzc-web',
|
'local-nodemodules/@cssyq/ggzc-web',
|
||||||
'local-nodemodules/@gt4/common-front',
|
'local-nodemodules/@gt4/common-front',
|
||||||
@ -30,7 +31,7 @@ function run(cmd, opts = {}) {
|
|||||||
console.log('=== 碳信网 Web 项目初始化 ===\n');
|
console.log('=== 碳信网 Web 项目初始化 ===\n');
|
||||||
|
|
||||||
for (const web of WEBS) {
|
for (const web of WEBS) {
|
||||||
const webPath = path.join(ROOT, web);
|
const webPath = path.join(ROOT, '..', web);
|
||||||
if (!fs.existsSync(webPath)) {
|
if (!fs.existsSync(webPath)) {
|
||||||
console.warn(`[跳过] ${web} 目录不存在`);
|
console.warn(`[跳过] ${web} 目录不存在`);
|
||||||
continue;
|
continue;
|
||||||
@ -42,8 +43,10 @@ for (const web of WEBS) {
|
|||||||
const pkgName = localPkg.split('/').pop();
|
const pkgName = localPkg.split('/').pop();
|
||||||
const scope = localPkg.split('/')[1].slice(1); // remove '@'
|
const scope = localPkg.split('/')[1].slice(1); // remove '@'
|
||||||
const scopeDir = path.join(webPath, 'node_modules', `@${scope}`);
|
const scopeDir = path.join(webPath, 'node_modules', `@${scope}`);
|
||||||
const linkTarget = path.join(ROOT, localPkg);
|
// 创建 symlink
|
||||||
const linkPath = path.join(scopeDir, pkgName);
|
const cssyqDir = path.join(webPath, 'node_modules/@cssyq');
|
||||||
|
const linkTarget = path.join(ROOT, '..', localPkg);
|
||||||
|
const linkPath = path.join(cssyqDir, 'ggzc-web');
|
||||||
|
|
||||||
fs.mkdirSync(scopeDir, { recursive: true });
|
fs.mkdirSync(scopeDir, { recursive: true });
|
||||||
if (fs.existsSync(linkPath)) {
|
if (fs.existsSync(linkPath)) {
|
||||||
@ -73,6 +76,18 @@ for (const web of WEBS) {
|
|||||||
console.log(` 链接 @${scope}/${pkgName} -> ${localPkg}`);
|
console.log(` 链接 @${scope}/${pkgName} -> ${localPkg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改 package.json 的 resolutions,强制使用本地包
|
||||||
|
const pkgJsonPath = path.join(webPath, 'package.json');
|
||||||
|
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
||||||
|
pkgJson.resolutions = pkgJson.resolutions || {};
|
||||||
|
for (const localPkg of LOCAL_PKGS) {
|
||||||
|
const pkgName = localPkg.split('/').pop();
|
||||||
|
const localPath = path.join(ROOT, '..', localPkg);
|
||||||
|
pkgJson.resolutions[pkgName] = `link:${localPath}`;
|
||||||
|
}
|
||||||
|
fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
||||||
|
console.log(` 已添加 resolutions`);
|
||||||
|
|
||||||
// 安装依赖
|
// 安装依赖
|
||||||
console.log(' 安装依赖...');
|
console.log(' 安装依赖...');
|
||||||
run(`cd "${webPath}" && yarn install --prefer-offline --ignore-engines`);
|
run(`cd "${webPath}" && yarn install --prefer-offline --ignore-engines`);
|
||||||
|
|||||||
13825
txw-gxzx-web/yarn.lock
13825
txw-gxzx-web/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
|||||||
registry=http://10.23.10.90:4873/
|
|
||||||
strict-ssl=false
|
|
||||||
52670
txw-mhzc-web/package-lock.json
generated
52670
txw-mhzc-web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,6 @@
|
|||||||
"@vue/babel-preset-jsx": "1.4.0"
|
"@vue/babel-preset-jsx": "1.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cssyq/ggzc-web": "^1.0.7",
|
|
||||||
"@fortawesome/fontawesome-free": "^7.0.1",
|
"@fortawesome/fontawesome-free": "^7.0.1",
|
||||||
"@gt4/common-front": "2.0.113",
|
"@gt4/common-front": "2.0.113",
|
||||||
"@gtff/tdesign-gt-vue": "1.4.0",
|
"@gtff/tdesign-gt-vue": "1.4.0",
|
||||||
@ -100,5 +99,10 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": "http://10.23.12.27:8089/qyd-znsb/znsb-mhzc.git",
|
"repository": "http://10.23.12.27:8089/qyd-znsb/znsb-mhzc.git",
|
||||||
"author": "wangjianxin@css.com.cn <wangjianxin@css.com.cn>",
|
"author": "wangjianxin@css.com.cn <wangjianxin@css.com.cn>",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
}
|
"resolutions": {
|
||||||
|
"ggzc-web": "link:D:\\shanghai\\txw2\\local-nodemodules\\@cssyq\\ggzc-web",
|
||||||
|
"common-front": "link:D:\\shanghai\\txw2\\local-nodemodules\\@gt4\\common-front",
|
||||||
|
"tdesign-gt-vue": "link:D:\\shanghai\\txw2\\local-nodemodules\\@gtff\\tdesign-gt-vue"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
txw-mhzc-web/src/pages/index/assets/fwsc/city.svg
Normal file
5
txw-mhzc-web/src/pages/index/assets/fwsc/city.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.00008 4.33337L3.66675 6.66671V14.6667" stroke="#D1D9D5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.33337L10.3333 3.66671V8.00004L12.6667 9.66671V14.6667H7V1.33337Z" fill="#D1D9D5" stroke="#D1D9D5" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M1.33325 14.6666H14.6666" stroke="#D1D9D5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 546 B |
7
txw-mhzc-web/src/pages/index/assets/fwsc/map.svg
Normal file
7
txw-mhzc-web/src/pages/index/assets/fwsc/map.svg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M5.66659 4L1.33325 2V12L5.66659 14L10.3333 12L14.6666 14V4L10.3333 2L5.66659 4Z" fill="#D1D9D5" stroke="#D1D9D5" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.3333 2V12" stroke="white" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5.66675 4V14" stroke="white" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.5 3L5.66667 4L10.3333 2L12.5 3" stroke="#D1D9D5" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.5 13L5.66667 14L10.3333 12L12.5 13" stroke="#D1D9D5" stroke-width="0.666667" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 794 B |
@ -1,28 +1,87 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fwsc-container">
|
<div class="fwsc-container">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<BreadcrumbNav currentPage="碳服务市场" />
|
<!-- <BreadcrumbNav currentPage="碳服务市场" /> -->
|
||||||
|
|
||||||
<!-- 二级菜单 -->
|
<!-- 二级菜单 -->
|
||||||
<div class="secondary-nav">
|
<div class="secondary-nav">
|
||||||
<div class="secondary-nav-content">
|
<div class="secondary-nav-content">
|
||||||
<div class="nav-tabs">
|
<div class="nav-tabs">
|
||||||
<button
|
<button v-for="tab in navTabs" :key="tab.path" :class="['nav-tab', { active: isActiveTab(tab.path) }]"
|
||||||
v-for="tab in navTabs"
|
@click="goToTab(tab.path)">
|
||||||
:key="tab.path"
|
|
||||||
:class="['nav-tab', { active: isActiveTab(tab.path) }]"
|
|
||||||
@click="goToTab(tab.path)"
|
|
||||||
>
|
|
||||||
{{ tab.label }}
|
{{ tab.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="publish-btn" @click="handlePublish">免费发布服务</button>
|
<div class="nav-right">
|
||||||
|
<span class="list-count">共 {{ page.total }} 条服务</span>
|
||||||
|
<button class="publish-btn" @click="handlePublish">免费发布服务</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main class="fwsc-main">
|
<main class="fwsc-main">
|
||||||
<div class="content-area">
|
<div class="content-area">
|
||||||
<!-- 左侧筛选栏 -->
|
<!-- 左侧服务卡片列表 -->
|
||||||
|
<div class="card-list">
|
||||||
|
<div class="service-grid">
|
||||||
|
<div v-for="(card, index) in cardList" :key="card.gxUuid" :data-gx-uuid="card.gxUuid" class="service-card">
|
||||||
|
<!-- 卡片头部 -->
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title-box">
|
||||||
|
<div class="card-title-text">
|
||||||
|
<div class="card-title-row">
|
||||||
|
<div class="card-title-main">{{ card.bt1 }}</div>
|
||||||
|
<!-- 收藏按钮 -->
|
||||||
|
<div class="card-collect" @click="handleCollect(card)">
|
||||||
|
<img v-if="card.scbz === 'Y'" src="../../assets/fwsc/ysc.svg" />
|
||||||
|
<img v-else src="../../assets/fwsc/wsc.svg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-title-sub">
|
||||||
|
<div class="card-company">
|
||||||
|
<img src="../../assets/fwsc/city.svg" />
|
||||||
|
<span class="company-name">{{ card.qymc }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="location" v-if="card.fwfw">
|
||||||
|
<img src="../../assets/fwsc/map.svg" />
|
||||||
|
<span class="company-name">{{ card.fwfw }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片内容 -->
|
||||||
|
<div class="card-content">
|
||||||
|
<p class="card-desc">{{ card.fwnr }}</p>
|
||||||
|
<div class="card-tags">
|
||||||
|
<span v-for="(tag, i) in card.fwlxbqList" :key="i" class="tag">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 卡片底部 -->
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="card-price-info">
|
||||||
|
<span class="price-value" v-if="card.gjjg">¥{{ card.gjjg }}</span>
|
||||||
|
<span class="price-value" v-else>面议</span>
|
||||||
|
<!-- <span class="price-unit" v-if="card.gjdwDm">/{{ card.gjdwDm }}</span> -->
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<span @click="handleContact(card)">立即咨询</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div v-if="cardList.length === 0 && !loading" class="empty-state">
|
||||||
|
<p>暂无服务信息</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧筛选栏 -->
|
||||||
<aside class="filter-sidebar">
|
<aside class="filter-sidebar">
|
||||||
<div class="filter-toggle" @click="filterCollapsed = !filterCollapsed">
|
<div class="filter-toggle" @click="filterCollapsed = !filterCollapsed">
|
||||||
<span class="toggle-text">筛选</span>
|
<span class="toggle-text">筛选</span>
|
||||||
@ -32,13 +91,12 @@
|
|||||||
<!-- 内容搜索 -->
|
<!-- 内容搜索 -->
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-title">内容搜索</div>
|
<div class="filter-title">内容搜索</div>
|
||||||
<t-input v-model="filter.nr" placeholder="请输入关键词" @enter="onSearch" />
|
<t-input v-model="filter.nr" placeholder="请输入关键词" @enter="onSearch">
|
||||||
<div class="filter-buttons">
|
<template #suffix-icon>
|
||||||
<t-button theme="primary" @click="onSearch">查询</t-button>
|
<SearchIcon />
|
||||||
<t-button theme="default" @click="onReset">重置</t-button>
|
</template>
|
||||||
</div>
|
</t-input>
|
||||||
|
|
||||||
|
|
||||||
<!-- 只展示收藏项 -->
|
<!-- 只展示收藏项 -->
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
<t-checkbox v-model="filter.zzsscx" @change="onSearch">只展示收藏项</t-checkbox>
|
<t-checkbox v-model="filter.zzsscx" @change="onSearch">只展示收藏项</t-checkbox>
|
||||||
@ -57,13 +115,8 @@
|
|||||||
<!-- 服务企业 -->
|
<!-- 服务企业 -->
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-title">服务企业</div>
|
<div class="filter-title">服务企业</div>
|
||||||
<t-input
|
<t-input v-model="qySearchKeyword" placeholder="搜索企业名称" clearable class="qy-search-input"
|
||||||
v-model="qySearchKeyword"
|
@change="filterQyOptions">
|
||||||
placeholder="搜索企业名称"
|
|
||||||
clearable
|
|
||||||
class="qy-search-input"
|
|
||||||
@change="filterQyOptions"
|
|
||||||
>
|
|
||||||
<template #prefix-icon>
|
<template #prefix-icon>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
</template>
|
</template>
|
||||||
@ -77,105 +130,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- 右侧服务卡片列表 -->
|
|
||||||
<div class="card-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>共 {{ page.total }} 条服务</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="service-grid">
|
|
||||||
<div
|
|
||||||
v-for="(card, index) in cardList"
|
|
||||||
:key="card.gxUuid"
|
|
||||||
:data-gx-uuid="card.gxUuid"
|
|
||||||
class="service-card"
|
|
||||||
>
|
|
||||||
<!-- 卡片头部 -->
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="card-title-box">
|
|
||||||
<div class="card-title-text">
|
|
||||||
<div class="card-title-main">{{ card.bt1 }}</div>
|
|
||||||
<div class="card-title-sub">
|
|
||||||
<span class="company-name">{{ card.qymc }}</span>
|
|
||||||
<span class="location" v-if="card.fwfw">
|
|
||||||
<LocationIcon style="transform: translateY(-1px)" />{{ card.fwfw }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 收藏按钮 -->
|
|
||||||
<div class="card-collect" @click="handleCollect(card)">
|
|
||||||
<img v-if="card.scbz === 'Y'" src="../../assets/fwsc/ysc.svg" />
|
|
||||||
<img v-else src="../../assets/fwsc/wsc.svg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 卡片内容 -->
|
|
||||||
<div class="card-content">
|
|
||||||
<p class="card-desc">{{ card.fwnr }}</p>
|
|
||||||
<div class="card-tags">
|
|
||||||
<span v-for="(tag, i) in card.fwlxbqList" :key="i" class="tag">{{ tag }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 卡片底部 -->
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="card-price-info">
|
|
||||||
<span class="price-value" v-if="card.gjjg">¥{{ card.gjjg }}</span>
|
|
||||||
<span class="price-value" v-else>面议</span>
|
|
||||||
<span class="price-unit" v-if="card.gjdwDm">/{{ card.gjdwDm }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<t-button theme="primary" size="small" @click="handleContact(card)">联系服务商</t-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 空状态 -->
|
|
||||||
<div v-if="cardList.length === 0 && !loading" class="empty-state">
|
|
||||||
<p>暂无服务信息</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<div class="pagination-box" v-if="page.total > 0">
|
<div class="pagination-box" v-if="page.total > 0">
|
||||||
<t-pagination
|
<div class="pagination-total">共 {{ page.total }} 条数据</div>
|
||||||
v-model="page.pageNo"
|
<t-pagination v-model="page.pageNo" :total="page.total" :page-size.sync="page.pageSize" :totalContent='false'
|
||||||
:total="page.total"
|
:page-size-options="[10, 20, 30, 50]" @change="onPageChange" align="center" />
|
||||||
:page-size.sync="page.pageSize"
|
|
||||||
:page-size-options="[3, 9, 27, 45]"
|
|
||||||
@change="onPageChange"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
<!-- 发布服务抽屉 -->
|
<!-- 发布服务抽屉 -->
|
||||||
<FwscPublish
|
<FwscPublish :visible.sync="publishVisible" @success="onPublishSuccess" />
|
||||||
:visible.sync="publishVisible"
|
|
||||||
@success="onPublishSuccess"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 联系服务弹窗 -->
|
<!-- 联系服务弹窗 -->
|
||||||
<t-dialog
|
<t-dialog :closeOnOverlayClick="false" header="联系服务" :visible.sync="contactVisible" @confirm="onContactConfirm"
|
||||||
:closeOnOverlayClick="false"
|
:onClose="onContactClose" class="global-dialog" attach="body">
|
||||||
header="联系服务"
|
|
||||||
:visible.sync="contactVisible"
|
|
||||||
@confirm="onContactConfirm"
|
|
||||||
:onClose="onContactClose"
|
|
||||||
class="global-dialog"
|
|
||||||
attach="body"
|
|
||||||
>
|
|
||||||
<div class="dialog-line">
|
<div class="dialog-line">
|
||||||
<div class="dialog-line-title">联系人:</div>
|
<div class="dialog-line-title">联系人:</div>
|
||||||
<div class="dialog-line-text">{{ contactData.lxr }}</div>
|
<div class="dialog-line-text">{{ contactData.lxr }}</div>
|
||||||
@ -191,29 +163,13 @@
|
|||||||
</t-dialog>
|
</t-dialog>
|
||||||
|
|
||||||
<!-- 提示弹窗 -->
|
<!-- 提示弹窗 -->
|
||||||
<t-dialog
|
<t-dialog :closeOnOverlayClick="false" header="提示" body="请先进行企业入驻" :visible.sync="rzVisible" @confirm="onRzConfirm"
|
||||||
:closeOnOverlayClick="false"
|
:onClose="onRzClose" :cancelBtn="null" class="global-dialog" />
|
||||||
header="提示"
|
|
||||||
body="请先进行企业入驻"
|
|
||||||
:visible.sync="rzVisible"
|
|
||||||
@confirm="onRzConfirm"
|
|
||||||
:onClose="onRzClose"
|
|
||||||
:cancelBtn="null"
|
|
||||||
class="global-dialog"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 发布成功弹窗 -->
|
<!-- 发布成功弹窗 -->
|
||||||
<t-dialog
|
<t-dialog :closeOnOverlayClick="false" body="发布申请成功,请等待审核,是否继续发布?" :visible.sync="publishSuccessVisible"
|
||||||
:closeOnOverlayClick="false"
|
@confirm="onPublishSuccessConfirm" @cancel="onPublishSuccessCancel" :onClose="onPublishSuccessClose"
|
||||||
body="发布申请成功,请等待审核,是否继续发布?"
|
cancelBtn="返回" confirmBtn="继续发布" class="global-dialog" />
|
||||||
:visible.sync="publishSuccessVisible"
|
|
||||||
@confirm="onPublishSuccessConfirm"
|
|
||||||
@cancel="onPublishSuccessCancel"
|
|
||||||
:onClose="onPublishSuccessClose"
|
|
||||||
cancelBtn="返回"
|
|
||||||
confirmBtn="继续发布"
|
|
||||||
class="global-dialog"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -265,7 +221,7 @@ export default {
|
|||||||
// 分页
|
// 分页
|
||||||
page: {
|
page: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 9,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
},
|
},
|
||||||
// 加载状态
|
// 加载状态
|
||||||
@ -532,8 +488,7 @@ export default {
|
|||||||
|
|
||||||
// 二级菜单
|
// 二级菜单
|
||||||
.secondary-nav {
|
.secondary-nav {
|
||||||
background: #fff;
|
border-bottom: none;
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.secondary-nav-content {
|
.secondary-nav-content {
|
||||||
@ -541,60 +496,53 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
padding: 0 20px;
|
padding: 20px 20px 0;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 40px;
|
||||||
|
width: 596px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tab {
|
.nav-tab {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 12px 20px;
|
min-width: max-content;
|
||||||
font-size: 14px;
|
height: 42px;
|
||||||
color: #666;
|
padding: 8px 16px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #003B1A;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border-radius: 32px;
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 50%;
|
|
||||||
width: 0;
|
|
||||||
height: 2px;
|
|
||||||
background: linear-gradient(90deg, #009a29, #48C666);
|
|
||||||
border-radius: 1px;
|
|
||||||
content: '';
|
|
||||||
transform: translateX(-50%);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #009a29;
|
color: #009a29;
|
||||||
|
|
||||||
&::after {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: #009a29;
|
background: #8CFFCE;
|
||||||
|
box-shadow: inset 0 0 0 1px #00B96B;
|
||||||
&::after {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish-btn {
|
.publish-btn {
|
||||||
padding: 8px 24px;
|
width: 220px;
|
||||||
font-size: 14px;
|
height: 42px;
|
||||||
font-weight: 500;
|
line-height: 26px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 400;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: linear-gradient(135deg, #009a29 0%, #48C666 100%);
|
background: linear-gradient(135deg, #009a29 0%, #48C666 100%);
|
||||||
@ -616,6 +564,7 @@ export default {
|
|||||||
.content-area {
|
.content-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 左侧筛选栏
|
// 左侧筛选栏
|
||||||
@ -623,7 +572,6 @@ export default {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 104px;
|
top: 104px;
|
||||||
width: 220px;
|
width: 220px;
|
||||||
height: fit-content;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,12 +630,12 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-section {
|
.filter-section {
|
||||||
padding-bottom: 20px;
|
// padding-bottom: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
border-bottom: 1px dashed #e0e0e0;
|
border-bottom: 1px dashed #e0e0e0;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
padding-bottom: 0;
|
padding: 10px 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
@ -734,16 +682,6 @@ export default {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
.t-button {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 右侧卡片列表
|
// 右侧卡片列表
|
||||||
.card-list {
|
.card-list {
|
||||||
@ -751,67 +689,16 @@ export default {
|
|||||||
min-width: 0;
|
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: #333;
|
|
||||||
background: linear-gradient(135deg, #333 0%, #009a29 100%);
|
|
||||||
background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-count {
|
.list-count {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #999;
|
font-weight: 400;
|
||||||
|
color: #6B8575;
|
||||||
.count-dot {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
background: linear-gradient(135deg, #009a29, #48C666);
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: pulse 2s infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0%, 100% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-grid {
|
.service-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
gap: 20px;
|
gap: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-card {
|
.service-card {
|
||||||
@ -828,32 +715,43 @@ export default {
|
|||||||
animation: highlight-pulse 3s ease-out;
|
animation: highlight-pulse 3s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
// &::before {
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
top: 0;
|
// top: 0;
|
||||||
left: 0;
|
// left: 0;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
height: 3px;
|
// height: 3px;
|
||||||
background: linear-gradient(90deg, #009a29, #48C666);
|
// background: linear-gradient(90deg, #009a29, #48C666);
|
||||||
content: '';
|
// content: '';
|
||||||
transform: scaleX(0);
|
// transform: scaleX(0);
|
||||||
transform-origin: left;
|
// transform-origin: left;
|
||||||
transition: transform 0.3s ease;
|
// transition: transform 0.3s ease;
|
||||||
}
|
// }
|
||||||
|
|
||||||
&:hover {
|
// &:hover {
|
||||||
transform: translateY(-4px);
|
// transform: translateY(-4px);
|
||||||
box-shadow: 0 8px 24px rgba(0, 154, 41, 0.15);
|
// box-shadow: 0 8px 24px rgba(0, 154, 41, 0.15);
|
||||||
|
|
||||||
&::before {
|
// &::before {
|
||||||
transform: scaleX(1);
|
// transform: scaleX(1);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
|
position: relative;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border-bottom: 1px solid #eee;
|
height: 70px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
bottom: -6px;
|
||||||
|
left: 16px;
|
||||||
|
height: 1px;
|
||||||
|
background: #E8F0EC;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-title-box {
|
.card-title-box {
|
||||||
@ -867,34 +765,49 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-title-main {
|
.card-title-main {
|
||||||
margin-bottom: 4px;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
color: #333;
|
color: #003B1A;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-company {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.card-title-sub {
|
.card-title-sub {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.company-name {
|
.company-name {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6B8575;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.location {
|
.location {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 2px;
|
gap: 8px;
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-collect {
|
.card-collect {
|
||||||
@ -931,18 +844,30 @@ export default {
|
|||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
color: #2e7d32;
|
font-weight: 400;
|
||||||
background: #dcf9e2;
|
color: #00B96B;
|
||||||
|
background: #EEFAE2;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-footer {
|
.card-footer {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
border-top: 1px dashed #979797;
|
height: 64px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 16px;
|
||||||
|
left: 16px;
|
||||||
|
height: 1px;
|
||||||
|
background: #E8F0EC;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-price-info {
|
.card-price-info {
|
||||||
@ -950,10 +875,21 @@ export default {
|
|||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-actions {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #00b96b;
|
||||||
|
color: #00b96b;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
.price-value {
|
.price-value {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #d25f00;
|
color: #FF4D4F;
|
||||||
}
|
}
|
||||||
|
|
||||||
.price-unit {
|
.price-unit {
|
||||||
@ -992,6 +928,7 @@ export default {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(10px);
|
transform: translateY(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
@ -999,10 +936,28 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 分页
|
// 分页
|
||||||
|
.pagination-total {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
.pagination-box {
|
.pagination-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-top: 32px;
|
padding-top: 32px;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
::v-deep .t-pagination {
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: initial;
|
||||||
|
|
||||||
|
.t-input.t-is-readonly {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 弹窗样式
|
// 弹窗样式
|
||||||
@ -1100,7 +1055,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-actions {
|
.card-actions {
|
||||||
width: 100%;
|
width: 100%
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-box {
|
.pagination-box {
|
||||||
@ -1153,9 +1108,11 @@ export default {
|
|||||||
0% {
|
0% {
|
||||||
box-shadow: 0 0 0 0 rgba(0, 154, 41, 0.4);
|
box-shadow: 0 0 0 0 rgba(0, 154, 41, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
box-shadow: 0 0 20px 10px rgba(0, 154, 41, 0.2);
|
box-shadow: 0 0 20px 10px rgba(0, 154, 41, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="jrsc-page">
|
<div class="jrsc-page">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<BreadcrumbNav currentPage="碳金融市场" />
|
<!-- <BreadcrumbNav currentPage="碳金融市场" /> -->
|
||||||
|
|
||||||
<!-- 二级菜单 -->
|
<!-- 二级菜单 -->
|
||||||
<div class="secondary-nav">
|
<div class="secondary-nav">
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sjlbc-page">
|
<div class="sjlbc-page">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<BreadcrumbNav
|
<!-- <BreadcrumbNav
|
||||||
:currentPage="currentPageName"
|
:currentPage="currentPageName"
|
||||||
secondPage="碳数据市场"
|
secondPage="碳数据市场"
|
||||||
secondLink="/tsjsc"
|
secondLink="/tsjsc"
|
||||||
/>
|
/> -->
|
||||||
|
|
||||||
<!-- 主内容区 -->
|
<!-- 主内容区 -->
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sjsc-page">
|
<div class="sjsc-page">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<BreadcrumbNav currentPage="碳数据市场" />
|
<!-- <BreadcrumbNav currentPage="碳数据市场" /> -->
|
||||||
|
|
||||||
<!-- 二级菜单 -->
|
<!-- 二级菜单 -->
|
||||||
<div class="secondary-nav">
|
<div class="secondary-nav">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="xqsc-container">
|
<div class="xqsc-container">
|
||||||
<!-- 面包屑导航 -->
|
<!-- 面包屑导航 -->
|
||||||
<BreadcrumbNav currentPage="碳需求市场" />
|
<!-- <BreadcrumbNav currentPage="碳需求市场" /> -->
|
||||||
|
|
||||||
<!-- 二级菜单 -->
|
<!-- 二级菜单 -->
|
||||||
<div class="secondary-nav">
|
<div class="secondary-nav">
|
||||||
|
|||||||
14425
txw-mhzc-web/yarn.lock
14425
txw-mhzc-web/yarn.lock
File diff suppressed because it is too large
Load Diff
660
前端项目文档.md
Normal file
660
前端项目文档.md
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
# 前端项目文档
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [项目概览](#项目概览)
|
||||||
|
- [目录结构](#目录结构)
|
||||||
|
- [核心模块详解](#核心模块详解)
|
||||||
|
- [技术栈](#技术栈)
|
||||||
|
- [环境变量](#环境变量)
|
||||||
|
- [启动方式](#启动方式)
|
||||||
|
- [API 层](#api-层)
|
||||||
|
- [Mock 数据](#mock-数据)
|
||||||
|
- [各项目功能对比](#各项目功能对比)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目概览
|
||||||
|
|
||||||
|
本项目是一个**多模块前后分离架构**的企业级应用,包含 6 个 Vue 前端项目和一个 Java 微服务后端。
|
||||||
|
|
||||||
|
### 前端项目列表
|
||||||
|
|
||||||
|
| 项目 | 访问路径 | 描述 |
|
||||||
|
|------|----------|------|
|
||||||
|
| txw-gxzx-web | /view/gxzx | 可信碳信息网(功能最丰富) |
|
||||||
|
| txw-mhzc-web | /view/mhzc | 苗栗县综合平台 |
|
||||||
|
| txw-tzzx-web | /view/tzzx | Topfans 投资资讯 |
|
||||||
|
| txw-ytzx-web | /view/ytzx | Topfans 媒体中心 |
|
||||||
|
| txw-yygl-web | /view/yygl | 运营管理系统 |
|
||||||
|
| txw-kxtfwzx-web | /view/kxtfwzx | 综合服务信息中心 |
|
||||||
|
|
||||||
|
### 技术架构
|
||||||
|
|
||||||
|
- **框架**: Vue 2.6 + Vue Router 3 + Vuex 3
|
||||||
|
- **UI 组件库**: TDesign Vue 1.4.0 + @gtff/tdesign-gt-vue
|
||||||
|
- **构建工具**: Vue CLI 4.5
|
||||||
|
- **HTTP 客户端**: Axios
|
||||||
|
- **图表库**: ECharts 5.5
|
||||||
|
- **样式预处理**: LESS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
<project>/
|
||||||
|
├── public/ # 静态资源(不经过 webpack 处理)
|
||||||
|
│ ├── index.html # 生产环境 HTML 模板
|
||||||
|
│ └── local.html # 本地开发 HTML 模板
|
||||||
|
├── src/
|
||||||
|
│ ├── core/ # 核心初始化模块(所有项目共享)
|
||||||
|
│ │ ├── index.js # Vue 插件注册、TDesign 组件库初始化
|
||||||
|
│ │ ├── request.js # Axios 封装(拦截器 + 4 种 fetch 函数)
|
||||||
|
│ │ └── download.js # 文件下载工具(含 IE 兼容)
|
||||||
|
│ ├── pages/
|
||||||
|
│ │ └── index/ # 主页面模块(所有业务代码)
|
||||||
|
│ │ ├── main.js # 入口文件
|
||||||
|
│ │ ├── app.vue # 根组件
|
||||||
|
│ │ ├── api/ # API 接口定义
|
||||||
|
│ │ ├── assets/ # 模块资源(图片、字体等)
|
||||||
|
│ │ ├── components/ # 业务组件
|
||||||
|
│ │ ├── config/ # 顶部/侧边栏配置
|
||||||
|
│ │ ├── router/ # 路由定义
|
||||||
|
│ │ │ ├── index.js # VueRouter 实例创建
|
||||||
|
│ │ │ └── routes.js # 路由表定义(懒加载)
|
||||||
|
│ │ ├── store/ # Vuex 状态管理
|
||||||
|
│ │ │ ├── index.js # Store 实例
|
||||||
|
│ │ │ └── modules/ # 状态模块
|
||||||
|
│ │ ├── styles/ # 模块级样式
|
||||||
|
│ │ └── views/ # 页面组件
|
||||||
|
│ ├── styles/ # 全局共享样式
|
||||||
|
│ │ ├── index.less
|
||||||
|
│ │ ├── index.css
|
||||||
|
│ │ ├── variables.less # LESS 变量(主题色、尺寸等)
|
||||||
|
│ │ └── span-btn.less
|
||||||
|
│ └── utils/ # 全局工具函数
|
||||||
|
│ ├── auth.js # Token 管理
|
||||||
|
│ ├── calc.js # 税费计算
|
||||||
|
│ ├── dateUtil.js # 日期工具
|
||||||
|
│ ├── numberUtils.js # 数字格式化
|
||||||
|
│ ├── eventBus.js # 事件总线
|
||||||
|
│ └── urlParams.js # URL 参数解析
|
||||||
|
├── mock/ # Mock 数据(开发环境)
|
||||||
|
│ ├── index.js # Mock 入口
|
||||||
|
│ ├── get/ # GET 请求 Mock
|
||||||
|
│ └── post/ # POST 请求 Mock
|
||||||
|
├── .env # 默认环境变量
|
||||||
|
├── .env.development # 开发环境变量
|
||||||
|
├── .env.production # 生产环境变量
|
||||||
|
├── .env.test # 测试环境变量
|
||||||
|
├── babel.config.js # Babel 转译配置
|
||||||
|
├── vue.config.js # Vue CLI Webpack 配置
|
||||||
|
├── proxy.js # 开发服务器代理配置
|
||||||
|
├── package.json
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 目录用途说明
|
||||||
|
|
||||||
|
| 目录/文件 | 用途 |
|
||||||
|
|-----------|------|
|
||||||
|
| `public/` | 不经过 webpack 处理的静态资源,直接复制到输出目录 |
|
||||||
|
| `src/core/` | 核心初始化代码,包括 Axios 封装、下载工具 |
|
||||||
|
| `src/pages/index/` | 所有业务代码,API、组件、视图、路由、状态 |
|
||||||
|
| `src/styles/` | 全局样式和 LESS 变量 |
|
||||||
|
| `src/utils/` | 与业务无关的纯工具函数 |
|
||||||
|
| `mock/` | 前端 Mock 数据,用于独立开发 |
|
||||||
|
| `.env.*` | 环境差异化配置 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心模块详解
|
||||||
|
|
||||||
|
### 1. 入口文件 (`src/pages/index/main.js`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. Polyfill 引入
|
||||||
|
import 'core-js/stable';
|
||||||
|
import 'regenerator-runtime/runtime';
|
||||||
|
|
||||||
|
// 2. 核心模块初始化
|
||||||
|
import core from '@/core/index.js';
|
||||||
|
|
||||||
|
// 3. Vue 实例创建
|
||||||
|
import Vue from 'vue';
|
||||||
|
import App from './app.vue';
|
||||||
|
|
||||||
|
// 4. 路由和状态管理
|
||||||
|
import router from './router/index.js';
|
||||||
|
import store from './store/index.js';
|
||||||
|
|
||||||
|
// 5. 创建并挂载 Vue 实例
|
||||||
|
new Vue({
|
||||||
|
router,
|
||||||
|
store,
|
||||||
|
render: h => h(App)
|
||||||
|
}).$mount('#app');
|
||||||
|
```
|
||||||
|
|
||||||
|
**主要职责**:
|
||||||
|
- 初始化 polyfill
|
||||||
|
- 注册 Vue 插件和全局组件
|
||||||
|
- 整合 Router 和 Vuex Store
|
||||||
|
- 设置文档标题
|
||||||
|
- 注册全局事件(登录/登出)
|
||||||
|
|
||||||
|
### 2. Axios 封装 (`src/core/request.js`)
|
||||||
|
|
||||||
|
提供 4 种请求方法:
|
||||||
|
|
||||||
|
| 函数 | 用途 | BaseURL | 特殊 Header |
|
||||||
|
|------|------|---------|-------------|
|
||||||
|
| `fetch` | 普通业务 API | `API_PREFIX` | 无 |
|
||||||
|
| `fetchSso` | SSO 服务 | `SSO_PREFIX` | `TOKEN-TYPE: YW` |
|
||||||
|
| `fetchSso1` | SSO 服务 | `SSO_PREFIX` | `TOKEN-TYPE: STAR` |
|
||||||
|
| `fetchNoPrefix` | 无前缀调用 | 空 | 无 |
|
||||||
|
|
||||||
|
**请求拦截器**:
|
||||||
|
- 自动添加时间戳防止缓存
|
||||||
|
- GET 请求参数映射到 URL query string
|
||||||
|
|
||||||
|
**响应拦截器**:
|
||||||
|
- `code !== 1` 时显示错误信息
|
||||||
|
- `code === 401` 时跳转登录页
|
||||||
|
- 统一错误处理
|
||||||
|
|
||||||
|
### 3. 路由 (`src/pages/index/router/`)
|
||||||
|
|
||||||
|
**`index.js`** - VueRouter 实例:
|
||||||
|
```javascript
|
||||||
|
const router = new VueRouter({
|
||||||
|
mode: 'history', // 使用 History 模式
|
||||||
|
base: `${window.STATIC_ENV_CONFIG.ROUTER_PREFIX}/`, // 基础路径
|
||||||
|
routes: require('./routes').default
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**`routes.js`** - 路由表(懒加载):
|
||||||
|
```javascript
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
name: 'login',
|
||||||
|
component: () => import(/* webpackChunkName: "login" */ '@/pages/index/views/login/login.vue')
|
||||||
|
},
|
||||||
|
// ...其他路由
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 状态管理 (`src/pages/index/store/`)
|
||||||
|
|
||||||
|
**`index.js`** - Store 实例创建:
|
||||||
|
```javascript
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Vuex from 'vuex';
|
||||||
|
import user from './modules/user.js';
|
||||||
|
import mxuser from './modules/mxuser.js';
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
export default new Vuex.Store({
|
||||||
|
modules: {
|
||||||
|
user,
|
||||||
|
mxuser
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**模块结构**:
|
||||||
|
- `modules/user.js` - 用户信息、登录状态
|
||||||
|
- `modules/mxuser.js` - MX 用户状态
|
||||||
|
- 各业务模块的 store 在各自目录下
|
||||||
|
|
||||||
|
### 5. 文件下载 (`src/core/download.js`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 普通浏览器下载
|
||||||
|
download(url, filename) {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// IE 兼容下载
|
||||||
|
downloadForIE(url, filename) {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.style.display = 'none';
|
||||||
|
iframe.src = url;
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
### 核心依赖
|
||||||
|
|
||||||
|
| 技术 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| vue | ~2.6.11 | 前端框架 |
|
||||||
|
| vue-router | 3.2.0 | 路由管理 |
|
||||||
|
| vuex | ^3.4.0 | 状态管理 |
|
||||||
|
| tdesign-vue | 1.4.0 | TDesign UI 组件库 |
|
||||||
|
| @gtff/tdesign-gt-vue | 1.4.0 | 定制 TDesign 组件 |
|
||||||
|
| @gt4/common-front | 2.0.113 | 公共前端工具库 |
|
||||||
|
|
||||||
|
### HTTP 与数据处理
|
||||||
|
|
||||||
|
| 技术 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| axios | ^0.21.1 | HTTP 客户端 |
|
||||||
|
| dayjs | ^1.10.4 | 日期处理(轻量级) |
|
||||||
|
| lodash-es | ^4.17.21 | JavaScript 工具库 |
|
||||||
|
|
||||||
|
### 可视化
|
||||||
|
|
||||||
|
| 技术 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| echarts | ^5.5.0 | 图表库 |
|
||||||
|
| vue-echarts | ^6.6.9 | ECharts Vue 封装 |
|
||||||
|
| vue-pdf | ^4.3.0 | PDF 预览 |
|
||||||
|
|
||||||
|
### 构建与开发
|
||||||
|
|
||||||
|
| 技术 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| @vue/cli-service | ~4.5.0 | Vue CLI 服务 |
|
||||||
|
| @wecity/static-env-config | 1.0.32 | 环境配置注入 |
|
||||||
|
| mockjs | ^1.1.0 | Mock 数据生成 |
|
||||||
|
| less | ^4.1.3 | LESS 预处理器 |
|
||||||
|
|
||||||
|
### 图标
|
||||||
|
|
||||||
|
| 技术 | 版本 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| tdesign-icons-vue | 0.0.8 | TDesign 图标 |
|
||||||
|
| @fortawesome/fontawesome-free | ^7.0.1 | Font Awesome 图标 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
### `.env` 默认配置
|
||||||
|
|
||||||
|
```
|
||||||
|
VUE_APP_ENV=dev
|
||||||
|
VUE_APP_MODEL=local
|
||||||
|
VUE_APP_CDN_PATH=/view/<project>
|
||||||
|
VUE_APP_ROUTER_BASE=/view/<project>
|
||||||
|
VUE_APP_API_BASE_URL=
|
||||||
|
VUE_APP_API_TIMEOUT=15000
|
||||||
|
VUE_APP_CSS_EXTRACT=false
|
||||||
|
```
|
||||||
|
|
||||||
|
### `.env.development` 开发配置
|
||||||
|
|
||||||
|
```
|
||||||
|
VUE_APP_ENV=dev
|
||||||
|
VUE_APP_MODEL=local
|
||||||
|
VUE_APP_CDN_PATH=/view/<project>
|
||||||
|
VUE_APP_ROUTER_BASE=/view/<project>
|
||||||
|
VUE_APP_API_BASE_URL=
|
||||||
|
VUE_APP_DEV_SERVER_PORT=9002
|
||||||
|
VUE_APP_MOCK=true
|
||||||
|
VUE_APP_AUTO_ROUTER=false
|
||||||
|
```
|
||||||
|
|
||||||
|
### `.env.production` 生产配置
|
||||||
|
|
||||||
|
```
|
||||||
|
VUE_APP_ENV=prod
|
||||||
|
VUE_APP_MODEL=online
|
||||||
|
VUE_APP_CDN_PATH=/view/<project>
|
||||||
|
VUE_APP_ROUTER_BASE=/view/<project>
|
||||||
|
VUE_APP_API_BASE_URL=
|
||||||
|
VUE_APP_AUTO_ROUTER=false
|
||||||
|
```
|
||||||
|
|
||||||
|
### `.env.test` 测试配置
|
||||||
|
|
||||||
|
```
|
||||||
|
NODE_ENV=production
|
||||||
|
VUE_APP_ENV=beta
|
||||||
|
VUE_APP_MODEL=online
|
||||||
|
VUE_APP_CDN_PATH=/test
|
||||||
|
VUE_APP_ROUTER_BASE=/test
|
||||||
|
VUE_APP_API_BASE_URL=/test/api
|
||||||
|
VUE_APP_API_BASE_URL2=/test/api
|
||||||
|
```
|
||||||
|
|
||||||
|
### 变量说明
|
||||||
|
|
||||||
|
| 变量 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `VUE_APP_ENV` | 环境标识 | dev / prod / beta |
|
||||||
|
| `VUE_APP_MODEL` | 运行模式 | local(本地)/ online(线上) |
|
||||||
|
| `VUE_APP_CDN_PATH` | 静态资源基础路径 | /view/gxzx |
|
||||||
|
| `VUE_APP_ROUTER_BASE` | Vue Router 基础路径 | /view/gxzx |
|
||||||
|
| `VUE_APP_API_BASE_URL` | API 请求前缀 | 空(使用网关) |
|
||||||
|
| `VUE_APP_DEV_SERVER_PORT` | 开发服务器端口 | 9002 |
|
||||||
|
| `VUE_APP_MOCK` | 是否启用 Mock 数据 | true / false |
|
||||||
|
| `VUE_APP_AUTO_ROUTER` | 是否启用自动路由 | false |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 启动方式
|
||||||
|
|
||||||
|
### 前置条件
|
||||||
|
|
||||||
|
- Node.js >= 14.x
|
||||||
|
- Yarn 或 npm
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd txw-gxzx-web # 进入项目目录
|
||||||
|
yarn install # 安装依赖(推荐)
|
||||||
|
# 或 npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开发模式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 普通开发模式
|
||||||
|
yarn dev
|
||||||
|
|
||||||
|
# 启用 Mock 数据模式(无需后端启动)
|
||||||
|
yarn dev:mock
|
||||||
|
|
||||||
|
# 使用 npm
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建打包
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 生产环境打包
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
# 开发环境打包
|
||||||
|
yarn build:site:dev
|
||||||
|
|
||||||
|
# 测试环境打包
|
||||||
|
yarn build:site:test
|
||||||
|
|
||||||
|
# 指定环境打包
|
||||||
|
yarn build:site --mode development
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码检查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ESLint 检查
|
||||||
|
yarn lint
|
||||||
|
|
||||||
|
# 样式检查
|
||||||
|
yarn lint:style
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开发服务器
|
||||||
|
|
||||||
|
默认端口:`9002`(可通过 `VUE_APP_DEV_SERVER_PORT` 修改)
|
||||||
|
|
||||||
|
代理配置(`proxy.js`):
|
||||||
|
```javascript
|
||||||
|
proxy: {
|
||||||
|
'/sso': { target: 'http://10.23.20.13:94/' },
|
||||||
|
'/mhzc': { target: 'http://10.23.20.13:94/' },
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 层
|
||||||
|
|
||||||
|
### API 定义示例
|
||||||
|
|
||||||
|
在 `src/pages/index/api/` 目录下定义接口:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// login.js
|
||||||
|
import { fetch, fetchSso } from '@/core/request.js';
|
||||||
|
|
||||||
|
export const login = (data) => fetch.post('/user/login', data);
|
||||||
|
export const logout = () => fetchSso.post('/sso/logout');
|
||||||
|
export const getUserInfo = () => fetch.get('/user/info');
|
||||||
|
```
|
||||||
|
|
||||||
|
### API 调用方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { login, getUserInfo } from '../api/login.js';
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
login({ username: 'admin', password: '123456' })
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === 1) {
|
||||||
|
// 登录成功
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
getUserInfo()
|
||||||
|
.then(res => console.log(res.data));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 各项目 API 文件
|
||||||
|
|
||||||
|
| 项目 | API 文件 |
|
||||||
|
|------|----------|
|
||||||
|
| txw-gxzx-web | login.js, common.js, cjjpwh.js, ggwhglHtgl/index.js, gxzx/index.js, htgl.js, lsjr.js, lsjy.js, tjzsym.js, yhjfzsym.js |
|
||||||
|
| txw-mhzc-web | login.js, ggwhglHtgl/index.js, gxzx/index.js, htgl.js, yhzx/index.js |
|
||||||
|
| txw-tzzx-web | login.js, cjjpwh.js, common.js, ggwhglHtgl/index.js, htgl.js, tjzsym.js, yhjfzsym.js |
|
||||||
|
| txw-ytzx-web | login.js, cjjpwh.js, common.js, ggwhglHtgl/index.js, htgl.js, tjzsym.js, yhjfzsym.js |
|
||||||
|
| txw-yygl-web | login.js, cjjpwh.js, common.js, gggl/index.js, ggwhglHtgl/index.js, gxzx/index.js, htgl.js, lscp.js, tjzsym.js, yhjfzsym.js |
|
||||||
|
| txw-kxtfwzx-web | login.js, cjjpwh.js, common.js, ggwhglHtgl/index.js, htgl.js, tjzsym.js, yhjfzsym.js |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mock 数据
|
||||||
|
|
||||||
|
### Mock 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
mock/
|
||||||
|
├── index.js # Mock 入口
|
||||||
|
├── get/ # GET 请求 Mock
|
||||||
|
│ ├── user_info.json # -> GET /user/info
|
||||||
|
│ └── user_list.json # -> GET /user/list
|
||||||
|
└── post/ # POST 请求 Mock
|
||||||
|
├── user_login.json # -> POST /user/login
|
||||||
|
└── user_logout.json # -> POST /user/logout
|
||||||
|
```
|
||||||
|
|
||||||
|
### 文件命名规则
|
||||||
|
|
||||||
|
Mock 文件名中的双下划线 `__` 会被映射为路径斜杠 `/`:
|
||||||
|
|
||||||
|
| 文件名 | 映射路径 |
|
||||||
|
|--------|----------|
|
||||||
|
| `user_info.json` | `/user/info` |
|
||||||
|
| `user_bulk__delete.json` | `/user/bulk_delete` |
|
||||||
|
| `admin_role_list.json` | `/admin/role/list` |
|
||||||
|
|
||||||
|
### 启用 Mock
|
||||||
|
|
||||||
|
方式一:修改 `.env.development`
|
||||||
|
```
|
||||||
|
VUE_APP_MOCK=true
|
||||||
|
```
|
||||||
|
|
||||||
|
方式二:使用 dev:mock 命令
|
||||||
|
```bash
|
||||||
|
yarn dev:mock
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock 数据示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// mock/post/user_login.json
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"msg": "登录成功",
|
||||||
|
"data": {
|
||||||
|
"token": "mock_token_12345",
|
||||||
|
"userId": 1001,
|
||||||
|
"username": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 各项目功能对比
|
||||||
|
|
||||||
|
| 项目 | 主要功能模块 | 特点 |
|
||||||
|
|------|-------------|------|
|
||||||
|
| **txw-gxzx-web** | 可信碳信息、绿色金融(lsjr)、绿色交易(lsjy)、绿色信贷(lsxd)、企业出海(qych)、碳能力平台(gxnlpt) | 功能最丰富,业务模块最多 |
|
||||||
|
| **txw-mhzc-web** | 登录、首页(mhNewMain/home/home2)、用户中心(yhzx)、新闻中心、授权(authorize)、论坛(zxym)、企业入驻(qyrz/qy-rz) | 多首页适配,屏幕适配(1895x953) |
|
||||||
|
| **txw-tzzx-web** | 登录、首页 | 简单结构,仅基础功能 |
|
||||||
|
| **txw-ytzx-web** | 登录、首页 | 简单结构,仅基础功能 |
|
||||||
|
| **txw-yygl-web** | 登录、用户中心、公告管理(gggl)、轮播图(banner)、企业入驻(qyrz/qysp)、历史产品(lscp)、数据概览(tjzsym) | 运营管理功能 |
|
||||||
|
| **txw-kxtfwzx-web** | 登录、首页 | 简单结构,仅基础功能 |
|
||||||
|
|
||||||
|
### 各项目 Views 目录结构
|
||||||
|
|
||||||
|
**txw-gxzx-web**:
|
||||||
|
```
|
||||||
|
views/gxzx/ # 可信碳信息
|
||||||
|
views/lsjr/ # 绿色金融
|
||||||
|
views/lsjy/ # 绿色交易
|
||||||
|
views/qych/ # 企业出海
|
||||||
|
views/transfer/ # 转让
|
||||||
|
```
|
||||||
|
|
||||||
|
**txw-mhzc-web**:
|
||||||
|
```
|
||||||
|
views/dddl/ # 订单
|
||||||
|
views/ggwhglHtgl/ # 公共管理
|
||||||
|
views/glxtSy/ # 管理平台首页
|
||||||
|
views/gxfb/ # 信息发布
|
||||||
|
views/gxnlpt/ # 能力平台
|
||||||
|
views/home/ # 首页
|
||||||
|
views/hyzt/ # 行业状态
|
||||||
|
views/login/ # 登录
|
||||||
|
views/lsjy/ # 历史交易
|
||||||
|
views/qy-rz/ # 企业入驻
|
||||||
|
views/qych/ # 企业出海
|
||||||
|
views/qyrz/ # 企业认证
|
||||||
|
views/zx/ # 资讯
|
||||||
|
```
|
||||||
|
|
||||||
|
**txw-yygl-web**:
|
||||||
|
```
|
||||||
|
views/banner/ # 轮播图管理
|
||||||
|
views/ggwhglHtgl/ # 公共管理
|
||||||
|
views/glxtSy/ # 管理平台首页
|
||||||
|
views/gxfb/ # 信息发布
|
||||||
|
views/login/ # 登录
|
||||||
|
views/lscp/ # 历史产品
|
||||||
|
views/lsjy/ # 历史交易
|
||||||
|
views/qyrz/ # 企业入驻
|
||||||
|
views/qysp/ # 企业审批
|
||||||
|
views/yhgl/ # 用户管理
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 公共组件
|
||||||
|
|
||||||
|
| 组件 | 路径 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| AddEditTable | `components/AddEditTable/` | 表格增删改一体 |
|
||||||
|
| all-select | `components/all-select/` | 自定义多选组件 |
|
||||||
|
| common-breadcrumb | `components/common-breadcrumb/` | 面包屑导航 |
|
||||||
|
| common-confirm | `components/common-confirm/` | 确认对话框 |
|
||||||
|
| commonCard | `components/commonCard/` | 卡片包装组件 |
|
||||||
|
| empty-placeholder | `components/empty-placeholder/` | 空状态占位 |
|
||||||
|
| footer | `components/footer/` | 页脚 |
|
||||||
|
| header-search | `components/header-search/` | 头部搜索 |
|
||||||
|
| ImportDialog | `components/ImportDialog/` | 文件导入弹窗 |
|
||||||
|
| nav | `components/nav/` | 导航组件 |
|
||||||
|
| pdf | `components/pdf/` | PDF 预览组件 |
|
||||||
|
| sbbBottomSubmit | `components/sbbBottomSubmit/` | 底部提交按钮 |
|
||||||
|
| search-control-panel | `components/search-control-panel/` | 搜索面板 |
|
||||||
|
| workflow | `components/workflow/` | 工作流组件 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 工具函数
|
||||||
|
|
||||||
|
| 文件 | 函数 | 用途 |
|
||||||
|
|------|------|------|
|
||||||
|
| **auth.js** | `getAccessToken()` | 获取 Access Token |
|
||||||
|
| | `setToken(token)` | 设置 Token |
|
||||||
|
| | `removeToken()` | 清除 Token |
|
||||||
|
| **dateUtil.js** | `getQuarter(date)` | 获取日期所在季度 |
|
||||||
|
| | `getMonthStartEndDay(date)` | 获取月份开始结束日期 |
|
||||||
|
| | `getThisMonthRange()` | 获取本月日期范围 |
|
||||||
|
| **calc.js** | 税费计算相关 | 税费计算工具 |
|
||||||
|
| **numberUtils.js** | 数字处理相关 | 数字格式化工具 |
|
||||||
|
| **eventBus.js** | `EventBus.$on()` | 监听事件 |
|
||||||
|
| | `EventBus.$emit()` | 触发事件 |
|
||||||
|
| **urlParams.js** | URL 参数解析 | 获取 URL 参数 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 部署说明
|
||||||
|
|
||||||
|
### 静态资源路径
|
||||||
|
|
||||||
|
每个项目部署后通过不同路径访问:
|
||||||
|
- `/view/gxzx` -> txw-gxzx-web
|
||||||
|
- `/view/mhzc` -> txw-mhzc-web
|
||||||
|
- `/view/tzzx` -> txw-tzzx-web
|
||||||
|
- `/view/ytzx` -> txw-ytzx-web
|
||||||
|
- `/view/yygl` -> txw-yygl-web
|
||||||
|
- `/view/kxtfwzx` -> txw-kxtfwzx-web
|
||||||
|
|
||||||
|
### 环境配置注入
|
||||||
|
|
||||||
|
构建时通过 `@wecity/static-env-config` 插件注入环境变量,生成 `env.config.js` 文件:
|
||||||
|
- 开发环境: `/view/<project>/env.config.js`
|
||||||
|
- 生产环境: `/view/<project>/env.config.js`
|
||||||
|
|
||||||
|
### Nginx 配置示例
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location /view/gxzx {
|
||||||
|
alias /usr/share/nginx/html/gxzx;
|
||||||
|
try_files $uri $uri/ /view/gxzx/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /view/mhzc {
|
||||||
|
alias /usr/share/nginx/html/mhzc;
|
||||||
|
try_files $uri $uri/ /view/mhzc/index.html;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### 1. 跨域问题
|
||||||
|
开发环境通过 `proxy.js` 配置代理解决。生产环境通过网关路由解决。
|
||||||
|
|
||||||
|
### 2. Mock 数据与实际接口切换
|
||||||
|
修改 `VUE_APP_MOCK` 环境变量即可切换。
|
||||||
|
|
||||||
|
### 3. 路由 404 问题
|
||||||
|
确保 Nginx 配置了 `try_files $uri $uri/ /index.html`,支持 History 模式的路由。
|
||||||
|
|
||||||
|
### 4. IE 浏览器兼容
|
||||||
|
已引入 `@wecity/tdesign-vue-ie` 和相关 polyfill,但部分功能可能受限。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*文档生成时间: 2026-04-03*
|
||||||
Loading…
Reference in New Issue
Block a user