| VITE_BASE_URL=http://parkshuyuan.test.hhrchina.com |
| VITE_NODE_ENV=development | |||||
| VITE_BASE_URL=http://parkshuyuan.test.hhrchina.com |
| VITE_NODE_ENV=production | |||||
| VITE_BASE_URL=http://parkshuyuan.test.hhrchina.com |
| # Logs | |||||
| logs | |||||
| *.log | |||||
| npm-debug.log* | |||||
| yarn-debug.log* | |||||
| yarn-error.log* | |||||
| pnpm-debug.log* | |||||
| lerna-debug.log* | |||||
| node_modules | |||||
| dist | |||||
| dist-ssr | |||||
| *.local | |||||
| # Editor directories and files | |||||
| .vscode/* | |||||
| !.vscode/extensions.json | |||||
| .idea | |||||
| .DS_Store | |||||
| *.suo | |||||
| *.ntvs* | |||||
| *.njsproj | |||||
| *.sln | |||||
| *.sw? |
| { | |||||
| "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] | |||||
| } |
| # Vue 3 + Vite | |||||
| This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. | |||||
| ## Recommended IDE Setup | |||||
| - [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8" /> | |||||
| <link rel="icon" type="image/svg+xml" href="/logo.png" /> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||||
| <title>书院</title> | |||||
| </head> | |||||
| <body> | |||||
| <div id="app"></div> | |||||
| <script type="module" src="/src/main.js"></script> | |||||
| </body> | |||||
| </html> |
| { | |||||
| "name": "SHUYUAN-TOWN", | |||||
| "private": true, | |||||
| "version": "0.0.0", | |||||
| "type": "module", | |||||
| "scripts": { | |||||
| "dev": "vite", | |||||
| "build": "vite build", | |||||
| "preview": "vite preview" | |||||
| }, | |||||
| "dependencies": { | |||||
| "amfe-flexible": "^2.2.1", | |||||
| "axios": "^1.4.0", | |||||
| "codemirror": "^5.65.14", | |||||
| "element-plus": "^2.3.4", | |||||
| "marked": "^3.0.8", | |||||
| "pinia": "^2.0.35", | |||||
| "pinia-plugin-persist": "^1.0.0", | |||||
| "postcss-pxtorem": "^6.0.0", | |||||
| "qs": "^6.11.2", | |||||
| "simplemde": "^1.11.2", | |||||
| "vant": "^4.6.2", | |||||
| "vue": "^3.2.47", | |||||
| "vue-router": "^4.1.6", | |||||
| "vue-scrollto": "^2.20.0" | |||||
| }, | |||||
| "devDependencies": { | |||||
| "@vitejs/plugin-vue": "^4.1.0", | |||||
| "sass": "^1.62.1", | |||||
| "unplugin-auto-import": "^0.15.3", | |||||
| "unplugin-vue-components": "^0.24.1", | |||||
| "vite": "^4.3.2", | |||||
| "vite-plugin-compression": "^0.5.1" | |||||
| } | |||||
| } |
| module.exports = { | |||||
| plugins: { | |||||
| // autoprefixer: { | |||||
| // overrideBrowserslist: [ | |||||
| // "Android 4.1", | |||||
| // "iOS 7.1", | |||||
| // "Chrome > 31", | |||||
| // "ff > 31", | |||||
| // "ie >= 8", | |||||
| // "last 10 versions", // 所有主流浏览器最近10版本用 | |||||
| // ], | |||||
| // grid: true, | |||||
| // }, | |||||
| // "postcss-pxtorem": { | |||||
| // rootValue: 192, | |||||
| // exclude: /node_modules\/vant|mobile/i, // 排除mobile和vant库 | |||||
| // propList: ["*"], | |||||
| // selectorBlackList: [".van-"], // 排除移动端使用了vant库 | |||||
| // }, | |||||
| "postcss-pxtorem": { | |||||
| rootValue: 37.5, | |||||
| exclude: /node_modules\/element-plus|pc/i, // 排除pc | |||||
| propList: ["*"], | |||||
| }, | |||||
| }, | |||||
| }; |
| <template> | |||||
| <template v-if="!isMobile"> | |||||
| <StickBlock /> | |||||
| <template v-if="!loading"> | |||||
| <TopNav :logo="homeData.logo" /> | |||||
| <div class="main_content"> | |||||
| <Banner :banner="homeData.topBanner"></Banner> | |||||
| <router-view></router-view> | |||||
| </div> | |||||
| <FooterInfo /> | |||||
| </template> | |||||
| </template> | |||||
| <template v-else> | |||||
| <PageBack /> | |||||
| <MobileStickBlock></MobileStickBlock> | |||||
| <template v-if="!loading"> | |||||
| <MobileTopNav :logo="homeData.logo" /> | |||||
| <MobileBanner :banner="homeData.topBanner" /> | |||||
| <MobileTipDialog ref="tipRef"></MobileTipDialog> | |||||
| <router-view></router-view> | |||||
| </template> | |||||
| </template> | |||||
| </template> | |||||
| <script setup> | |||||
| import TopNav from "@/components/pc/TopNav.vue"; | |||||
| import Banner from "@/components/pc/Banner.vue"; | |||||
| import FooterInfo from "@/components/pc/FooterInfo.vue"; | |||||
| import StickBlock from "@/components/pc/StickBlock.vue"; | |||||
| import MobileBanner from "@/components/mobile/MBanner.vue"; | |||||
| import MobileTopNav from "@/components/mobile/MTopNav.vue"; | |||||
| import MobileTipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| import MobileStickBlock from "@/components/mobile/MStickBlock.vue"; | |||||
| import PageBack from "@/components/mobile/PageBack.vue"; | |||||
| const isMobile = /Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(navigator.userAgent); | |||||
| let homeData = ref({}); | |||||
| const loading = ref(true); | |||||
| import { getHomeData } from "./views/pc/home/home"; | |||||
| import { onMounted, ref } from "vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| const { getData } = getHomeData(); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| homeData = await getData(); | |||||
| homeStore.homeData.value = homeData; | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .main_content { | |||||
| min-height: 200px; | |||||
| } | |||||
| </style> |
| /** | |||||
| * api接口统一管理 | |||||
| */ | |||||
| import {get, post } from "../utils/request"; | |||||
| // 首页-获取详情 | |||||
| export const getAreaData = () => get("/areaInfoManagement/getAreaData"); | |||||
| // 增加官网浏览量 | |||||
| export const updateAreaInfoManagementPageView = p => | |||||
| post(`/areaInfoManagement/updateAreaInfoManagementPageView/${p}`); | |||||
| // 获取最近那一个编辑或者上架的招商载体 | |||||
| export const getRegistrationPackageByFirst = () => | |||||
| get("/registrationPackage/getRegistrationPackageByFirst"); | |||||
| // 获取全部产业聚集 | |||||
| export const getAreaIndustrialAllocationList = () => | |||||
| get("/areaIndustrialAllocation/getAreaIndustrialAllocationList"); | |||||
| // 获取全部招商载体 | |||||
| export const getRegistrationPackageList = () => | |||||
| get("/registrationPackage/getRegistrationPackageList"); | |||||
| // 获取全部企业链家 | |||||
| export const getEnterpriseHomeLinkList = () => get("/enterpriseHomeLink/getEnterpriseHomeLinkList"); | |||||
| // 获取全部招商项目 | |||||
| export const getAttractInvestmentProjectList = () => | |||||
| get("/attractInvestmentProject/getAttractInvestmentProjectList"); | |||||
| // 申请入驻接口 | |||||
| export const addEnter = p => | |||||
| post(`/enter/addEnter`, p, { | |||||
| headers: { | |||||
| "Content-Type": "application/json;charset=UTF-8", | |||||
| }, | |||||
| }); | |||||
| // 获取全部政策 | |||||
| export const getReleasePolicyList = p => get(`/releasePolicy/getReleasePolicyList`, p); | |||||
| export const getReleasePolicyById = p => get(`/releasePolicy/getReleasePolicyById`, p); | |||||
| // 获取某个实体属性状态列表 | |||||
| export const getPickListByKey = p => get(`/common/getPickListByKey`, p); | |||||
| // 增加浏览量 | |||||
| export const updateReleasePolicyPageView = p => | |||||
| post(`/releasePolicy/updateReleasePolicyPageView/${p}`); | |||||
| export const getContactInfoConfig = p => get(`/contactInfoConfig/getContactInfoConfigByOne`, p); |
| <template> | |||||
| <van-swipe class="my-swipe" :autoplay="3000" indicator-color="white"> | |||||
| <van-swipe-item v-for="(item, index) in propsData.banner" :key="index"> | |||||
| <img :src="formatImg(item)" alt="banner图片" /> | |||||
| </van-swipe-item> | |||||
| </van-swipe> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| banner: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .my-swipe .van-swipe-item { | |||||
| height: 150px; | |||||
| img { | |||||
| @include font(12px, $color-black); | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="block" @click="showTipInfo"> | |||||
| <div class="block-item"> | |||||
| <img src="@/assets/phone.png" alt="电话咨询" /> | |||||
| <span>电话咨询</span> | |||||
| </div> | |||||
| <div class="block-item"> | |||||
| <img src="@/assets/code.png" alt="扫码关注" /> | |||||
| <span>扫码关注</span> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRef"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import TipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| const tipRef = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRef.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .block { | |||||
| position: fixed; | |||||
| right: 0; | |||||
| bottom: 100px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| z-index: 1008; | |||||
| border-radius: 24px; | |||||
| padding: 20px 0; | |||||
| @include border-box; | |||||
| &-item { | |||||
| @include size(52px, auto); | |||||
| @include font(10px, $color-white); | |||||
| @include flex(column, center, center, nowrap); | |||||
| border-top: 1px solid rgba(255, 255, 255, 1); | |||||
| padding: 10px 0; | |||||
| @include border-box; | |||||
| cursor: pointer; | |||||
| img { | |||||
| height: 25px; | |||||
| margin-bottom: 4px; | |||||
| } | |||||
| } | |||||
| &-item:last-child { | |||||
| border-bottom: 1px solid rgba(255, 255, 255, 1); | |||||
| } | |||||
| } | |||||
| </style> |
| <!-- 导航 --> | |||||
| <template> | |||||
| <div class="header"> | |||||
| <van-sticky> | |||||
| <div class="wrap"> | |||||
| <section class="wrap_left"> | |||||
| <img v-if="propsData.logo" :src="formatImg(logoArr[0])" alt="logo" /> | |||||
| <div class="title"> | |||||
| <span class="ch">浦东新区书院镇</span> | |||||
| <span class="en">SHUYUAN TOWN</span> | |||||
| </div> | |||||
| </section> | |||||
| <van-dropdown-menu class="wrap_right" ref="menuRef"> | |||||
| <van-dropdown-item> | |||||
| <template #title> | |||||
| <van-icon name="wap-nav" size="26px" /> | |||||
| </template> | |||||
| <router-link | |||||
| v-for="item in nav" | |||||
| :key="item.name" | |||||
| :to="item.path" | |||||
| class="routers" | |||||
| @click="goPath(item.name)" | |||||
| > | |||||
| {{ item.meta.title }} | |||||
| </router-link> | |||||
| </van-dropdown-item> | |||||
| </van-dropdown-menu> | |||||
| </div> | |||||
| </van-sticky> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { useRouter } from "vue-router"; //1.引入路由 | |||||
| const router = useRouter(); //2.实例化路由 | |||||
| const nav = router.getRoutes().filter(item => item.meta.isNav && item.meta.type === "mobile"); | |||||
| const menuRef = ref(null); | |||||
| const goPath = name => { | |||||
| router.push({ | |||||
| name, | |||||
| }); | |||||
| menuRef.value.close(); | |||||
| }; | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| let logoArr = ref([]); | |||||
| const propsData = defineProps({ | |||||
| logo: { | |||||
| type: String, | |||||
| }, | |||||
| }); | |||||
| logoArr.value = propsData.logo ? JSON.parse(propsData.logo) : []; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| //@import url(); 引入公共css类 | |||||
| .header { | |||||
| // @include size(100%, 48px); | |||||
| // margin: 0 auto; | |||||
| // color: $color-black; | |||||
| // background: #fff; | |||||
| // @include border-box; | |||||
| } | |||||
| .wrap { | |||||
| padding: 10px 12px; | |||||
| @include size(100%, 48px); | |||||
| background: #fff; | |||||
| @include flex(row, space-between, center, wrap); | |||||
| @include border-box; | |||||
| .wrap_left { | |||||
| @include flex(row, center, center, wrap); | |||||
| img { | |||||
| @include size(auto, 30px); | |||||
| margin-right: 10px; | |||||
| } | |||||
| .title { | |||||
| @include size(auto, 30px); | |||||
| @include flex(column, space-around, flex-start, nowrap); | |||||
| } | |||||
| & .ch { | |||||
| @include font(14px, $color-black); | |||||
| font-weight: bold; | |||||
| } | |||||
| & .en { | |||||
| @include font(12px, $color-black); | |||||
| } | |||||
| } | |||||
| .wrap_right { | |||||
| @include size(auto, 100%); | |||||
| @include flex(row, flex-end, center, wrap); | |||||
| .routers { | |||||
| @include size(90%, auto); | |||||
| margin: auto; | |||||
| padding: 10px 0; | |||||
| @include font(14px, $color-black); | |||||
| @include flex(row, center, center, nowrap); | |||||
| text-align: center; | |||||
| // border-bottom: 1px solid rgba(179, 179, 179, 1); | |||||
| @include border-box; | |||||
| } | |||||
| .router-link-active { | |||||
| color: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| .van-dropdown-item__content > .routers + .routers { | |||||
| border-top: 1px solid rgba(179, 179, 179, 1); | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| :deep() { | |||||
| .van-dropdown-menu__bar { | |||||
| height: 100%; | |||||
| box-shadow: none; | |||||
| } | |||||
| .van-dropdown-menu__title:after { | |||||
| display: none; | |||||
| } | |||||
| .van-dropdown-item { | |||||
| top: 48px; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="page-back" v-if="$route.path !== '/m_home'"> | |||||
| <div class="icon-back" @click="goBack"> | |||||
| <img src="@/assets/page-back.png" /> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { useRoute, useRouter } from "vue-router"; //1.引入路由 | |||||
| const $router = useRouter(); //2.实例化路由 | |||||
| const $route = useRoute(); //2.实例化路由 | |||||
| const goBack = () => { | |||||
| if ($route.path == "/m_preferential-policy-detail") { | |||||
| $router.go(-1); | |||||
| } else { | |||||
| $router.push({ | |||||
| path: "/", | |||||
| }); | |||||
| } | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .icon-back { | |||||
| width: 38px; | |||||
| height: 38px; | |||||
| position: fixed; | |||||
| left: 10px; | |||||
| top: 48px; | |||||
| z-index: 999; | |||||
| img { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <van-dialog v-model:show="dialogVisible" :showConfirmButton="false"> | |||||
| <template #title> | |||||
| <div class="head"> | |||||
| <van-icon name="cross" size="20px" @click="dialogVisible = false" /> | |||||
| </div> | |||||
| <div>立即咨询</div> | |||||
| </template> | |||||
| <div class="dialog"> | |||||
| <div class="dialog-item"> | |||||
| <span class="dialog-item-title">电话咨询</span> | |||||
| <div class="phone"> | |||||
| <p v-if="contract.mobileOne">{{ contract.mobileOne }}</p> | |||||
| <p v-if="contract.mobileTwo">{{ contract.mobileTwo }}</p> | |||||
| <p v-if="contract.mobileThree">{{ contract.mobileThree }}</p> | |||||
| </div> | |||||
| </div> | |||||
| <div class="dialog-item" v-if="contract.qrCode.length > 0"> | |||||
| <span class="dialog-item-title">扫码咨询</span> | |||||
| <img :src="formatImg(contract.qrCode[0])" alt="" /> | |||||
| </div> | |||||
| <div class="dialog-item" v-if="contract.email"> | |||||
| <span class="dialog-item-title">邮箱</span> | |||||
| <span class="email">{{ contract.email }}</span> | |||||
| </div> | |||||
| </div> | |||||
| </van-dialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { getContactInfoConfig } from "@/apis/index"; | |||||
| import { toast, formatImg } from "@/utils/common.js"; | |||||
| import { onMounted, ref } from "vue"; | |||||
| const dialogVisible = ref(false); | |||||
| const handleClose = () => { | |||||
| dialogVisible.value = false; | |||||
| }; | |||||
| const showTip = () => { | |||||
| dialogVisible.value = true; | |||||
| }; | |||||
| defineExpose({ showTip, handleClose }); | |||||
| const contract = ref(); | |||||
| const getData = () => { | |||||
| getContactInfoConfig() | |||||
| .then(res => { | |||||
| if (res.data.status == 0) { | |||||
| contract.value = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| }) | |||||
| .catch(error => { | |||||
| console.log(error); | |||||
| }); | |||||
| }; | |||||
| onMounted(() => { | |||||
| getData(); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .head { | |||||
| text-align: right; | |||||
| padding: 0 10px; | |||||
| @include border-box; | |||||
| } | |||||
| .dialog { | |||||
| @include flex(column, flex-start, center, nowrap); | |||||
| padding-bottom: 20px; | |||||
| @include border-box; | |||||
| &-item { | |||||
| @include flex(column, flex-start, center, nowrap); | |||||
| &-title { | |||||
| @include font(14px, $color-black); | |||||
| font-weight: 400; | |||||
| margin: 12px 0; | |||||
| } | |||||
| .phone { | |||||
| @include font(14px, rgba(0, 153, 255, 1)); | |||||
| } | |||||
| p { | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| img { | |||||
| @include size(150px, 150px); | |||||
| } | |||||
| .email { | |||||
| @include font(14px, $color-black); | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <el-carousel :interval="5000" arrow="always"> | |||||
| <el-carousel-item v-for="(item, index) in propsData.banner" :key="index"> | |||||
| <img :src="formatImg(item)" alt="banner图片" /> | |||||
| </el-carousel-item> | |||||
| </el-carousel> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| banner: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .el-carousel--horizontal { | |||||
| height: 700px; | |||||
| min-width: $wrapWidth; | |||||
| // background: yellowgreen; | |||||
| } | |||||
| :deep() { | |||||
| .el-carousel__container { | |||||
| height: 100%; | |||||
| img { | |||||
| // background: pink; | |||||
| @include size(100%, 100%); | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <!-- 底部导航 --> | |||||
| <template> | |||||
| <el-row class="footer_box"> | |||||
| <div class="wrap_box"> | |||||
| <div class="nav_info"> | |||||
| <section class="nav"> | |||||
| <div class="title">浦东新区书院镇</div> | |||||
| <div class="navs"> | |||||
| <router-link v-for="item in nav" :key="item.name" :to="item.path"> | |||||
| {{ item.meta.title }} | |||||
| </router-link> | |||||
| </div> | |||||
| </section> | |||||
| <section class="footer_info"> | |||||
| <img v-if="qrCode" :src="formatImg(qrCode)" alt="" /> | |||||
| <div class="info"> | |||||
| <span>地址:{{ addressConfig }}</span> | |||||
| <span>电话:{{ mobile }}</span> | |||||
| <span>传真:{{ faxConfig }}</span> | |||||
| <span>邮箱:{{ email }}</span> | |||||
| </div> | |||||
| </section> | |||||
| </div> | |||||
| <div class="line"></div> | |||||
| <div class="bottom_info"> | |||||
| <span>版权所有 ©2023-现在</span> | |||||
| <span>{{ addressConfig }}</span> | |||||
| <span>沪CP畜2022025118号</span> | |||||
| <span>沪B2-20200177</span> | |||||
| <span>沪公网安备31010402001838号</span> | |||||
| </div> | |||||
| </div> | |||||
| </el-row> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| import { useRouter } from "vue-router"; //1.引入路由 | |||||
| const router = useRouter(); //2.实例化路由 | |||||
| const nav = router.getRoutes().filter(item => item.meta.isNav && item.meta.type === "pc"); | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| const qrCode = homeStore.contract.value.qrCode[0]; | |||||
| const email = homeStore.contract.value.email; | |||||
| const mobile = homeStore.contract.value.mobileOne; | |||||
| const faxConfig = homeStore.contract.value.faxConfig; | |||||
| const addressConfig = homeStore.contract.value.addressConfig; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| //@import url(); 引入公共css类 | |||||
| .footer_box { | |||||
| @include size(100%, 305Px); | |||||
| background: url(https://img.js.design/assets/img/64a77155c194a91b49b37dcc.jpg) no-repeat; | |||||
| background-size: 100% 100%; | |||||
| box-sizing: border-box; | |||||
| @include flex(row, center, center, wrap); | |||||
| } | |||||
| .wrap_box { | |||||
| width: 1200Px; | |||||
| } | |||||
| .nav_info { | |||||
| @include size(1200Px, 250Px); | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| // padding: 0 50Px; | |||||
| box-sizing: border-box; | |||||
| } | |||||
| .nav { | |||||
| @include border-box; | |||||
| .title { | |||||
| @include font(36Px, $color-white); | |||||
| margin-bottom: 54Px; | |||||
| } | |||||
| .navs { | |||||
| @include flex(row, flex-start, center, nowrap); | |||||
| margin: 0 auto; | |||||
| @include font(16Px, $color-white); | |||||
| a { | |||||
| @include font(16Px, $color-white); | |||||
| margin-right: 20Px; | |||||
| } | |||||
| // a:hover { | |||||
| // color: #99a9b8; | |||||
| // } | |||||
| // .router-link-active { | |||||
| // color: #99a9b8; | |||||
| // } | |||||
| } | |||||
| .navs > a + a { | |||||
| border-left: 1Px solid $color-white; | |||||
| padding-left: 20Px; | |||||
| } | |||||
| } | |||||
| .footer_info { | |||||
| @include size(auto, 170Px); | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| img { | |||||
| @include size(170Px, 170Px); | |||||
| margin-right: 10Px; | |||||
| } | |||||
| .info { | |||||
| @include size(auto, 170Px); | |||||
| @include font(16Px, $color-white); | |||||
| @include flex(column, space-between, flex-start, nowrap); | |||||
| > div { | |||||
| flex: 1; | |||||
| @include flex(column, center, flex-start, nowrap); | |||||
| span { | |||||
| margin-bottom: 4Px; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| .line { | |||||
| width: 100%; | |||||
| height: 1Px; | |||||
| background: $color-white; | |||||
| } | |||||
| .bottom_info { | |||||
| @include size(1200Px, 55Px); | |||||
| @include font(14Px, $color-white); | |||||
| font-weight: 500; | |||||
| // padding: 0 50Px; | |||||
| box-sizing: border-box; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="block" @click="showTipInfo"> | |||||
| <div class="block-item"> | |||||
| <img src="@/assets/phone.png" alt="电话咨询" /> | |||||
| <span>电话咨询</span> | |||||
| </div> | |||||
| <div class="block-item"> | |||||
| <img src="@/assets/code.png" alt="扫码关注" /> | |||||
| <span>扫码关注</span> | |||||
| </div> | |||||
| </div> | |||||
| <el-backtop :bottom="100"></el-backtop> | |||||
| <TipDialog ref="tipRefPC"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import TipDialog from "@/components/pc/TipDialogPC.vue"; | |||||
| const tipRefPC = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRefPC.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .block { | |||||
| position: fixed; | |||||
| right: 0; | |||||
| top: 200px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| z-index: 1008; | |||||
| border-radius: 45px; | |||||
| padding: 50px 0; | |||||
| @include border-box; | |||||
| &-item { | |||||
| @include size(100px, auto); | |||||
| @include font(16px, $color-white); | |||||
| @include flex(column, center, center, nowrap); | |||||
| border-top: 1px solid rgba(255, 255, 255, 1); | |||||
| padding: 10px 0; | |||||
| @include border-box; | |||||
| cursor: pointer; | |||||
| img { | |||||
| height: 60px; | |||||
| margin-bottom: 4px; | |||||
| } | |||||
| } | |||||
| &-item:last-child { | |||||
| border-bottom: 1px solid rgba(255, 255, 255, 1); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <el-dialog | |||||
| v-model="dialogVisible" | |||||
| title="立即咨询" | |||||
| :before-close="handleClose" | |||||
| center | |||||
| style="border-radius: 20px" | |||||
| > | |||||
| <div class="dialog" v-if="contract"> | |||||
| <div class="dialog-item"> | |||||
| <span class="dialog-item-title">电话咨询</span> | |||||
| <div class="phone"> | |||||
| <p v-if="contract.mobileOne">{{ contract.mobileOne }}</p> | |||||
| <p v-if="contract.mobileTwo">{{ contract.mobileTwo }}</p> | |||||
| <p v-if="contract.mobileThree">{{ contract.mobileThree }}</p> | |||||
| </div> | |||||
| </div> | |||||
| <div class="dialog-item" v-if="contract.qrCode.length > 0"> | |||||
| <span class="dialog-item-title">扫码咨询</span> | |||||
| <img :src="formatImg(contract.qrCode[0])" alt="" /> | |||||
| </div> | |||||
| <div class="dialog-item" v-if="contract.email"> | |||||
| <span class="dialog-item-title">邮箱</span> | |||||
| <span class="email">{{ contract.email }}</span> | |||||
| </div> | |||||
| </div> | |||||
| </el-dialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { getContactInfoConfig } from "@/apis/index"; | |||||
| import { toast, formatImg } from "@/utils/common.js"; | |||||
| import { onMounted, ref } from "vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| const dialogVisible = ref(false); | |||||
| const handleClose = () => { | |||||
| dialogVisible.value = false; | |||||
| }; | |||||
| const showTip = () => { | |||||
| dialogVisible.value = true; | |||||
| }; | |||||
| defineExpose({ showTip, handleClose }); | |||||
| const contract = ref(); | |||||
| const getData = () => { | |||||
| getContactInfoConfig() | |||||
| .then(res => { | |||||
| if (res.data.status == 0) { | |||||
| contract.value = res.data.data; | |||||
| homeStore.contract.value = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| }) | |||||
| .catch(error => { | |||||
| console.log(error); | |||||
| }); | |||||
| }; | |||||
| onMounted(() => { | |||||
| getData(); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .dialog { | |||||
| @include flex(row, space-between, flex-start, nowrap); | |||||
| &-item { | |||||
| width: 30%; | |||||
| @include flex(column, flex-start, center, nowrap); | |||||
| &-title { | |||||
| @include font(20px, $color-black); | |||||
| font-weight: 400; | |||||
| margin-bottom: 50px; | |||||
| } | |||||
| .phone { | |||||
| @include font(24px, rgba(0, 153, 255, 1)); | |||||
| } | |||||
| p { | |||||
| margin-bottom: 30px; | |||||
| } | |||||
| img { | |||||
| @include size(150px, 150px); | |||||
| } | |||||
| .email { | |||||
| @include font(24px, $color-black); | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <!-- 导航 --> | |||||
| <template> | |||||
| <div class="header"> | |||||
| <div class="wrap"> | |||||
| <section class="wrap_left"> | |||||
| <img v-if="propsData.logo" :src="formatImg(logoArr[0])" alt="logo" /> | |||||
| <div class="title"> | |||||
| <span class="ch">浦东新区书院镇</span> | |||||
| <span class="en">SHUYUAN TOWN</span> | |||||
| </div> | |||||
| </section> | |||||
| <section class="wrap_right"> | |||||
| <div> | |||||
| <router-link | |||||
| v-for="item in nav" | |||||
| :key="item.name" | |||||
| :to="item.path" | |||||
| :class="[item.name === 'P_ApplyForEntry' ? 'apply' : '']" | |||||
| > | |||||
| {{ item.meta.title }} | |||||
| </router-link> | |||||
| </div> | |||||
| </section> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { useRouter } from "vue-router"; //1.引入路由 | |||||
| const router = useRouter(); //2.实例化路由 | |||||
| const nav = router.getRoutes().filter(item => item.meta.isNav && item.meta.type === "pc"); | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| let logoArr = ref([]); | |||||
| const propsData = defineProps({ | |||||
| logo: { | |||||
| type: String, | |||||
| }, | |||||
| }); | |||||
| logoArr.value = propsData.logo ? JSON.parse(propsData.logo) : []; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| //@import url(); 引入公共css类 | |||||
| .header { | |||||
| @include size(100%, 100px); | |||||
| margin: 0 auto; | |||||
| color: $color-black; | |||||
| background: #fff; | |||||
| @include flex(row, center, center, wrap); | |||||
| @include border-box; | |||||
| } | |||||
| .wrap { | |||||
| min-width: $wrapWidth; | |||||
| @include size($wrapWidth, 100%); | |||||
| @include flex(row, space-between, center, wrap); | |||||
| .wrap_left { | |||||
| @include flex(row, center, center, wrap); | |||||
| img { | |||||
| @include size(auto, 50px); | |||||
| margin-right: 20px; | |||||
| } | |||||
| .title { | |||||
| @include size(auto, 50px); | |||||
| @include flex(column, space-around, flex-start, nowrap); | |||||
| } | |||||
| & .ch { | |||||
| @include font(16px, $color-black); | |||||
| font-weight: bold; | |||||
| } | |||||
| & .en { | |||||
| @include font(12px, $color-black); | |||||
| } | |||||
| } | |||||
| .wrap_right { | |||||
| height: 100%; | |||||
| @include flex(row, flex-end, center, wrap); | |||||
| & > div { | |||||
| height: 100%; | |||||
| @include flex(row, space-between, center, wrap); | |||||
| a { | |||||
| margin-right: 60px; | |||||
| @include font(20px, $color-black); | |||||
| font-weight: bold; | |||||
| @include flex(row, center, center, wrap); | |||||
| } | |||||
| a.apply { | |||||
| border-radius: 50px; | |||||
| background: rgba(0, 145, 255, 1); | |||||
| font-weight: normal; | |||||
| padding: 2px 12px; | |||||
| @include font(18px, $color-white); | |||||
| box-sizing: border-box; | |||||
| margin-right: 0; | |||||
| } | |||||
| :hover { | |||||
| color: rgba(0, 145, 255, 1); | |||||
| } | |||||
| .router-link-active { | |||||
| color: rgba(0, 145, 255, 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| .enterprise { | |||||
| @include size(160px, 40px); | |||||
| border: solid 1px rgba(255, 255, 255, 0.5); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| @include flex(row, center, center, wrap); | |||||
| img { | |||||
| @include size(20px, 20px); | |||||
| margin-right: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| import { createApp } from "vue"; | |||||
| import App from "./App.vue"; | |||||
| import router from "./router"; | |||||
| import store from "./store"; | |||||
| import "@/styles/reset.scss"; /*引入公共样式*/ | |||||
| import "amfe-flexible"; | |||||
| // main.js | |||||
| if (/Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(navigator.userAgent)) { | |||||
| // Vue.use(VueTouch, { name: "v-touch" }); | |||||
| // VueTouch.config.swipe = { | |||||
| // threshold: 50, | |||||
| // }; | |||||
| var oMeta = document.createElement("meta"); | |||||
| oMeta.content = | |||||
| "width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0, user-scalable=0"; | |||||
| oMeta.name = "viewport"; | |||||
| document.getElementsByTagName("head")[0].appendChild(oMeta); | |||||
| } | |||||
| createApp(App).use(store).use(router).mount("#app"); |
| import { createRouter, createWebHistory } from "vue-router"; | |||||
| const isMobile = /Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(navigator.userAgent); | |||||
| const redirectPath = isMobile ? "/m_home" : "/p_home"; | |||||
| const routes = [{ | |||||
| path: "/", | |||||
| redirect: redirectPath, | |||||
| }, | |||||
| { | |||||
| path: "/m_home", | |||||
| name: "M_Home", | |||||
| component: () => | |||||
| import ("@/views/mobile/home/Home.vue"), | |||||
| meta: { | |||||
| title: "首页", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_industry-park", | |||||
| name: "M_IndustryPark", | |||||
| component: () => | |||||
| import ("@/views/mobile/industry/IndustryPark.vue"), | |||||
| meta: { | |||||
| title: "产业园区", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_investment-projects", | |||||
| name: "M_InvestmentProjects", | |||||
| component: () => | |||||
| import ("@/views/mobile/project/InvestmentProjects.vue"), | |||||
| meta: { | |||||
| title: "招商项目 ", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_preferential-policy", | |||||
| name: "M_PreferentialPolicy", | |||||
| component: () => | |||||
| import ("@/views/mobile/policy/PreferentialPolicy.vue"), | |||||
| meta: { | |||||
| title: "优惠政策", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_preferential-policy-detail", | |||||
| name: "M_PreferentialPolicyDetail", | |||||
| component: () => | |||||
| import ("@/views/mobile/policy/PreferentialPolicyDetail.vue"), | |||||
| meta: { | |||||
| title: "优惠政策", | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_about-me", | |||||
| name: "M_AboutMe", | |||||
| component: () => | |||||
| import ("@/views/mobile/aboutMe/AboutMe.vue"), | |||||
| meta: { | |||||
| title: "关于书院", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/m_apply-for-entry", | |||||
| name: "M_ApplyForEntry", | |||||
| component: () => | |||||
| import ("@/views/mobile/ApplyForEntry.vue"), | |||||
| meta: { | |||||
| title: "申请入驻", | |||||
| isNav: true, | |||||
| type: "mobile", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_home", | |||||
| name: "P_Home", | |||||
| component: () => | |||||
| import ("@/views/pc/home/Home.vue"), | |||||
| meta: { | |||||
| title: "首页", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_industry-park", | |||||
| name: "P_IndustryPark", | |||||
| component: () => | |||||
| import ("@/views/pc/industry/IndustryPark.vue"), | |||||
| meta: { | |||||
| title: "产业园区", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_investment-projects", | |||||
| name: "P_InvestmentProjects", | |||||
| component: () => | |||||
| import ("@/views/pc/project/InvestmentProjects.vue"), | |||||
| meta: { | |||||
| title: "招商项目 ", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_preferential-policy", | |||||
| name: "P_PreferentialPolicy", | |||||
| component: () => | |||||
| import ("@/views/pc/policy/PreferentialPolicy.vue"), | |||||
| meta: { | |||||
| title: "优惠政策", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_preferential-policy-detail", | |||||
| name: "P_PreferentialPolicyDetail", | |||||
| component: () => | |||||
| import ("@/views/pc/policy/PreferentialPolicyDetail.vue"), | |||||
| meta: { | |||||
| title: "优惠政策", | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_about-me", | |||||
| name: "P_AboutMe", | |||||
| component: () => | |||||
| import ("@/views/pc/aboutMe/AboutMe.vue"), | |||||
| meta: { | |||||
| title: "关于书院", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| { | |||||
| path: "/p_apply-for-entry", | |||||
| name: "P_ApplyForEntry", | |||||
| component: () => | |||||
| import ("@/views/pc/apply/ApplyForEntry.vue"), | |||||
| meta: { | |||||
| title: "申请入驻", | |||||
| isNav: true, | |||||
| type: "pc", | |||||
| }, | |||||
| }, | |||||
| ]; | |||||
| const router = createRouter({ | |||||
| history: createWebHistory("/public"), | |||||
| routes, | |||||
| scrollBehavior() { | |||||
| return { | |||||
| left: 0, | |||||
| top: 0, | |||||
| }; | |||||
| }, | |||||
| }); | |||||
| router.beforeEach((to, from, next) => { | |||||
| // 移动端访问PC | |||||
| if (isMobile && to.meta.type !== "mobile") { | |||||
| let routers = router.options.routes.filter(v => v.path != "/" && v.meta.type === "mobile"); | |||||
| let path = null; | |||||
| routers.forEach(v => { | |||||
| if (v.name.split("_")[1] == to.name.split("_")[1]) { | |||||
| path = v.path; | |||||
| } | |||||
| }); | |||||
| if (path) next(path); | |||||
| next("/"); | |||||
| } | |||||
| // pc 访问 移动 | |||||
| if (!isMobile && to.meta.type !== "pc") { | |||||
| const routers = router.options.routes.filter(v => v.path != "/" && v.meta.type === "pc"); | |||||
| let path = null; | |||||
| routers.forEach(v => { | |||||
| if (v.name.split("_")[1] == to.name.split("_")[1]) { | |||||
| path = v.path; | |||||
| } | |||||
| }); | |||||
| if (path) next(path); | |||||
| next("/"); | |||||
| } | |||||
| next(); | |||||
| }); | |||||
| export default router; |
| import { createPinia } from "pinia"; | |||||
| // 引入持久化插件 | |||||
| import piniaPluginPersist from "pinia-plugin-persist"; | |||||
| const store = createPinia(); | |||||
| // 使用该插件 | |||||
| store.use(piniaPluginPersist); | |||||
| //导出 | |||||
| export default store; |
| import { defineStore } from "pinia"; | |||||
| import { ref } from "vue"; | |||||
| const useHomeStore = defineStore("Home", { | |||||
| state: () => { | |||||
| return { | |||||
| homeData: ref({}), | |||||
| policyInfo: ref({}), | |||||
| contract: ref({}), | |||||
| }; | |||||
| }, | |||||
| actions: {}, | |||||
| getters: {}, | |||||
| persist: { | |||||
| //这里存储默认使用的是session | |||||
| enabled: true, | |||||
| strategies: [{ | |||||
| //key的名称 | |||||
| key: "home", | |||||
| //更改默认存储,我更改为localStorage | |||||
| storage: localStorage, | |||||
| // 可以选择哪些进入local存储,这样就不用全部都进去存储了 | |||||
| // 默认是全部进去存储 | |||||
| // paths: [""], | |||||
| }, ], | |||||
| }, | |||||
| }); | |||||
| export default useHomeStore; |
| * { | |||||
| padding: 0; | |||||
| margin: 0; | |||||
| } | |||||
| html { | |||||
| height: 100%; | |||||
| } | |||||
| body { | |||||
| height: 100%; | |||||
| } | |||||
| #app { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| max-width: auto; | |||||
| min-height: 100%; | |||||
| } | |||||
| ul, | |||||
| ol, | |||||
| li { | |||||
| list-style: none; | |||||
| } | |||||
| a { | |||||
| text-decoration: none; | |||||
| } | |||||
| .pointer { | |||||
| cursor: pointer; | |||||
| } | |||||
| .fl { | |||||
| float: left; | |||||
| } | |||||
| .fr { | |||||
| float: right; | |||||
| } | |||||
| .tip { | |||||
| color: #fff; | |||||
| font-size: 16px; | |||||
| text-align: center; | |||||
| background: rgba(0, 0, 0, 0.7); | |||||
| border-radius: 8px; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| padding: 14px; | |||||
| box-sizing: content-box; | |||||
| } |
| $bg-color: red; | |||||
| $color-white: #fff; | |||||
| $color-black: rgba(0, 0, 0, 1); | |||||
| $wrapWidth: 1200px; | |||||
| $contentWidth: 1180px; | |||||
| // 尺寸 | |||||
| @mixin size($w, $h) { | |||||
| width: $w; | |||||
| height: $h; | |||||
| } | |||||
| // 字体大小、颜色 | |||||
| @mixin font($font-size, $font-color) { | |||||
| font-size: $font-size; | |||||
| color: $font-color; | |||||
| } | |||||
| // 背景图片 | |||||
| @mixin bg-image($url) { | |||||
| background-image: url($url); | |||||
| } | |||||
| // 文本溢出省略显示 | |||||
| // 单行文本溢出省略显示 | |||||
| @mixin text-ellipsis() { | |||||
| white-space: nowrap; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| } | |||||
| // 多行文本溢出省略显示,支持 WebKit浏览器或移动端的页面 | |||||
| // $row - 行数 | |||||
| @mixin text-ellipsis-multiple($row) { | |||||
| overflow: hidden; | |||||
| word-break: break-all; | |||||
| text-overflow: ellipsis; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: $row; | |||||
| -webkit-box-orient: vertical; | |||||
| } | |||||
| // flex布局 | |||||
| @mixin flex( $direction: row, $justify-content: flex-start, $align-items: flex-start, $flex-wrap: nowrap) { | |||||
| display: flex; | |||||
| flex-direction: $direction; | |||||
| justify-content: $justify-content; | |||||
| align-items: $align-items; | |||||
| flex-wrap: $flex-wrap; | |||||
| } | |||||
| @mixin hoverLine($height, $color: $color-text-primary) { | |||||
| position: relative; | |||||
| &:hover::after { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| height: $height; | |||||
| width: 100%; | |||||
| background-color: $color; | |||||
| bottom: 0; | |||||
| left: 0; | |||||
| } | |||||
| } | |||||
| // IE盒模型 | |||||
| @mixin border-box { | |||||
| -webkit-box-sizing: border-box; | |||||
| -moz-box-sizing: border-box; | |||||
| box-sizing: border-box; | |||||
| } |
| import router from "../router/index"; | |||||
| import dayjs from "dayjs"; // 时间格式化组件 | |||||
| import { showToast } from "vant"; | |||||
| const { VITE_BASE_URL } = | |||||
| import.meta.env; | |||||
| // 在新的页面打开路由 | |||||
| export const routerOpenInNewWindow = routerPath => { | |||||
| let routeData = router.resolve(routerPath); | |||||
| window.open(routeData.href, "_blank"); | |||||
| }; | |||||
| /** | |||||
| * | |||||
| * @param {*} path 图片路径 | |||||
| * @returns | |||||
| */ | |||||
| export const formatImg = path => { | |||||
| return path ? `${VITE_BASE_URL}/common/getImg?path=${path}` : ""; | |||||
| // return path ? `http://shuyuan.test.hhrchina.com/filex/img/${path}` : ""; | |||||
| }; | |||||
| /** | |||||
| * | |||||
| * @param {*} path 图片路径 | |||||
| * @returns | |||||
| */ | |||||
| export const formatVideo = path => { | |||||
| return path ? `${VITE_BASE_URL}/common/getVideo?path=${path}` : ""; | |||||
| }; | |||||
| /** | |||||
| * | |||||
| * @param {*} time 时间 | |||||
| * @param {*} fmtString 转换的格式 | |||||
| * @returns | |||||
| */ | |||||
| export const formatDate = (time, fmtString) => { | |||||
| time = new Date(time); | |||||
| // 使用dayjs这个日期格式化类库实现日期的格式化功能 | |||||
| if (time == "" || !time) { | |||||
| return "——"; | |||||
| } else { | |||||
| return dayjs(time).format(fmtString); | |||||
| } | |||||
| }; | |||||
| /** | |||||
| * | |||||
| * @param {*} ary 数组 | |||||
| * @param {*} key 根据key值排序 | |||||
| * @returns | |||||
| */ | |||||
| export const sortByKey = (ary, key) => { | |||||
| return ary.sort(function(a, b) { | |||||
| let x = a[key]; | |||||
| let y = b[key]; | |||||
| return x < y ? -1 : x > y ? 1 : 0; | |||||
| }); | |||||
| }; | |||||
| /** | |||||
| * | |||||
| * @param {*} val string | |||||
| * @returns | |||||
| */ | |||||
| export const toast = (val, type) => { | |||||
| const isMobile = /Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(navigator.userAgent); | |||||
| if (isMobile) { | |||||
| showToast({ | |||||
| message: val, | |||||
| className: "tip", | |||||
| }); | |||||
| } else { | |||||
| ElMessage({ | |||||
| message: val, | |||||
| type, | |||||
| }); | |||||
| } | |||||
| }; | |||||
| export const debounce = (func, delay) => { | |||||
| let timer = null; | |||||
| return function(...args) { | |||||
| clearTimeout(timer); | |||||
| timer = setTimeout(() => { | |||||
| func.apply(this, args); | |||||
| }, delay); | |||||
| }; | |||||
| }; | |||||
| export const throttle = (func, wait) => { | |||||
| let timer; | |||||
| return () => { | |||||
| if (timer) { | |||||
| return; | |||||
| } | |||||
| timer = setTimeout(() => { | |||||
| func(); | |||||
| timer = null; | |||||
| }, wait); | |||||
| }; | |||||
| }; |
| /**axios封装 | |||||
| * 请求拦截、相应拦截、错误统一处理 | |||||
| */ | |||||
| import axios from "axios"; | |||||
| // import QS from 'qs'; | |||||
| // 环境的切换 | |||||
| axios.defaults.baseURL = | |||||
| import.meta.env.VITE_BASE_URL; | |||||
| // 请求超时时间 | |||||
| axios.defaults.timeout = 25000; | |||||
| // post请求头 | |||||
| axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; | |||||
| // axios.defaults.headers.post["Content-Type"] = "application/json; charset=UTF-8"; | |||||
| let pending = []; //声明一个数组用于存储每个请求的取消函数和axios标识 | |||||
| let cancelRepeatUrl = []; // 园区服务、物业租售 | |||||
| let cancelToken = axios.CancelToken; | |||||
| let removePending = config => { | |||||
| // console.log(config); | |||||
| for (let i in pending) { | |||||
| if (pending[i].url === axios.defaults.baseURL + config.url) { | |||||
| //在当前请求在数组中存在时执行取消函数 | |||||
| pending[i].f(); //执行取消操作 | |||||
| // pending.splice(i, 1); // 根据具体情况决定是否在这里就把pending去掉 | |||||
| // console.log("重复的:" + pending[i].url); | |||||
| } | |||||
| } | |||||
| }; | |||||
| // 请求拦截器 | |||||
| axios.interceptors.request.use( | |||||
| config => { | |||||
| // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了 | |||||
| // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断 | |||||
| // const token = store.state.token; | |||||
| // token && (config.headers.Authorization = token); | |||||
| // return config; | |||||
| removePending(config); //在一个axios发送前执行一下判定操作,在removePending中执行取消操作 | |||||
| // console.log(config.url); | |||||
| config.cancelToken = new cancelToken(function executor(c) { | |||||
| //本次axios请求的配置添加cancelToken | |||||
| if (cancelRepeatUrl.indexOf(config.url) > -1) { | |||||
| pending.push({ | |||||
| // url: config.url, | |||||
| url: axios.defaults.baseURL + config.url, | |||||
| f: c, | |||||
| }); | |||||
| // console.log(axios.defaults.baseURL + config.url); | |||||
| //将本次的url添加到pending中,因此对于某个url第一次发起的请求不会被取消,因为还没有配置取消函数 | |||||
| } | |||||
| }); | |||||
| return Promise.resolve(config); | |||||
| }, | |||||
| error => { | |||||
| return Promise.error(error); | |||||
| } | |||||
| ); | |||||
| // 响应拦截器 | |||||
| axios.interceptors.response.use( | |||||
| response => { | |||||
| if (response.status === 200) { | |||||
| // removePending(response.config); //在一个axios响应后再执行一下取消操作,把已经完成的请求从pending中移除 | |||||
| return Promise.resolve(response); | |||||
| } else { | |||||
| return Promise.reject(response); | |||||
| } | |||||
| }, | |||||
| // 服务器状态码不是200的情况 | |||||
| error => { | |||||
| if (error.response) { | |||||
| return Promise.reject(error.response); | |||||
| } | |||||
| } | |||||
| ); | |||||
| /** | |||||
| * get方法,对应get请求 | |||||
| * @param {String} url [请求的url地址] | |||||
| * @param {Object} params [请求时携带的参数] | |||||
| */ | |||||
| export function get(url, params) { | |||||
| return new Promise((resolve, reject) => { | |||||
| axios | |||||
| .get(url, { | |||||
| params: params, | |||||
| }) | |||||
| .then(res => { | |||||
| resolve(res); | |||||
| }) | |||||
| .catch(err => { | |||||
| reject(err); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| /** | |||||
| * post方法,对应post请求 | |||||
| * @param {String} url [请求的url地址] | |||||
| * @param {Object} params [请求时携带的参数] | |||||
| */ | |||||
| export function post(url, params, options) { | |||||
| return new Promise((resolve, reject) => { | |||||
| axios | |||||
| .post(url, params, options) | |||||
| .then(res => { | |||||
| resolve(res); | |||||
| }) | |||||
| .catch(err => { | |||||
| reject(err); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| /** | |||||
| * put方法,对应put请求 | |||||
| * @param {String} url [请求的url地址] | |||||
| * @param {Object} params [请求时携带的参数] | |||||
| */ | |||||
| export function put(url, params) { | |||||
| return new Promise((resolve, reject) => { | |||||
| axios | |||||
| .put(url, params) | |||||
| .then(res => { | |||||
| resolve(res); | |||||
| }) | |||||
| .catch(err => { | |||||
| reject(err); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| /** | |||||
| * delete方法,对应delete请求,delete是保留字,使用del代替 | |||||
| * @param {String} url [请求的url地址] | |||||
| */ | |||||
| export function del(url, params) { | |||||
| return new Promise((resolve, reject) => { | |||||
| axios | |||||
| .delete(url, { | |||||
| params: params, | |||||
| }) | |||||
| .then(res => { | |||||
| resolve(res); | |||||
| }) | |||||
| .catch(err => { | |||||
| reject(err); | |||||
| }); | |||||
| }); | |||||
| } |
| <template> | |||||
| <section> | |||||
| <div class="form-tab"> | |||||
| <span | |||||
| v-for="(item, index) in tabArr" | |||||
| :class="[currentTb == index ? 'active' : '']" | |||||
| @click="changeTab(item.value, index)" | |||||
| :key="item.value" | |||||
| > | |||||
| {{ item.label }} | |||||
| </span> | |||||
| </div> | |||||
| <div class="form"> | |||||
| <el-form | |||||
| v-if="currentTb == 0" | |||||
| :label-position="labelPosition" | |||||
| label-width="100px" | |||||
| :model="params" | |||||
| > | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 企业名称 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.companyName" | |||||
| placeholder="请输入企业名称" | |||||
| maxlength="50" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系人 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.name" | |||||
| placeholder="请输入联系人名称" | |||||
| maxlength="10" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系电话 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.mobile" | |||||
| placeholder="请输入联系电话" | |||||
| maxlength="11" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label">预计产税</div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.estimatedPropertyTax" | |||||
| placeholder="请输入预计产税" | |||||
| maxlength="20" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label><div class="form-item-label">需求内容</div></template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.text" | |||||
| type="textarea" | |||||
| rows="10" | |||||
| placeholder="请输入需求内容" | |||||
| resize="none" | |||||
| maxlength="200" | |||||
| /> | |||||
| </el-form-item> | |||||
| </el-form> | |||||
| <el-form | |||||
| v-else | |||||
| :label-position="labelPosition" | |||||
| label-width="100px" | |||||
| :model="formLabelAlign" | |||||
| > | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 企业名称 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.companyName" | |||||
| placeholder="请输入企业名称" | |||||
| maxlength="50" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系人 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.name" | |||||
| placeholder="请输入联系人名称" | |||||
| maxlength="10" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系电话 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.mobile" | |||||
| placeholder="请输入联系电话" | |||||
| maxlength="11" | |||||
| /> | |||||
| </el-form-item> | |||||
| </el-form> | |||||
| <van-button | |||||
| class="submit" | |||||
| round | |||||
| block | |||||
| type="primary" | |||||
| native-type="submit" | |||||
| @click="submitForm" | |||||
| > | |||||
| 提交申请 | |||||
| </van-button> | |||||
| <div class="text-tip">提交后我们将在1-7个工作日内联系您</div> | |||||
| </div> | |||||
| </section> | |||||
| </template> | |||||
| <script setup> | |||||
| import { apply } from "@/views/pc/apply/apply"; | |||||
| const { labelPosition, currentTb, tabArr, params, applyForEntry, changeTab, submitForm } = apply(); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .form-tab { | |||||
| padding: 10px 22px; | |||||
| @include border-box; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| span { | |||||
| width: 50%; | |||||
| height: 30px; | |||||
| @include font(12px, $color-black); | |||||
| font-weight: 500; | |||||
| @include flex(row, center, center, nowrap); | |||||
| border-radius: 20px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| cursor: pointer; | |||||
| @include border-box; | |||||
| } | |||||
| .active { | |||||
| @include font(12px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| .form { | |||||
| margin: 10px 22px; | |||||
| padding: 18px; | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| text-align: center; | |||||
| &-item { | |||||
| border-radius: 50px; | |||||
| background: rgba(242, 244, 249, 1); | |||||
| padding: 5px 10px 5px 0; | |||||
| @include border-box; | |||||
| &-label { | |||||
| @include font(12px, $color-black); | |||||
| border-right: 3px solid rgba(145, 145, 145, 1); | |||||
| padding-right: 10px; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| .submit { | |||||
| @include size(186px, 40px); | |||||
| @include font(12px, $color-white); | |||||
| border-radius: 50px; | |||||
| @include border-box; | |||||
| margin: 20px auto; | |||||
| } | |||||
| .text-tip { | |||||
| @include font(12px, $color-black); | |||||
| } | |||||
| } | |||||
| .required { | |||||
| color: rgba(255, 0, 0, 1); | |||||
| } | |||||
| :deep() { | |||||
| .el-input__wrapper, | |||||
| .el-textarea__inner { | |||||
| background: none; | |||||
| box-shadow: none; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="block"> | |||||
| <div class="title">{{ propsData.aboutItem.label }}</div> | |||||
| <div class="content" v-html="formatHtml(propsData.aboutItem.value)"></div> | |||||
| <!-- <div class="content"> | |||||
| <div> | |||||
| 书院镇位于上海市浦东新区的东南部、自贸区临港新片区北门户位置,在浦东国际机场和洋山深水港之间,东临大海,南接泥城镇,西至万祥镇,北与老港镇隔大治河相望。 | |||||
| </div> | |||||
| <img | |||||
| src="https://img.js.design/assets/img/64ab9e9276b0da9863e5bba0.png#1b5fe6bef0090a0d2c77afb77c9b7873" | |||||
| alt="" | |||||
| /> | |||||
| </div> --> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| aboutItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| const formatHtml = text => { | |||||
| let html = SimpleMDE.prototype.markdown(text); | |||||
| console.log(html); | |||||
| let imgUrl = `${import.meta.env.VITE_BASE_URL}/common/getImg?path=`; | |||||
| html = html.replace( | |||||
| /<img [^>]*src=['"]([^'"]+)[^>]*>/gi, | |||||
| "<img src='" + imgUrl + "$1' width='100%'/>" | |||||
| ); | |||||
| return html; | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .block { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| padding: 10px; | |||||
| @include border-box; | |||||
| @include flex(column, space-between, center, nowrap); | |||||
| margin: 10px 0; | |||||
| .title { | |||||
| @include font(14px, $color-black); | |||||
| font-weight: 500; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| .content { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| word-break: break-word; | |||||
| } | |||||
| img { | |||||
| @include size(100%, auto); | |||||
| margin-top: 10px; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="about" v-if="!loading"> | |||||
| <!-- <div> | |||||
| <span v-for="item in tabArr" :key="item.label">{{ item.label }}</span> | |||||
| </div> --> | |||||
| <template v-for="(item, index) in tabArr" :key="item.label"> | |||||
| <About | |||||
| :aboutItem="{ | |||||
| label: tabArr[index].label, | |||||
| value: homeData[tabArr[index].key], | |||||
| }" | |||||
| ></About> | |||||
| </template> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted, ref } from "vue"; | |||||
| import About from "./About.vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| let homeData = ref({}); | |||||
| const tab = [ | |||||
| { | |||||
| label: "区位优势", | |||||
| value: 0, | |||||
| key: "regionalAdvantages", | |||||
| }, | |||||
| { | |||||
| label: "发展机遇", | |||||
| value: 1, | |||||
| key: "developmentOpportunity", | |||||
| }, | |||||
| { | |||||
| label: "配套建设", | |||||
| value: 2, | |||||
| key: "supportingConstruction", | |||||
| }, | |||||
| { | |||||
| label: "发展趋势", | |||||
| value: 3, | |||||
| key: "developmentTendency", | |||||
| }, | |||||
| { | |||||
| label: "交通优势", | |||||
| value: 4, | |||||
| key: "transportationAdvantage", | |||||
| }, | |||||
| { | |||||
| label: "镇域概况", | |||||
| value: 5, | |||||
| key: "townProfile", | |||||
| }, | |||||
| { | |||||
| label: "书院介绍", | |||||
| value: 6, | |||||
| key: "academyHistory", | |||||
| }, | |||||
| ]; | |||||
| const tabArr = ref(tab); | |||||
| const loading = ref(true); | |||||
| onMounted(() => { | |||||
| loading.value = true; | |||||
| homeData.value = homeStore.homeData.value; | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .about { | |||||
| padding: 0 15px; | |||||
| overflow: hidden; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include border-box; | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div v-if="!loading"> | |||||
| <div class="wrap-box"> | |||||
| <Introduce :homeData="homeData"></Introduce> | |||||
| <IndustrialPark :projectItem="registrationPackage"></IndustrialPark> | |||||
| <IndustrialCluster :industrialAllocation="industrialAllocation"></IndustrialCluster> | |||||
| </div> | |||||
| <div class="wrap-box"> | |||||
| <div class="title">政策优势</div> | |||||
| <Policy v-for="(item, index) in policy" :key="index" :policyItem="item"></Policy> | |||||
| <PicturePolicy | |||||
| :policySupportKeyIndustries="homeData.policySupportKeyIndustries" | |||||
| :domesticTalentIntroduction="homeData.domesticTalentIntroduction" | |||||
| ></PicturePolicy> | |||||
| <DetailPolicy | |||||
| v-for="(item, index) in detailPolicy" | |||||
| :key="index" | |||||
| :detailPolicyItem="item" | |||||
| ></DetailPolicy> | |||||
| <OtherPolicy></OtherPolicy> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Introduce from "./project/Introduce.vue"; | |||||
| import IndustrialPark from "./project/IndustrialPark.vue"; | |||||
| import IndustrialCluster from "./project/IndustrialCluster.vue"; | |||||
| import Policy from "./policy/Policy.vue"; | |||||
| import PicturePolicy from "./policy/PicturePolicy.vue"; | |||||
| import DetailPolicy from "./policy/DetailPolicy.vue"; | |||||
| import OtherPolicy from "./policy/OtherPolicy.vue"; | |||||
| import { getHomeData } from "@/views/pc/home/home"; | |||||
| import { onBeforeMount } from "vue"; | |||||
| const { | |||||
| getAreaIndustrialAllocation, | |||||
| setDetailPolicy, | |||||
| setPolicy, | |||||
| updatePageView, | |||||
| getRegistrationPackage, | |||||
| } = getHomeData(); | |||||
| let homeData = ref({}); | |||||
| let industrialAllocation = ref([]); | |||||
| let policy = ref([]); | |||||
| let detailPolicy = ref([]); | |||||
| let registrationPackage = ref({}); | |||||
| const loading = ref(true); | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| onBeforeMount(async () => { | |||||
| loading.value = true; | |||||
| homeData.value = homeStore.homeData.value; | |||||
| policy = setPolicy(homeData.value); | |||||
| detailPolicy = setDetailPolicy(homeData.value); | |||||
| industrialAllocation.value = await getAreaIndustrialAllocation(); | |||||
| registrationPackage.value = await getRegistrationPackage(); | |||||
| loading.value = false; | |||||
| updatePageView(homeData.value.areaInfoManagementId); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .wrap-box { | |||||
| padding: 10px 15px; | |||||
| background: #fff; | |||||
| @include border-box; | |||||
| } | |||||
| .title { | |||||
| @include font(16px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="detail-title">{{ propsData.detailPolicyItem.title }}</div> | |||||
| <div class="detail-policy"> | |||||
| <div | |||||
| class="detail-policy-content" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.detailPolicyItem.content)" | |||||
| ></div> | |||||
| <!-- <div class="detail-policy-content"> | |||||
| 按当年销售金额最高 10% 给予奖励,单款芯片产品年度奖励总额不超过 500 万元。 | |||||
| </div> --> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| detailPolicyItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .detail-title { | |||||
| @include font(14px, rgba(42, 130, 228, 1)); | |||||
| border-bottom: 2px solid rgba(42, 130, 228, 1); | |||||
| padding: 10px 0; | |||||
| @include border-box; | |||||
| } | |||||
| .detail-policy { | |||||
| padding: 10px 0; | |||||
| @include border-box; | |||||
| &-title { | |||||
| @include font(14px, $color-black); | |||||
| margin-bottom: 10px; | |||||
| font-weight: bold; | |||||
| } | |||||
| &-content { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| word-break: break-word; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="other-policy" v-if="dataList && dataList.length > 0"> | |||||
| <div class="other-policy-title">其他政策</div> | |||||
| <div class="other-policy-content"> | |||||
| <div | |||||
| v-for="item in dataList" | |||||
| :key="item.releasePolicyId" | |||||
| :title="item.policyName" | |||||
| @click="goRoute(item)" | |||||
| > | |||||
| {{ item.policyName }} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted } from "vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { useRouter } from "vue-router"; | |||||
| const $router = useRouter(); | |||||
| const { params, getList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| const loading = ref(true); | |||||
| const getListData = async () => { | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| }; | |||||
| const goRoute = val => { | |||||
| localStorage.setItem("policyInfo", JSON.stringify(val)); | |||||
| $router.push({ | |||||
| path: "/m_preferential-policy-detail", | |||||
| query: { | |||||
| releasePolicyId: val.releasePolicyId, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| getListData(); | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .other-policy { | |||||
| // padding: 16px 42px; | |||||
| @include border-box; | |||||
| margin-bottom: 28px; | |||||
| &-title { | |||||
| @include font(16px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| &-content { | |||||
| // @include flex(row, space-between, flex-start, wrap); | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| div { | |||||
| margin-bottom: 8px; | |||||
| @include text-ellipsis; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="picture-box"> | |||||
| <div | |||||
| class="picture-policy" | |||||
| v-if=" | |||||
| propsData.policySupportKeyIndustries && | |||||
| propsData.policySupportKeyIndustries.length > 0 | |||||
| " | |||||
| > | |||||
| <div class="picture-policy-title">重点产业扶持政策</div> | |||||
| <img | |||||
| class="picture-policy-content" | |||||
| :src="formatImg(propsData.policySupportKeyIndustries[0])" | |||||
| alt="重点产业扶持政策" | |||||
| /> | |||||
| </div> | |||||
| <div | |||||
| class="picture-policy" | |||||
| v-if=" | |||||
| propsData.domesticTalentIntroduction && | |||||
| propsData.domesticTalentIntroduction.length > 0 | |||||
| " | |||||
| > | |||||
| <div class="picture-policy-title">国内人才引进</div> | |||||
| <img | |||||
| class="picture-policy-content" | |||||
| :src="formatImg(propsData.domesticTalentIntroduction[0])" | |||||
| alt="国内人才引进" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| policySupportKeyIndustries: { | |||||
| type: Array, | |||||
| }, | |||||
| domesticTalentIntroduction: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .picture-box { | |||||
| // @include flex(row, space-between, flex-start, nowrap); | |||||
| } | |||||
| .picture-policy { | |||||
| // padding: 10px 22px 0; | |||||
| @include border-box; | |||||
| margin-bottom: 10px; | |||||
| &-title { | |||||
| @include font(14px, $color-black); | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include size(100%, 100%); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div | |||||
| class="policy" | |||||
| :style="{ color: propsData.policyItem.color, background: propsData.policyItem.bgColor }" | |||||
| > | |||||
| <div class="policy-title" :style="{ color: propsData.policyItem.color }"> | |||||
| {{ propsData.policyItem.title }} | |||||
| </div> | |||||
| <div | |||||
| class="policy-content" | |||||
| :style="{ color: propsData.policyItem.color }" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.policyItem.content)" | |||||
| ></div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| policyItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .policy { | |||||
| background: rgba(255, 242, 197, 1); | |||||
| border-radius: 20px; | |||||
| padding: 10px 12px; | |||||
| @include border-box; | |||||
| margin-bottom: 12px; | |||||
| &-title { | |||||
| @include font(14px, $color-black); | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| word-break: break-word; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="industrial-park"> | |||||
| <div class="industrial-park-title">产业聚集</div> | |||||
| <div class="industrial-park-content"> | |||||
| <van-swipe class="my-swipe" :autoplay="5000" indicator-color="white"> | |||||
| <van-swipe-item | |||||
| v-for="item in propsData.industrialAllocation" | |||||
| :key="item.areaIndustrialAllocationId" | |||||
| > | |||||
| <Cluster :data="item" :height="200" /> | |||||
| </van-swipe-item> | |||||
| </van-swipe> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Cluster from "@/views/mobile/industry/Cluster.vue"; | |||||
| const propsData = defineProps({ | |||||
| industrialAllocation: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .industrial-park { | |||||
| // padding: 16px 42px; | |||||
| @include border-box; | |||||
| margin-top: 10px; | |||||
| &-title { | |||||
| @include font(16px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include flex(row, space-between, flex-start, wrap); | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| span { | |||||
| margin-bottom: 10px; | |||||
| @include text-ellipsis; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| } | |||||
| :deep() { | |||||
| // .van-swipe__indicator { | |||||
| // color: rgba(204, 204, 204, 1); | |||||
| // } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="industrial-park"> | |||||
| <div class="industrial-park-title">产业园区</div> | |||||
| <div class="industrial-park-content"> | |||||
| <!-- <van-swipe class="my-swipe" :autoplay="5000" indicator-color="white"> --> | |||||
| <!-- <van-swipe-item v-for="item in 3"> --> | |||||
| <Project :projectItem="propsData.projectItem" @doSth="showTipInfo" /> | |||||
| <!-- </van-swipce-item> --> | |||||
| <!-- </van-swipe> --> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRef"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import TipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| import Project from "@/views/mobile/project/Project.vue"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| const tipRef = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRef.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .industrial-park { | |||||
| // padding: 16px 42px; | |||||
| @include border-box; | |||||
| margin-top: 20px; | |||||
| &-title { | |||||
| @include font(16px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include flex(row, space-between, flex-start, wrap); | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| span { | |||||
| margin-bottom: 10px; | |||||
| @include text-ellipsis; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="introduce"> | |||||
| <div class="introduce-box"> | |||||
| <div class="introduce-box-title">区位优势</div> | |||||
| <div> | |||||
| {{ propsData.homeData.academyHistory }} | |||||
| </div> | |||||
| </div> | |||||
| <img | |||||
| class="introduce-img" | |||||
| v-if="propsData.homeData.parkPicture && propsData.homeData.parkPicture.length > 0" | |||||
| :src="formatImg(propsData.homeData.parkPicture[0])" | |||||
| alt="园区图片" | |||||
| /> | |||||
| <div class="introduce-box"> | |||||
| <div class="introduce-box-title">镇域概括</div> | |||||
| <ul class="introduce-ul"> | |||||
| <li> | |||||
| <div class="subtitle">行政区域面积</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.administrativeArea }}</span> | |||||
| 平方公里 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>实有入口</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.actualEntry }}</span> | |||||
| 万 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>下辖</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.haveJurisdictionOver }}</span> | |||||
| 个村 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>居民区</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.residentialArea }}</span> | |||||
| 个 | |||||
| </div> | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| homeData: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .introduce { | |||||
| padding-top: 5px; | |||||
| @include border-box; | |||||
| &-img { | |||||
| @include size(100%, 325px); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| margin: 10px 0; | |||||
| } | |||||
| &-box { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| &-title { | |||||
| @include font(16px, $color-black); | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .introduce-ul { | |||||
| @include flex(row, space-between, flex-start, nowrap); | |||||
| li { | |||||
| // width: 25%; | |||||
| // margin-top: 10px; | |||||
| } | |||||
| .subtitle { | |||||
| @include font(12px, $color-black); | |||||
| } | |||||
| .blue-text { | |||||
| @include font(20px, rgba(0, 153, 255, 1)); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div | |||||
| :class="['cluster', propsData.height ? 'height_200' : '']" | |||||
| :style="{ backgroundImage: 'url(' + formatImg(propsData.data.productUrl[0]) + ')' }" | |||||
| > | |||||
| <div class="cluster-title">{{ propsData.data.leadingIndustryName }}</div> | |||||
| <div | |||||
| class="cluster-content" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.data.leadingIndustryDetail)" | |||||
| ></div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| data: { | |||||
| type: Object, | |||||
| }, | |||||
| height: { | |||||
| type: Number, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .cluster { | |||||
| position: relative; | |||||
| border-radius: 10px; | |||||
| padding: 10px 20px; | |||||
| @include border-box; | |||||
| @include flex(column, flex-start, flex-start, nowrap); | |||||
| margin-bottom: 10px; | |||||
| // @include bg-image("https://img.js.design/assets/img/64abb2f1eec7205596b5791f.jpg"); | |||||
| background-size: 100% 100%; | |||||
| background-repeat: no-repeat; | |||||
| &-title { | |||||
| @include font(14px, $color-white); | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| z-index: 100; | |||||
| } | |||||
| &-content { | |||||
| @include font(12px, $color-white); | |||||
| line-height: 20px; | |||||
| word-break: break-word; | |||||
| z-index: 100; | |||||
| } | |||||
| } | |||||
| .cluster:before { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| background-color: rgba(0, 0, 0, 0.5); | |||||
| border-radius: 10px; | |||||
| @include border-box; | |||||
| } | |||||
| .height_200 { | |||||
| height: 200px; | |||||
| .cluster-content { | |||||
| @include text-ellipsis-multiple(7); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="enterprise_item_box"> | |||||
| <div class="block-title">{{ propsData.projectItem.element.text }}</div> | |||||
| <div | |||||
| class="enterprise" | |||||
| v-for="item in propsData.projectItem.enterpriseData" | |||||
| :key="item.enterpriseHomeLinkId" | |||||
| > | |||||
| <img :src="formatImg(item.url[0])" alt="图片" /> | |||||
| <div class="content" v-html="SimpleMDE.prototype.markdown(item.detail)"></div> | |||||
| <!-- <div class="content">占地面积381亩</div> | |||||
| <div class="content">建筑面积337515平方米</div> --> | |||||
| <div class="consult" @click="showTipInfo">立 即 咨 询</div> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRef"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| import TipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| const tipRef = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRef.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .enterprise_item_box { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .block-title { | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(14px, $color-black); | |||||
| font-weight: 500; | |||||
| } | |||||
| .enterprise { | |||||
| img { | |||||
| @include font(12px, $color-black); | |||||
| display: inline-block; | |||||
| @include size(100%, 220px); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| margin: 12px 0; | |||||
| } | |||||
| .content { | |||||
| @include font(12px, $color-black); | |||||
| font-weight: 400; | |||||
| margin-bottom: 12px; | |||||
| line-height: 20px; | |||||
| word-break: break-word; | |||||
| } | |||||
| .consult { | |||||
| @include size(290px, 32px); | |||||
| border-radius: 30px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(14px, $color-white); | |||||
| margin: 0 auto; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="industry"> | |||||
| <div class="form-tab"> | |||||
| <span | |||||
| v-for="item in tabArr" | |||||
| :key="item.value" | |||||
| :class="[currentTab == item.value ? 'active' : '']" | |||||
| @click="changeTab(item.value)" | |||||
| > | |||||
| {{ item.label }} | |||||
| </span> | |||||
| </div> | |||||
| <template v-if="!loading"> | |||||
| <template v-if="currentTab == 0"> | |||||
| <InvestmentVehicle | |||||
| v-for="item in registrationPackageList" | |||||
| :key="item.registrationPackageId" | |||||
| :projectItem="item" | |||||
| @doSth="showTipInfo" | |||||
| ></InvestmentVehicle> | |||||
| </template> | |||||
| <template v-if="currentTab == 1"> | |||||
| <Enterprise | |||||
| v-for="item in enterpriseData" | |||||
| :key="item.element.itemId" | |||||
| :projectItem="item" | |||||
| ></Enterprise> | |||||
| </template> | |||||
| <template v-if="currentTab == 2"> | |||||
| <Cluster | |||||
| v-for="item in industrialAllocation" | |||||
| :key="item.areaIndustrialAllocationId" | |||||
| :data="item" | |||||
| ></Cluster> | |||||
| </template> | |||||
| </template> | |||||
| </div> | |||||
| <TipDialog ref="tipRef"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import Cluster from "./Cluster.vue"; | |||||
| import Enterprise from "./Enterprise.vue"; | |||||
| import InvestmentVehicle from "../project/Project.vue"; | |||||
| import TipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| import { getIndustryData } from "@/views/pc/industry/getRegistrationPackageList"; | |||||
| import { onMounted } from "vue"; | |||||
| let { | |||||
| loading, | |||||
| tabArr, | |||||
| currentTab, | |||||
| changeTab, | |||||
| registrationPackageList, | |||||
| enterpriseData, | |||||
| industrialAllocation, | |||||
| } = getIndustryData(); | |||||
| onMounted(() => { | |||||
| loading.value = true; | |||||
| changeTab(0); | |||||
| loading.value = false; | |||||
| }); | |||||
| const tipRef = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRef.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .industry { | |||||
| padding: 10px 15px; | |||||
| overflow: hidden; | |||||
| background: #fff; | |||||
| @include border-box; | |||||
| min-height: 100%; | |||||
| } | |||||
| .form-tab { | |||||
| @include size(100%, auto); | |||||
| margin: 10px auto 20px; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| span { | |||||
| width: 30%; | |||||
| height: 25px; | |||||
| @include font(12px, $color-black); | |||||
| font-weight: 500; | |||||
| @include flex(row, center, center, nowrap); | |||||
| border-radius: 20px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include border-box; | |||||
| } | |||||
| .active { | |||||
| @include font(12px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="policy" v-if="!loading"> | |||||
| <div class="policy-search"> | |||||
| <div class="search-left" @click="show = true"> | |||||
| {{ selectText }} | |||||
| <van-icon name="arrow-down" /> | |||||
| </div> | |||||
| <van-field | |||||
| class="search-input" | |||||
| v-model="params.search" | |||||
| @clear="toSearch" | |||||
| @keyup.enter="toSearch" | |||||
| /> | |||||
| <div class="search-right"> | |||||
| <van-icon name="search" @click="toSearch" /> | |||||
| 搜索 | |||||
| </div> | |||||
| </div> | |||||
| <div class="list_box"> | |||||
| <van-list | |||||
| v-model:loading="pageLoading" | |||||
| :finished="finished" | |||||
| finished-text="没有更多了" | |||||
| @load="onLoad" | |||||
| ref="checkbox" | |||||
| > | |||||
| <ul class="policy-ul"> | |||||
| <li | |||||
| class="policy-item" | |||||
| v-for="item in dataList" | |||||
| :key="item.releasePolicyId" | |||||
| @click="goRoute(item)" | |||||
| > | |||||
| <div class="policy-item-left">{{ item.policyName }}</div> | |||||
| <div class="policy-item-right"> | |||||
| <span>政策类型:{{ item.policyType.text }}</span> | |||||
| <span>发布时间:{{ formatDate(item.modifiedOn, "YYYY.MM.DD") }}</span> | |||||
| </div> | |||||
| </li> | |||||
| </ul> | |||||
| </van-list> | |||||
| </div> | |||||
| </div> | |||||
| <van-popup v-model:show="show" round position="bottom"> | |||||
| <van-picker :columns="selectList" @confirm="changeSelect" @cancel="onCancel" /> | |||||
| </van-popup> | |||||
| </template> | |||||
| <script setup> | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { formatDate, sortByKey } from "@/utils/common.js"; | |||||
| import { onMounted } from "vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| import { useRouter } from "vue-router"; | |||||
| const homeStore = useHomeStore(); | |||||
| const $router = useRouter(); | |||||
| const { params, getList, getPickList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| let selectList = ref([]); | |||||
| let total = ref(0); | |||||
| const loading = ref(true); | |||||
| let selectText = ref("全部"); | |||||
| const pageLoading = ref(false); | |||||
| const finished = ref(false); | |||||
| const onCancel = () => { | |||||
| show.value = false; | |||||
| }; | |||||
| const onLoad = () => { | |||||
| if (params.value.page !== 1) { | |||||
| getListData(); | |||||
| } | |||||
| }; | |||||
| const changeSelect = async ({ selectedOptions }) => { | |||||
| selectText.value = selectedOptions[0].text; | |||||
| console.log(selectedOptions[0]); | |||||
| params.value.policyTypeId = selectedOptions[0].text == "全部" ? "" : selectedOptions[0].itemId; | |||||
| params.value.page = 1; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| show.value = false; | |||||
| }; | |||||
| const toSearch = async () => { | |||||
| params.value.page = 1; | |||||
| params.value.pageSize = 10; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| }; | |||||
| const goRoute = val => { | |||||
| $router.push({ | |||||
| path: "/m_preferential-policy-detail", | |||||
| query: { | |||||
| releasePolicyId: val.releasePolicyId, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const getListData = async () => { | |||||
| pageLoading.value = true; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataList.value.concat(dataObj.list); | |||||
| total.value = dataObj.total; | |||||
| params.value.page = dataObj.page_no; | |||||
| pageLoading.value = false; | |||||
| if (dataList.value.length >= total.value) { | |||||
| finished.value = true; | |||||
| } else { | |||||
| finished.value = false; | |||||
| } | |||||
| params.value.page += 1; | |||||
| }; | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| let pickArr = await getPickList(); | |||||
| selectList.value = sortByKey(pickArr, "seq"); | |||||
| selectList.value.unshift({ | |||||
| text: "全部", | |||||
| itemId: "000", | |||||
| }); | |||||
| selectList.value.forEach(element => { | |||||
| element.value = element.itemId; | |||||
| }); | |||||
| // let dataObj = await getList(params); | |||||
| // dataList.value = dataObj.list; | |||||
| // total.value = dataObj.total; | |||||
| getListData(); | |||||
| loading.value = false; | |||||
| }); | |||||
| const input3 = ref(""); | |||||
| const show = ref(false); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .policy { | |||||
| height: calc(100vh - 48px - 150px); | |||||
| padding: 20px 15px; | |||||
| overflow: hidden; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include border-box; | |||||
| &-search { | |||||
| @include size(100%, 34px); | |||||
| border-radius: 25px; | |||||
| border: 2px solid rgba(29, 112, 217, 1); | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| @include font(12px, $color-black); | |||||
| margin-bottom: 20px; | |||||
| padding: 0 16px; | |||||
| @include border-box; | |||||
| .search-left { | |||||
| color: rgba(29, 112, 217, 1); | |||||
| } | |||||
| .search-right { | |||||
| color: rgba(153, 153, 153, 1); | |||||
| } | |||||
| .search-input { | |||||
| flex: 1; | |||||
| height: 100%; | |||||
| background: transparent; | |||||
| } | |||||
| } | |||||
| .list_box { | |||||
| overflow-y: scroll; | |||||
| height: calc(100vh - 48px - 150px - 84px); | |||||
| // height: calc(100vh - 84px); | |||||
| } | |||||
| &-item { | |||||
| @include size(100%, auto); | |||||
| @include font(12px, $color-black); | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| padding: 10px 15px; | |||||
| @include border-box; | |||||
| margin-bottom: 15px; | |||||
| &-left { | |||||
| @include text-ellipsis-multiple(2); | |||||
| font-weight: bold; | |||||
| } | |||||
| &-right { | |||||
| height: 100%; | |||||
| font-weight: normal; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| margin-top: 10px; | |||||
| } | |||||
| } | |||||
| } | |||||
| :deep() { | |||||
| .van-cell__value, | |||||
| .van-field__body { | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <section class="detail" v-if="!loading"> | |||||
| <div class="box"> | |||||
| <div class="title">{{ policyInfo.policyName }}</div> | |||||
| <div class="subtitle"> | |||||
| <span>发布日期:{{ formatDate(policyInfo.modifiedOn, "YYYY年MM月DD日") }}</span> | |||||
| <span>政策类型:{{ policyInfo.policyType.text }}</span> | |||||
| <span>浏览量:{{ policyInfo.pageView || 0 }}</span> | |||||
| </div> | |||||
| <div class="content" v-html="formatHtml(policyInfo.policyText)"></div> | |||||
| </div> | |||||
| </section> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted } from "vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { formatDate } from "@/utils/common.js"; | |||||
| import { useRoute } from "vue-router"; | |||||
| import SimpleMDE from "simplemde"; | |||||
| const formatHtml = text => { | |||||
| let html = SimpleMDE.prototype.markdown(text); | |||||
| let imgUrl = `${import.meta.env.VITE_BASE_URL}/common/getImg?path=`; | |||||
| html = html.replace( | |||||
| /<img [^>]*src=['"]([^'"]+)[^>]*>/gi, | |||||
| "<img src='" + imgUrl + "$1' width='100%'/>" | |||||
| ); | |||||
| return html; | |||||
| }; | |||||
| const { updatePageView, getReleasePolicyDetail } = getReleasePolicyData(); | |||||
| const loading = ref(true); | |||||
| let policyInfo = ref({}); | |||||
| const $route = useRoute(); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| policyInfo.value = await getReleasePolicyDetail($route.query.releasePolicyId); | |||||
| loading.value = false; | |||||
| updatePageView($route.query.releasePolicyId); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .detail { | |||||
| min-height: calc(100vh - 48px - 150px); | |||||
| padding: 10px 15px; | |||||
| overflow: hidden; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include border-box; | |||||
| .box { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 10px; | |||||
| padding: 12px 0 30px 10px; | |||||
| @include border-box; | |||||
| } | |||||
| .title { | |||||
| @include font(14px, $color-black); | |||||
| font-weight: 500; | |||||
| } | |||||
| .subtitle { | |||||
| @include font(12px, rgba(97, 96, 96, 1)); | |||||
| margin: 20px 0; | |||||
| span { | |||||
| margin-right: 15px; | |||||
| } | |||||
| } | |||||
| .content { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| white-space: pre-wrap; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="container" v-if="!loading"> | |||||
| <van-tabs v-model:active="active" swipeable type="card" :ellipsis="false"> | |||||
| <van-tab | |||||
| v-for="item in dataList" | |||||
| :key="item.attractInvestmentProjectId" | |||||
| :title="item.productName" | |||||
| > | |||||
| <Project :projectItem="item" @doSth="showTipInfo"></Project> | |||||
| </van-tab> | |||||
| </van-tabs> | |||||
| </div> | |||||
| <TipDialog ref="tipRef"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import TipDialog from "@/components/mobile/TipDialog.vue"; | |||||
| import Project from "./Project.vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/project/project"; | |||||
| import { onMounted } from "vue"; | |||||
| const { getList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| const loading = ref(true); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| dataList = await getList(); | |||||
| loading.value = false; | |||||
| }); | |||||
| const active = ref(0); | |||||
| const tipRef = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRef.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .container { | |||||
| padding: 10px 15px; | |||||
| overflow: hidden; | |||||
| background: #fff; | |||||
| @include border-box; | |||||
| min-height: 100%; | |||||
| :deep() { | |||||
| .van-tabs__wrap { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .van-tabs__nav--card { | |||||
| border: none; | |||||
| margin: 0; | |||||
| } | |||||
| .van-tab--card { | |||||
| border-right: none; | |||||
| border-radius: 25px; | |||||
| // margin-right: 8px; | |||||
| color: rgba(0, 0, 0, 1); | |||||
| } | |||||
| .van-tab--card.van-tab--active { | |||||
| color: #fff; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="project"> | |||||
| <img :src="formatImg(propsData.projectItem.productUrl[0])" alt="招商项目图片" /> | |||||
| <div class="project-title">{{ propsData.projectItem.productName }}</div> | |||||
| <div class="project-content"> | |||||
| {{ propsData.projectItem.productText }} | |||||
| </div> | |||||
| <span class="project-consult" @click="doSth">立 即 咨 询</span> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| const emit = defineEmits(["doSth"]); | |||||
| const doSth = () => { | |||||
| emit("doSth"); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .project { | |||||
| // background: rgba(255, 255, 255, 1); | |||||
| // padding: 24px 12px; | |||||
| @include border-box; | |||||
| @include flex(column, flex-start, center, nowrap); | |||||
| margin-bottom: 24px; | |||||
| img { | |||||
| @include font(12px, $color-black); | |||||
| @include size(100%, 238px); | |||||
| border-radius: 20px; | |||||
| margin-bottom: 10px; | |||||
| @include border-box; | |||||
| } | |||||
| &-title { | |||||
| width: 100%; | |||||
| @include font(14px, $color-black); | |||||
| font-weight: bold; | |||||
| } | |||||
| &-content { | |||||
| @include font(12px, $color-black); | |||||
| line-height: 20px; | |||||
| margin: 10px 0; | |||||
| word-break: break-word; | |||||
| white-space: pre-wrap; | |||||
| } | |||||
| &-consult { | |||||
| @include size(290px, 32px); | |||||
| border-radius: 30px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(14px, $color-white); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="block"> | |||||
| <div class="title">{{ propsData.aboutItem.label }}</div> | |||||
| <div class="content" v-html="formatHtml(propsData.aboutItem.value)"></div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| aboutItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| const formatHtml = text => { | |||||
| let html = SimpleMDE.prototype.markdown(text); | |||||
| let imgUrl = `${import.meta.env.VITE_BASE_URL}/common/getImg?path=`; | |||||
| html = html.replace( | |||||
| /<img [^>]*src=['"]([^'"]+)[^>]*>/gi, | |||||
| "<img src='" + imgUrl + "$1' width='100%'/>" | |||||
| ); | |||||
| return html; | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .block { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 10px; | |||||
| padding: 36px; | |||||
| @include border-box; | |||||
| @include flex(column, space-between, center, nowrap); | |||||
| margin-bottom: 24px; | |||||
| .title { | |||||
| @include font(36px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 50px; | |||||
| } | |||||
| .content { | |||||
| @include font(20px, $color-black); | |||||
| line-height: 30px; | |||||
| word-break: break-word; | |||||
| } | |||||
| img { | |||||
| @include size(100%, auto); | |||||
| margin-top: 20px; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="about"> | |||||
| <div class="about-box"> | |||||
| <van-sticky> | |||||
| <div class="form-tab"> | |||||
| <span | |||||
| v-for="item in tabArr" | |||||
| :key="item.value" | |||||
| :class="[currentTab == item.value ? 'active' : '']" | |||||
| @click="changeTab(item.value)" | |||||
| > | |||||
| {{ item.label }} | |||||
| </span> | |||||
| </div> | |||||
| </van-sticky> | |||||
| <template v-if="!loading"> | |||||
| <About | |||||
| :id="'tab' + index" | |||||
| class="scroll-item" | |||||
| v-for="(item, index) in tabArr" | |||||
| :key="item.value" | |||||
| :aboutItem="{ | |||||
| label: item.label, | |||||
| value: homeData[tab[index].key], | |||||
| }" | |||||
| ></About> | |||||
| </template> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted, onUnmounted, ref } from "vue"; | |||||
| import About from "./About.vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| import VueScrollTo from "vue-scrollto"; | |||||
| import { debounce } from "@/utils/common.js"; | |||||
| const homeStore = useHomeStore(); | |||||
| let homeData = ref({}); | |||||
| const tab = [ | |||||
| { | |||||
| label: "区位优势", | |||||
| value: 0, | |||||
| key: "regionalAdvantages", | |||||
| }, | |||||
| { | |||||
| label: "发展机遇", | |||||
| value: 1, | |||||
| key: "developmentOpportunity", | |||||
| }, | |||||
| { | |||||
| label: "配套建设", | |||||
| value: 2, | |||||
| key: "supportingConstruction", | |||||
| }, | |||||
| { | |||||
| label: "发展趋势", | |||||
| value: 3, | |||||
| key: "developmentTendency", | |||||
| }, | |||||
| { | |||||
| label: "交通优势", | |||||
| value: 4, | |||||
| key: "transportationAdvantage", | |||||
| }, | |||||
| { | |||||
| label: "镇域概况", | |||||
| value: 5, | |||||
| key: "townProfile", | |||||
| }, | |||||
| { | |||||
| label: "书院介绍", | |||||
| value: 6, | |||||
| key: "academyHistory", | |||||
| }, | |||||
| ]; | |||||
| const tabArr = ref(tab); | |||||
| const currentTab = ref(0); | |||||
| const loading = ref(true); | |||||
| const changeTab = val => { | |||||
| currentTab.value = val; | |||||
| VueScrollTo.scrollTo(`#tab${val}`, 500, { offset: -132 }); | |||||
| }; | |||||
| const scrollListenerHandler = debounce(() => { | |||||
| const scrollTop = | |||||
| window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; // 滚动条偏移量 | |||||
| document.querySelectorAll(".scroll-item").forEach((item, index) => { | |||||
| if (item.offsetTop - 132 <= scrollTop) { | |||||
| currentTab.value = index; | |||||
| } | |||||
| }); | |||||
| }, 100); | |||||
| onMounted(() => { | |||||
| loading.value = true; | |||||
| homeData.value = homeStore.homeData.value; | |||||
| loading.value = false; | |||||
| window.addEventListener("scroll", scrollListenerHandler); | |||||
| }); | |||||
| onUnmounted(() => { | |||||
| window.removeEventListener("scroll", scrollListenerHandler); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .about { | |||||
| background: rgba(245, 245, 245, 1); | |||||
| &-box { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto; | |||||
| padding: 20px 0 58px; | |||||
| @include border-box; | |||||
| } | |||||
| .form-tab { | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include size($contentWidth, auto); | |||||
| padding: 25px 0; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| @include border-box; | |||||
| span { | |||||
| width: 200px; | |||||
| height: 82px; | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| @include flex(row, center, center, nowrap); | |||||
| border-radius: 20px; | |||||
| cursor: pointer; | |||||
| @include border-box; | |||||
| } | |||||
| .active { | |||||
| @include font(24px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <section class="apply-box"> | |||||
| <div class="form-tab"> | |||||
| <span | |||||
| v-for="(item, index) in tabArr" | |||||
| :class="[currentTb == index ? 'active' : '']" | |||||
| @click="changeTab(item.value, index)" | |||||
| :key="item.value" | |||||
| > | |||||
| {{ item.label }} | |||||
| </span> | |||||
| </div> | |||||
| <div class="form"> | |||||
| <el-form | |||||
| v-if="currentTb == 0" | |||||
| :label-position="labelPosition" | |||||
| label-width="170px" | |||||
| :model="params" | |||||
| style="max-width: 800px" | |||||
| > | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 企业名称 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.companyName" | |||||
| placeholder="请输入企业名称" | |||||
| maxlength="50" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系人 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.name" | |||||
| placeholder="请输入联系人名称" | |||||
| maxlength="10" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系电话 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.mobile" | |||||
| placeholder="请输入联系电话" | |||||
| maxlength="11" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label">预计产税</div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.estimatedPropertyTax" | |||||
| placeholder="请输入预计产税" | |||||
| maxlength="20" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label><div class="form-item-label">需求内容</div></template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.text" | |||||
| type="textarea" | |||||
| rows="10" | |||||
| placeholder="请输入需求内容" | |||||
| resize="none" | |||||
| maxlength="200" | |||||
| /> | |||||
| </el-form-item> | |||||
| </el-form> | |||||
| <el-form | |||||
| v-else | |||||
| :label-position="labelPosition" | |||||
| label-width="170px" | |||||
| :model="params" | |||||
| style="max-width: 800px" | |||||
| > | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 企业名称 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.companyName" | |||||
| placeholder="请输入企业名称" | |||||
| maxlength="50" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系人 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.name" | |||||
| placeholder="请输入联系人名称" | |||||
| maxlength="10" | |||||
| /> | |||||
| </el-form-item> | |||||
| <el-form-item class="form-item"> | |||||
| <template v-slot:label> | |||||
| <div class="form-item-label"> | |||||
| <span class="required">*</span> | |||||
| 联系电话 | |||||
| </div> | |||||
| </template> | |||||
| <el-input | |||||
| class="form-item-content" | |||||
| v-model="params.mobile" | |||||
| placeholder="请输入联系电话" | |||||
| maxlength="11" | |||||
| /> | |||||
| </el-form-item> | |||||
| </el-form> | |||||
| <el-button class="submit" round type="primary" @click="submitForm">提交申请</el-button> | |||||
| <div class="submit-tip">提交后我们将在1-7个工作日内联系您</div> | |||||
| </div> | |||||
| </section> | |||||
| </template> | |||||
| <script setup> | |||||
| import { apply } from "@/views/pc/apply/apply"; | |||||
| const { labelPosition, currentTb, tabArr, params, applyForEntry, changeTab, submitForm } = apply(); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .apply-box { | |||||
| overflow: hidden; | |||||
| background: url(https://img.js.design/assets/img/64acb3a790162375e01752b3.jpg) no-repeat; | |||||
| background-size: 100% 100%; | |||||
| } | |||||
| .form-tab { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 25px auto; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| span { | |||||
| width: 50%; | |||||
| height: 82px; | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| @include flex(row, center, center, nowrap); | |||||
| border-radius: 20px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| cursor: pointer; | |||||
| @include border-box; | |||||
| } | |||||
| .active { | |||||
| @include font(24px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| .form { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto 60px; | |||||
| padding: 45px 220px 30px 178px; | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| text-align: center; | |||||
| &-item { | |||||
| border-radius: 50px; | |||||
| background: rgba(242, 244, 249, 1); | |||||
| padding: 10px 25px 10px 0; | |||||
| @include border-box; | |||||
| &-label { | |||||
| @include font(20px, $color-black); | |||||
| border-right: 3px solid rgba(145, 145, 145, 1); | |||||
| padding-right: 25px; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| .submit { | |||||
| @include size(240px, 68px); | |||||
| @include font(24px, $color-white); | |||||
| border-radius: 34px; | |||||
| @include border-box; | |||||
| margin: 100px 0 52px; | |||||
| } | |||||
| .submit-tip { | |||||
| @include font(20px, $color-black); | |||||
| } | |||||
| } | |||||
| .required { | |||||
| color: rgba(255, 0, 0, 1); | |||||
| } | |||||
| :deep() { | |||||
| .el-input__wrapper, | |||||
| .el-textarea__inner { | |||||
| background: none; | |||||
| box-shadow: none; | |||||
| } | |||||
| } | |||||
| </style> |
| import { addEnter } from "@/apis/index"; | |||||
| import { ref } from "vue"; | |||||
| import { toast, throttle } from "@/utils/common.js"; | |||||
| export function apply() { | |||||
| // tab相关 | |||||
| const currentTb = ref(0); | |||||
| const tabArr = ref([{ | |||||
| label: "我是企业,我要申请入驻", | |||||
| value: "012-01894315f4680185", | |||||
| }, | |||||
| { | |||||
| label: "我是中介,我要合作加入", | |||||
| value: "012-01894315f4690186", | |||||
| }, | |||||
| ]); | |||||
| const changeTab = (val, index) => { | |||||
| params.value = { | |||||
| enterId: "", | |||||
| mobile: "", | |||||
| name: "", | |||||
| companyName: "", | |||||
| type: { | |||||
| text: "012-01894315f4680185", //企业入驻 012-01894315f4680185 中介加入 012-01894315f4690186 | |||||
| }, | |||||
| estimatedPropertyTax: "", | |||||
| }; | |||||
| params.value.type.text = val; | |||||
| currentTb.value = index; | |||||
| }; | |||||
| // 表单相关 | |||||
| const labelPosition = ref("right"); | |||||
| const params = ref({ | |||||
| enterId: "", | |||||
| mobile: "", | |||||
| name: "", | |||||
| companyName: "", | |||||
| type: { | |||||
| text: "012-01894315f4680185", //企业入驻 012-01894315f4680185 中介加入 012-01894315f4690186 | |||||
| }, | |||||
| estimatedPropertyTax: "", | |||||
| }); | |||||
| const applyForEntry = async() => { | |||||
| let data; | |||||
| let res = await addEnter(params); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| const submitForm = throttle(async() => { | |||||
| let { companyName, name, mobile } = params.value; | |||||
| if (!companyName.trim()) { | |||||
| toast("请输入企业名称!", "error"); | |||||
| return; | |||||
| } | |||||
| if (!name.trim()) { | |||||
| toast("请输入联系人名称!", "error"); | |||||
| return; | |||||
| } | |||||
| if (!mobile.trim()) { | |||||
| toast("请输入联系电话!", "error"); | |||||
| return; | |||||
| } | |||||
| let res = await addEnter(params.value); | |||||
| if (res.data.status == 0) { | |||||
| toast("提交成功!", "success"); | |||||
| } | |||||
| }, 500); | |||||
| return { labelPosition, currentTb, tabArr, params, applyForEntry, changeTab, submitForm }; | |||||
| } |
| <template> | |||||
| <div v-if="!loading"> | |||||
| <div class="wrap-box"> | |||||
| <Introduce :homeData="homeData"></Introduce> | |||||
| </div> | |||||
| <div class="project-container"> | |||||
| <div class="wrap-box"><Project></Project></div> | |||||
| </div> | |||||
| <IndustrialCluster :industrialAllocation="industrialAllocation"></IndustrialCluster> | |||||
| <div class="wrap-box"> | |||||
| <Policy v-for="(item, index) in policy" :key="index" :policyItem="item"></Policy> | |||||
| <PicturePolicy | |||||
| :policySupportKeyIndustries="homeData.policySupportKeyIndustries" | |||||
| :domesticTalentIntroduction="homeData.domesticTalentIntroduction" | |||||
| ></PicturePolicy> | |||||
| <template v-if="detailPolicy.length > 0"> | |||||
| <DetailPolicy | |||||
| v-for="(item, index) in detailPolicy" | |||||
| :key="index" | |||||
| :detailPolicyItem="item" | |||||
| ></DetailPolicy> | |||||
| </template> | |||||
| <OtherPolicy></OtherPolicy> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Introduce from "./project/Introduce.vue"; | |||||
| import Project from "./project/Project.vue"; | |||||
| import IndustrialCluster from "./project/IndustrialCluster.vue"; | |||||
| import Policy from "./policy/Policy.vue"; | |||||
| import PicturePolicy from "./policy/PicturePolicy.vue"; | |||||
| import DetailPolicy from "./policy/DetailPolicy.vue"; | |||||
| import OtherPolicy from "./policy/OtherPolicy.vue"; | |||||
| import { getHomeData } from "@/views/pc/home/home"; | |||||
| import { onMounted } from "vue"; | |||||
| const { getAreaIndustrialAllocation, setDetailPolicy, setPolicy, updatePageView } = getHomeData(); | |||||
| let homeData = ref({}); | |||||
| let industrialAllocation = ref([]); | |||||
| let policy = ref([]); | |||||
| let detailPolicy = ref([]); | |||||
| const loading = ref(true); | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| homeData.value = homeStore.homeData.value; | |||||
| policy = setPolicy(homeData.value); | |||||
| detailPolicy = setDetailPolicy(homeData.value); | |||||
| industrialAllocation.value = await getAreaIndustrialAllocation(); | |||||
| loading.value = false; | |||||
| updatePageView(homeData.value.areaInfoManagementId); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .project-container { | |||||
| background: rgba(248, 250, 253, 1); | |||||
| padding: 12px 0; | |||||
| @include border-box; | |||||
| } | |||||
| .wrap-box { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto; | |||||
| } | |||||
| </style> |
| import { | |||||
| getAreaData, | |||||
| getAreaIndustrialAllocationList, | |||||
| updateAreaInfoManagementPageView, | |||||
| getRegistrationPackageByFirst, | |||||
| } from "@/apis/index"; | |||||
| import { toast } from "@/utils/common.js"; | |||||
| export function getHomeData() { | |||||
| // 获取数据 | |||||
| const getData = async() => { | |||||
| let data; | |||||
| try { | |||||
| let res = await getAreaData(); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| toast("获取数据失败,请刷新重试!", "error"); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| // 获取主导产业 | |||||
| const getAreaIndustrialAllocation = async() => { | |||||
| let data; | |||||
| try { | |||||
| let res = await getAreaIndustrialAllocationList(); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| toast("获取主导产业失败,请刷新重试!", "error"); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| // 获取最近那一个编辑或者上架的招商载体 | |||||
| const getRegistrationPackage = async() => { | |||||
| let data; | |||||
| let res = await getRegistrationPackageByFirst(); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| const setDetailPolicy = homeData => { | |||||
| const detailPolicy = ref([]); | |||||
| if (homeData) { | |||||
| const { | |||||
| policyTitle, | |||||
| policyText, | |||||
| policySubtitleI, | |||||
| policyContentI, | |||||
| policySubtitleII, | |||||
| policyContentII, | |||||
| } = homeData; | |||||
| detailPolicy.value = [{ | |||||
| title: policyTitle, | |||||
| content: policyText, | |||||
| }, | |||||
| { | |||||
| title: policySubtitleI, | |||||
| content: policyContentI, | |||||
| }, | |||||
| { | |||||
| title: policySubtitleII, | |||||
| content: policyContentII, | |||||
| }, | |||||
| ]; | |||||
| } | |||||
| return detailPolicy; | |||||
| }; | |||||
| const setPolicy = homeData => { | |||||
| const policy = ref([]); | |||||
| if (homeData) { | |||||
| const { fiscalTaxationPolicy, talentRelatedPolicy, industryRelatedPolicy } = homeData; | |||||
| policy.value = [{ | |||||
| title: "财税政策", | |||||
| content: fiscalTaxationPolicy, | |||||
| color: "#333", | |||||
| bgColor: "rgb(255, 242, 197)", | |||||
| }, | |||||
| { | |||||
| title: "人才相关政策", | |||||
| content: talentRelatedPolicy, | |||||
| color: "#333", | |||||
| bgColor: "rgba(172, 217, 255, 1)", | |||||
| }, | |||||
| { | |||||
| title: "产业相关政策", | |||||
| content: industryRelatedPolicy, | |||||
| color: "#fff", | |||||
| bgColor: "rgba(28, 54, 127, 1)", | |||||
| }, | |||||
| ]; | |||||
| } | |||||
| return policy; | |||||
| }; | |||||
| const updatePageView = async p => { | |||||
| let data; | |||||
| try { | |||||
| let res = await updateAreaInfoManagementPageView(p); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| return { | |||||
| getData, | |||||
| getAreaIndustrialAllocation, | |||||
| setDetailPolicy, | |||||
| setPolicy, | |||||
| updatePageView, | |||||
| getRegistrationPackage, | |||||
| }; | |||||
| } |
| <template> | |||||
| <div class="detail-title">{{ propsData.detailPolicyItem.title }}</div> | |||||
| <div class="detail-policy"> | |||||
| <div | |||||
| class="detail-policy-content" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.detailPolicyItem.content)" | |||||
| ></div> | |||||
| <!-- <div class="detail-policy-content"> | |||||
| 按当年销售金额最高 10% 给予奖励,单款芯片产品年度奖励总额不超过 500 万元。 | |||||
| </div> --> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| // 安装 "simplemde": "^1.11.2", | |||||
| // 安装 "codemirror": "^5.65.14", | |||||
| // 安装 "marked": "^3.0.8", | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| detailPolicyItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .detail-title { | |||||
| @include font(24px, rgba(42, 130, 228, 1)); | |||||
| border-bottom: 3px solid rgba(42, 130, 228, 1); | |||||
| padding: 10px 0 18px; | |||||
| @include border-box; | |||||
| } | |||||
| .detail-policy { | |||||
| padding: 20px 0 14px; | |||||
| @include border-box; | |||||
| &-title { | |||||
| @include font(20px, $color-black); | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include font(18px, $color-black); | |||||
| line-height: 30px; | |||||
| word-break: break-word; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="other-policy" v-if="dataList && dataList.length > 0"> | |||||
| <div class="other-policy-title">其他政策</div> | |||||
| <div class="other-policy-content"> | |||||
| <span | |||||
| v-for="item in dataList" | |||||
| :key="item.releasePolicyId" | |||||
| :title="item.policyName" | |||||
| @click="goRoute(item)" | |||||
| > | |||||
| {{ item.policyName }} | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted } from "vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { routerOpenInNewWindow } from "@/utils/common.js"; | |||||
| const { params, getList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| const loading = ref(true); | |||||
| const getListData = async () => { | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| }; | |||||
| const goRoute = val => { | |||||
| localStorage.setItem("policyInfo", JSON.stringify(val)); | |||||
| routerOpenInNewWindow({ | |||||
| path: "/p_preferential-policy-detail", | |||||
| query: { | |||||
| releasePolicyId: val.releasePolicyId, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| getListData(); | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .other-policy { | |||||
| padding: 16px; | |||||
| @include border-box; | |||||
| margin-bottom: 28px; | |||||
| &-title { | |||||
| @include font(24px, $color-black); | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| &-content { | |||||
| @include flex(row, space-between, flex-start, wrap); | |||||
| @include font(18px, $color-black); | |||||
| line-height: 20px; | |||||
| span { | |||||
| width: 50%; | |||||
| margin-bottom: 20px; | |||||
| @include text-ellipsis; | |||||
| padding-right: 30px; | |||||
| @include border-box; | |||||
| cursor: pointer; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div | |||||
| :class="[ | |||||
| 'picture-box', | |||||
| propsData.policySupportKeyIndustries && | |||||
| propsData.policySupportKeyIndustries.length > 0 && | |||||
| propsData.domesticTalentIntroduction && | |||||
| propsData.domesticTalentIntroduction.length > 0 | |||||
| ? '' | |||||
| : 'box-center', | |||||
| ]" | |||||
| > | |||||
| <div | |||||
| class="picture-policy" | |||||
| v-if=" | |||||
| propsData.policySupportKeyIndustries && | |||||
| propsData.policySupportKeyIndustries.length > 0 | |||||
| " | |||||
| > | |||||
| <div class="picture-policy-title">重点产业扶持政策</div> | |||||
| <img | |||||
| class="picture-policy-content" | |||||
| :src="formatImg(propsData.policySupportKeyIndustries[0])" | |||||
| alt="重点产业扶持政策" | |||||
| /> | |||||
| </div> | |||||
| <div | |||||
| class="picture-policy" | |||||
| v-if=" | |||||
| propsData.domesticTalentIntroduction && | |||||
| propsData.domesticTalentIntroduction.length > 0 | |||||
| " | |||||
| > | |||||
| <div class="picture-policy-title">国内人才引进</div> | |||||
| <img | |||||
| class="picture-policy-content" | |||||
| :src="formatImg(propsData.domesticTalentIntroduction[0])" | |||||
| alt="国内人才引进" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| policySupportKeyIndustries: { | |||||
| type: Array, | |||||
| }, | |||||
| domesticTalentIntroduction: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .picture-box { | |||||
| @include flex(row, space-between, flex-start, nowrap); | |||||
| } | |||||
| .box-center { | |||||
| justify-content: center; | |||||
| } | |||||
| .picture-policy { | |||||
| padding: 10px 22px 0; | |||||
| @include border-box; | |||||
| margin-bottom: 24px; | |||||
| &-title { | |||||
| @include font(20px, $color-black); | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include size(100%, 100%); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div | |||||
| class="policy" | |||||
| :style="{ color: propsData.policyItem.color, background: propsData.policyItem.bgColor }" | |||||
| > | |||||
| <div class="policy-title" :style="{ color: propsData.policyItem.color }"> | |||||
| {{ propsData.policyItem.title }} | |||||
| </div> | |||||
| <div | |||||
| class="policy-content" | |||||
| :style="{ color: propsData.policyItem.color }" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.policyItem.content)" | |||||
| ></div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| // 安装 "simplemde": "^1.11.2", | |||||
| // 安装 "codemirror": "^5.65.14", | |||||
| // 安装 "marked": "^3.0.8", | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| policyItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .policy { | |||||
| background: rgba(255, 242, 197, 1); | |||||
| border-radius: 20px; | |||||
| padding: 16px 12px; | |||||
| @include border-box; | |||||
| margin-bottom: 24px; | |||||
| &-title { | |||||
| font-size: 20px; | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| &-content { | |||||
| font-size: 18px; | |||||
| line-height: 30px; | |||||
| word-break: break-word; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="industrial-park"> | |||||
| <el-carousel :interval="4000" type="card" indicator-position="none"> | |||||
| <el-carousel-item | |||||
| v-for="item in propsData.industrialAllocation" | |||||
| :key="item.areaIndustrialAllocationId" | |||||
| > | |||||
| <!-- <h3 text="2xl" justify="center">{{ item }}</h3> --> | |||||
| <Cluster :data="item"></Cluster> | |||||
| </el-carousel-item> | |||||
| </el-carousel> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Cluster from "@/views/pc/industry/Cluster.vue"; | |||||
| const propsData = defineProps({ | |||||
| industrialAllocation: { | |||||
| type: Array, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .industrial-park { | |||||
| padding: 46px 0; | |||||
| @include border-box; | |||||
| margin-top: 10px; | |||||
| } | |||||
| :deep() { | |||||
| .el-carousel__container { | |||||
| height: auto; | |||||
| min-height: 400px; | |||||
| } | |||||
| .el-carousel__item { | |||||
| border-radius: 10px; | |||||
| } | |||||
| // .van-swipe__indicator { | |||||
| // color: rgba(204, 204, 204, 1); | |||||
| // } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="introduce"> | |||||
| <div class="info"> | |||||
| <div class="info-box"> | |||||
| <div class="info-box-title">区位优势</div> | |||||
| <div> | |||||
| {{ propsData.homeData.academyHistory }} | |||||
| </div> | |||||
| </div> | |||||
| <div class="info-box"> | |||||
| <div class="info-box-title margin-title">镇域概括</div> | |||||
| <ul class="info-ul"> | |||||
| <li> | |||||
| <div class="subtitle">行政区域面积</div> | |||||
| <div> | |||||
| <span class="blue-text"> | |||||
| {{ propsData.homeData.administrativeArea }} | |||||
| </span> | |||||
| 平方公里 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>实有入口</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.actualEntry }}</span> | |||||
| 万 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>下辖</div> | |||||
| <div> | |||||
| <span class="blue-text"> | |||||
| {{ propsData.homeData.haveJurisdictionOver }} | |||||
| </span> | |||||
| 个村 | |||||
| </div> | |||||
| </li> | |||||
| <li> | |||||
| <div>居民区</div> | |||||
| <div> | |||||
| <span class="blue-text">{{ propsData.homeData.residentialArea }}</span> | |||||
| 个 | |||||
| </div> | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| </div> | |||||
| <img | |||||
| v-if="propsData.homeData.parkPicture && propsData.homeData.parkPicture.length > 0" | |||||
| class="introduce-img" | |||||
| :src="formatImg(propsData.homeData.parkPicture[0])" | |||||
| alt="园区图片" | |||||
| /> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| homeData: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .introduce { | |||||
| margin: 56px auto; | |||||
| @include flex(row, space-between, stretch, nowrap); | |||||
| &-img { | |||||
| @include size(550px, auto); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| } | |||||
| } | |||||
| .info { | |||||
| flex: 1; | |||||
| padding-right: 52px; | |||||
| @include border-box; | |||||
| &-box { | |||||
| @include font(20px, $color-black); | |||||
| &-title { | |||||
| @include font(24px, $color-black); | |||||
| margin-bottom: 36px; | |||||
| } | |||||
| } | |||||
| } | |||||
| .margin-title { | |||||
| margin-top: 48px; | |||||
| } | |||||
| .info-ul { | |||||
| @include flex(row, space-between, flex-start, wrap); | |||||
| li { | |||||
| width: 50%; | |||||
| margin-top: 24px; | |||||
| } | |||||
| .subtitle { | |||||
| @include font(20px, $color-black); | |||||
| } | |||||
| .blue-text { | |||||
| @include font(48px, rgba(0, 153, 255, 1)); | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="project"> | |||||
| <ul class="project-left"> | |||||
| <li class="active">招商载体</li> | |||||
| <li @click="toPath('/p_industry-park', 1)">企业链家</li> | |||||
| <li @click="toPath('/p_apply-for-entry')"> | |||||
| <div> | |||||
| 我是企业 | |||||
| <br /> | |||||
| 我要入驻 | |||||
| </div> | |||||
| <el-icon size="30px"><Right /></el-icon> | |||||
| </li> | |||||
| </ul> | |||||
| <div class="project-right" v-if="!loading"> | |||||
| <ProjectItem :projectItem="registrationPackage"></ProjectItem> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { Right } from "@element-plus/icons-vue"; // 引入 Edit 这个 svg组件 | |||||
| import ProjectItem from "./ProjectItem.vue"; | |||||
| import { getHomeData } from "../home"; | |||||
| import { onBeforeMount } from "vue"; | |||||
| import { useRoute, useRouter } from "vue-router"; //1.引入路由 | |||||
| const $router = useRouter(); //2.实例化路由 | |||||
| const { getRegistrationPackage } = getHomeData(); | |||||
| let registrationPackage = ref({}); | |||||
| const loading = ref(true); | |||||
| onBeforeMount(async () => { | |||||
| loading.value = true; | |||||
| registrationPackage.value = await getRegistrationPackage(); | |||||
| loading.value = false; | |||||
| }); | |||||
| const toPath = (path, tab) => { | |||||
| $router.push({ | |||||
| path, | |||||
| query: { | |||||
| tab, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .project { | |||||
| @include flex(row, space-between, flex-start, nowrap); | |||||
| &-left { | |||||
| width: 282px; | |||||
| li { | |||||
| @include size(100%, 130px); | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| background: linear-gradient( | |||||
| 90deg, | |||||
| rgba(0, 134, 231, 0.2) 0%, | |||||
| rgba(0, 136, 230, 0) 100% | |||||
| ); | |||||
| margin-bottom: 5px; | |||||
| border-radius: 20px; | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include border-box; | |||||
| cursor: pointer; | |||||
| } | |||||
| .active { | |||||
| background: linear-gradient(90deg, rgba(0, 134, 231, 1) 0%, rgba(0, 136, 230, 0) 100%); | |||||
| @include font(24px, $color-white); | |||||
| } | |||||
| } | |||||
| &-right { | |||||
| flex: 1; | |||||
| } | |||||
| .el-icon { | |||||
| margin-left: 20px; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="project"> | |||||
| <img :src="formatImg(propsData.projectItem.productUrl[0])" alt="招商项目图片" /> | |||||
| <div class="project-right"> | |||||
| <div class="content"> | |||||
| <span class="content-title">{{ propsData.projectItem.productName }}</span> | |||||
| <div class="content-content" :title="propsData.projectItem.productText"> | |||||
| {{ propsData.projectItem.productText }} | |||||
| </div> | |||||
| </div> | |||||
| <span class="project-right-consult" @click="showTipInfo">立 即 咨 询</span> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRefPC"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| import TipDialog from "@/components/pc/TipDialogPC.vue"; | |||||
| const tipRefPC = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRefPC.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .project { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 10px; | |||||
| padding: 24px 20px; | |||||
| @include border-box; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| img { | |||||
| @include size(496px, 352px); | |||||
| margin-right: 25px; | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| } | |||||
| &-right { | |||||
| flex: 1; | |||||
| @include size(auto, 352px); | |||||
| @include flex(column, space-between, flex-start, nowrap); | |||||
| .content { | |||||
| flex: 1; | |||||
| padding-bottom: 20px; | |||||
| @include flex(column, flex-start, flex-start, nowrap); | |||||
| &-title { | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 400; | |||||
| margin-bottom: 10px; | |||||
| } | |||||
| &-content { | |||||
| @include font(18px, $color-black); | |||||
| line-height: 26px; | |||||
| @include text-ellipsis-multiple(10); | |||||
| } | |||||
| } | |||||
| &-consult { | |||||
| @include size(242px, 42px); | |||||
| margin: 0 auto; | |||||
| border-radius: 50px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(20px, $color-white); | |||||
| cursor: pointer; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div | |||||
| class="cluster" | |||||
| :style="{ | |||||
| backgroundImage: 'url(' + formatImg(propsData.data.productUrl[0]) + ')', | |||||
| minHeight: $route.path === '/p_industry-park' ? auto : '500px', | |||||
| }" | |||||
| > | |||||
| <div class="cluster-title">{{ propsData.data.leadingIndustryName }}</div> | |||||
| <div | |||||
| class="cluster-content" | |||||
| v-html="SimpleMDE.prototype.markdown(propsData.data.leadingIndustryDetail)" | |||||
| ></div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import SimpleMDE from "simplemde"; | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| import { useRoute } from "vue-router"; //1.引入路由 | |||||
| const $route = useRoute(); //2.实例化路由 | |||||
| const propsData = defineProps({ | |||||
| data: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .cluster { | |||||
| position: relative; | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 10px; | |||||
| padding: 35px 40px 35px 32px; | |||||
| @include border-box; | |||||
| @include flex(column, flex-start, flex-start, nowrap); | |||||
| margin-bottom: 24px; | |||||
| // @include bg-image("https://img.js.design/assets/img/64abb2f1eec7205596b5791f.jpg"); | |||||
| background-size: 100% 100%; | |||||
| background-repeat: no-repeat; | |||||
| &-title { | |||||
| @include font(36px, $color-white); | |||||
| font-weight: bold; | |||||
| margin-bottom: 20px; | |||||
| z-index: 100; | |||||
| } | |||||
| &-content { | |||||
| @include font(20px, $color-white); | |||||
| line-height: 30px; | |||||
| @include text-ellipsis-multiple(8); | |||||
| word-break: break-word; | |||||
| z-index: 100; | |||||
| } | |||||
| } | |||||
| .cluster:before { | |||||
| content: ""; | |||||
| position: absolute; | |||||
| top: 0; | |||||
| left: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| border-radius: 10px; | |||||
| background-color: rgba(0, 0, 0, 0.5); | |||||
| @include border-box; | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="enterprise_item_box"> | |||||
| <div class="block-title"> | |||||
| <span>{{ propsData.projectItem.element.text }}</span> | |||||
| </div> | |||||
| <div class="enterprise_item"> | |||||
| <div | |||||
| class="enterprise" | |||||
| v-for="item in propsData.projectItem.enterpriseData" | |||||
| :key="item.enterpriseHomeLinkId" | |||||
| > | |||||
| <img :src="formatImg(item.url[0])" alt="图片" /> | |||||
| <div class="enterprise-right"> | |||||
| <div class="content"> | |||||
| <div | |||||
| class="content-title" | |||||
| v-html="SimpleMDE.prototype.markdown(item.detail)" | |||||
| ></div> | |||||
| </div> | |||||
| <span class="enterprise-right-consult" @click="showTipInfo">立 即 咨 询</span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRefPC"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| import SimpleMDE from "simplemde"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| import TipDialog from "@/components/pc/TipDialogPC.vue"; | |||||
| const tipRefPC = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRefPC.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .enterprise_item_box { | |||||
| margin-bottom: 40px; | |||||
| } | |||||
| .block-title { | |||||
| @include flex(row, center, center, nowrap); | |||||
| span { | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| border-top-left-radius: 50px; | |||||
| border-top-right-radius: 50px; | |||||
| background: rgba(255, 255, 255, 1); | |||||
| padding: 10px 70px; | |||||
| max-width: $contentWidth; | |||||
| } | |||||
| } | |||||
| .enterprise_item { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| @include border-box; | |||||
| } | |||||
| .enterprise { | |||||
| padding: 24px 12px; | |||||
| @include border-box; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| img { | |||||
| @include size(766px, 460px); | |||||
| margin-right: 32px; | |||||
| } | |||||
| &-right { | |||||
| flex: 1; | |||||
| @include size(auto, 460px); | |||||
| @include flex(column, space-between, flex-start, nowrap); | |||||
| .content { | |||||
| flex: 1; | |||||
| padding-bottom: 20px; | |||||
| @include flex(column, flex-start, flex-start, nowrap); | |||||
| &-title { | |||||
| // p { | |||||
| @include font(20px, $color-black); | |||||
| font-weight: 400; | |||||
| margin-bottom: 25px; | |||||
| word-break: break-word; | |||||
| // } | |||||
| } | |||||
| } | |||||
| &-consult { | |||||
| @include size(100%, 50px); | |||||
| border-radius: 50px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(20px, $color-white); | |||||
| cursor: pointer; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="industry"> | |||||
| <div class="box"> | |||||
| <div class="form-tab"> | |||||
| <span | |||||
| v-for="item in tabArr" | |||||
| :key="item.value" | |||||
| :class="[currentTab == item.value ? 'active' : '']" | |||||
| @click="changeTab(item.value)" | |||||
| > | |||||
| {{ item.label }} | |||||
| </span> | |||||
| </div> | |||||
| <div v-loading="loading" class="tab_content"> | |||||
| <template v-if="!loading"> | |||||
| <template v-if="currentTab == 0"> | |||||
| <InvestmentVehicle | |||||
| v-for="item in registrationPackageList" | |||||
| :key="item.registrationPackageId" | |||||
| :projectItem="item" | |||||
| ></InvestmentVehicle> | |||||
| </template> | |||||
| <template v-if="currentTab == 1"> | |||||
| <Enterprise | |||||
| v-for="item in enterpriseData" | |||||
| :key="item.element.itemId" | |||||
| :projectItem="item" | |||||
| ></Enterprise> | |||||
| </template> | |||||
| <template v-if="currentTab == 2"> | |||||
| <Cluster | |||||
| v-for="item in industrialAllocation" | |||||
| :key="item.areaIndustrialAllocationId" | |||||
| :data="item" | |||||
| ></Cluster> | |||||
| </template> | |||||
| </template> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Cluster from "./Cluster.vue"; | |||||
| import Enterprise from "./Enterprise.vue"; | |||||
| import InvestmentVehicle from "../project/Project.vue"; | |||||
| import { getIndustryData } from "@/views/pc/industry/getRegistrationPackageList"; | |||||
| import { useRoute } from "vue-router"; //1.引入路由 | |||||
| import { onMounted } from "vue"; | |||||
| const $route = useRoute(); //2.实例化路由 | |||||
| let { | |||||
| loading, | |||||
| tabArr, | |||||
| currentTab, | |||||
| changeTab, | |||||
| registrationPackageList, | |||||
| enterpriseData, | |||||
| industrialAllocation, | |||||
| } = getIndustryData(); | |||||
| onMounted(() => { | |||||
| loading.value = true; | |||||
| if ($route.query.tab) { | |||||
| changeTab($route.query.tab); | |||||
| } else { | |||||
| changeTab(0); | |||||
| } | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .industry { | |||||
| padding: 30px 0 58px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| .box { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto; | |||||
| } | |||||
| .form-tab { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 25px auto; | |||||
| @include flex(row, flex-start, center, nowrap); | |||||
| span { | |||||
| width: 200px; | |||||
| height: 82px; | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| @include flex(row, center, center, nowrap); | |||||
| border-radius: 20px; | |||||
| cursor: pointer; | |||||
| @include border-box; | |||||
| } | |||||
| .active { | |||||
| @include font(24px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| } | |||||
| .tab_content { | |||||
| min-height: 600px; | |||||
| } | |||||
| } | |||||
| </style> |
| import { | |||||
| getPickListByKey, | |||||
| getRegistrationPackageList, | |||||
| getAreaIndustrialAllocationList, | |||||
| getEnterpriseHomeLinkList, | |||||
| } from "@/apis/index"; | |||||
| import { ref } from "vue"; | |||||
| import { toast, sortByKey } from "@/utils/common.js"; | |||||
| const loading = ref(true); | |||||
| const tabArr = ref([{ | |||||
| label: "招商载体", | |||||
| value: 0, | |||||
| }, | |||||
| { | |||||
| label: '企业"链家"', | |||||
| value: 1, | |||||
| }, | |||||
| { | |||||
| label: "产业聚集", | |||||
| value: 2, | |||||
| }, | |||||
| ]); | |||||
| const currentTab = ref(0); | |||||
| let registrationPackageList = ref([]); | |||||
| let enterpriseData = ref([]); | |||||
| let industrialAllocation = ref([]); | |||||
| const pickList = []; | |||||
| export function getIndustryData() { | |||||
| const changeTab = async val => { | |||||
| currentTab.value = val; | |||||
| getData(val); | |||||
| }; | |||||
| const getPickList = temp => { | |||||
| const params = { | |||||
| key: "shitiwuyeshangjia_lianjialeixing", | |||||
| }; | |||||
| let data; | |||||
| getPickListByKey(params) | |||||
| .then(res => { | |||||
| if (res.data.status == 0) { | |||||
| data = sortByKey(res.data.data, "seq"); | |||||
| pickList.value = data; | |||||
| enterpriseData.value = setEnterpriseData(pickList.value, temp); | |||||
| console.log(enterpriseData.value); | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| }) | |||||
| .catch(error => { | |||||
| console.log(error); | |||||
| }); | |||||
| }; | |||||
| const getData = async tab => { | |||||
| registrationPackageList.value = []; | |||||
| enterpriseData.value = []; | |||||
| industrialAllocation.value = []; | |||||
| loading.value = true; | |||||
| let data; | |||||
| let res; | |||||
| if (tab == 0) { | |||||
| res = await getRegistrationPackageList(); | |||||
| } else if (tab == 1) { | |||||
| res = await getEnterpriseHomeLinkList(); | |||||
| } else { | |||||
| res = await getAreaIndustrialAllocationList(); | |||||
| } | |||||
| try { | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| if (tab == 0) { | |||||
| registrationPackageList.value = data; | |||||
| } else if (tab == 1) { | |||||
| getPickList(data); | |||||
| } else { | |||||
| industrialAllocation.value = data; | |||||
| } | |||||
| loading.value = false; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| toast("获取数据失败,请刷新重试!", "error"); | |||||
| } | |||||
| }; | |||||
| const setEnterpriseData = (typeArr, data) => { | |||||
| let arr = []; | |||||
| typeArr.forEach(element => { | |||||
| arr.push({ | |||||
| element, | |||||
| enterpriseData: data.filter(item => item.homeLinkType.id === element.itemId), | |||||
| }); | |||||
| }); | |||||
| return arr; | |||||
| }; | |||||
| return { | |||||
| loading, | |||||
| tabArr, | |||||
| currentTab, | |||||
| changeTab, | |||||
| getData, | |||||
| registrationPackageList, | |||||
| enterpriseData, | |||||
| industrialAllocation, | |||||
| }; | |||||
| } |
| <template> | |||||
| <div class="policy" v-if="!loading"> | |||||
| <div class="policy-search"> | |||||
| <el-input | |||||
| v-model="params.search" | |||||
| placeholder="" | |||||
| class="input-with-select" | |||||
| clearable | |||||
| @clear="toSearch" | |||||
| @keyup.enter="toSearch" | |||||
| > | |||||
| <template #prepend> | |||||
| <el-select | |||||
| v-model="params.policyTypeId" | |||||
| placeholder="全部" | |||||
| @change="changeSelect" | |||||
| > | |||||
| <el-option label="全部" value="全部"></el-option> | |||||
| <el-option | |||||
| v-for="item in selectList" | |||||
| :key="item.itemId" | |||||
| :label="item.text" | |||||
| :value="item.itemId" | |||||
| /> | |||||
| </el-select> | |||||
| </template> | |||||
| <template #append> | |||||
| <el-button :icon="Search" @click="toSearch">搜索</el-button> | |||||
| </template> | |||||
| </el-input> | |||||
| </div> | |||||
| <section v-loading="dataLoading"> | |||||
| <ul class="policy-ul" v-if="dataList && dataList.length > 0"> | |||||
| <li | |||||
| class="policy-item" | |||||
| v-for="item in dataList" | |||||
| :key="item.releasePolicyId" | |||||
| @click="goRoute(item)" | |||||
| > | |||||
| <div class="policy-item-left">{{ item.policyName }}</div> | |||||
| <div class="policy-item-right"> | |||||
| <span>政策类型:{{ item.policyType.text }}</span> | |||||
| <span>发布时间:{{ formatDate(item.modifiedOn, "YYYY.MM.DD") }}</span> | |||||
| </div> | |||||
| </li> | |||||
| </ul> | |||||
| <section class="listNull" v-else> | |||||
| <img src="@/assets/icon-no-data.png" alt="暂无数据" /> | |||||
| </section> | |||||
| </section> | |||||
| <div class="pagination" v-if="dataList && dataList.length > 0"> | |||||
| <el-pagination | |||||
| v-model:current-page="params.page" | |||||
| background | |||||
| layout="prev, pager, next" | |||||
| :page-size="params.pageSize" | |||||
| :total="total" | |||||
| @current-change="handleCurrentChange" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import { Search } from "@element-plus/icons-vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { formatDate, sortByKey, routerOpenInNewWindow } from "@/utils/common.js"; | |||||
| import { onMounted } from "vue"; | |||||
| import useHomeStore from "@/store/module/home"; | |||||
| const homeStore = useHomeStore(); | |||||
| const { params, getList, getPickList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| let selectList = ref([]); | |||||
| let total = ref(0); | |||||
| const loading = ref(true); | |||||
| const dataLoading = ref(false); | |||||
| const changeSelect = async val => { | |||||
| params.value.policyTypeId = val == "全部" ? "" : val; | |||||
| params.value.page = 1; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| }; | |||||
| const toSearch = async () => { | |||||
| dataLoading.value = true; | |||||
| params.value.page = 1; | |||||
| params.value.pageSize = 10; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| dataLoading.value = false; | |||||
| }; | |||||
| const handleCurrentChange = async val => { | |||||
| params.value.page = val; | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| }; | |||||
| const goRoute = val => { | |||||
| routerOpenInNewWindow({ | |||||
| path: "/p_preferential-policy-detail", | |||||
| query: { | |||||
| releasePolicyId: val.releasePolicyId, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| let pickArr = await getPickList(); | |||||
| selectList.value = sortByKey(pickArr, "seq"); | |||||
| let dataObj = await getList(params); | |||||
| dataList.value = dataObj.list; | |||||
| total.value = dataObj.total; | |||||
| loading.value = false; | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .policy { | |||||
| // width: 1180px; | |||||
| padding: 30px 0 68px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| @include border-box; | |||||
| &-search { | |||||
| @include size(726px, 50px); | |||||
| margin: 0 auto 25px; | |||||
| border-radius: 25px; | |||||
| border: 2px solid rgba(29, 112, 217, 1); | |||||
| @include border-box; | |||||
| background: #fff; | |||||
| } | |||||
| .listNull { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 20px auto 40px; | |||||
| @include flex(row, center, center, nowrap); | |||||
| } | |||||
| &-item { | |||||
| @include size($contentWidth, 100px); | |||||
| margin: 0 auto; | |||||
| @include font(18px, $color-black); | |||||
| background: rgba(255, 255, 255, 1); | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| padding: 20px 18px 24px 34px; | |||||
| border-radius: 25px; | |||||
| @include border-box; | |||||
| margin-bottom: 30px; | |||||
| cursor: pointer; | |||||
| &-left { | |||||
| flex: 1; | |||||
| @include text-ellipsis-multiple(2); | |||||
| } | |||||
| &-right { | |||||
| height: 100%; | |||||
| padding-left: 94px; | |||||
| @include flex(column, space-between, flex-end, nowrap); | |||||
| } | |||||
| } | |||||
| } | |||||
| .pagination { | |||||
| @include flex(row, center, center, nowrap); | |||||
| } | |||||
| :deep() { | |||||
| .el-input-group, | |||||
| .el-input, | |||||
| .el-select, | |||||
| .select-trigger, | |||||
| .el-input__wrapper { | |||||
| height: 100%; | |||||
| background: transparent; | |||||
| border: none !important; | |||||
| box-shadow: none !important; | |||||
| } | |||||
| .el-select { | |||||
| width: 160px; | |||||
| border: none !important; | |||||
| box-shadow: none !important; | |||||
| } | |||||
| .el-input-group--prepend | |||||
| .el-input-group__prepend | |||||
| .el-select | |||||
| .el-input.is-focus | |||||
| .el-input__wrapper { | |||||
| box-shadow: none !important; | |||||
| border: none; | |||||
| } | |||||
| .el-input__wrapper { | |||||
| box-shadow: none !important; | |||||
| } | |||||
| .el-input-group__append { | |||||
| border-top-right-radius: 25px; | |||||
| border-bottom-right-radius: 25px; | |||||
| background: transparent; | |||||
| } | |||||
| .el-input-group__prepend { | |||||
| border-top-left-radius: 25px; | |||||
| border-bottom-left-radius: 25px; | |||||
| background: transparent; | |||||
| box-shadow: none; | |||||
| .el-input__wrapper { | |||||
| padding-left: 25px; | |||||
| } | |||||
| } | |||||
| .el-input-group--prepend .el-input-group__prepend .el-select:hover .el-input__wrapper { | |||||
| box-shadow: none !important; | |||||
| } | |||||
| .el-button { | |||||
| display: inline-flex; | |||||
| } | |||||
| .el-select .el-input__wrapper.is-focus { | |||||
| box-shadow: none !important; | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <section class="detail" v-if="!loading"> | |||||
| <div class="title">{{ policyInfo.policyName }}</div> | |||||
| <div class="subtitle"> | |||||
| <span>发布日期:{{ formatDate(policyInfo.modifiedOn, "YYYY年MM月DD日") }}</span> | |||||
| <span>政策类型:{{ policyInfo.policyType.text }}</span> | |||||
| <span>浏览量:{{ policyInfo.pageView || 0 }}</span> | |||||
| </div> | |||||
| <div class="content" v-html="formatHtml(policyInfo.policyText)"></div> | |||||
| </section> | |||||
| </template> | |||||
| <script setup> | |||||
| import { onMounted } from "vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/policy/policy"; | |||||
| import { formatDate } from "@/utils/common.js"; | |||||
| import { useRoute } from "vue-router"; | |||||
| import SimpleMDE from "simplemde"; | |||||
| const formatHtml = text => { | |||||
| let html = SimpleMDE.prototype.markdown(text); | |||||
| let imgUrl = `${import.meta.env.VITE_BASE_URL}/common/getImg?path=`; | |||||
| html = html.replace( | |||||
| /<img [^>]*src=['"]([^'"]+)[^>]*>/gi, | |||||
| "<img src='" + imgUrl + "$1' width='100%'/>" | |||||
| ); | |||||
| return html; | |||||
| }; | |||||
| const { updatePageView, getReleasePolicyDetail } = getReleasePolicyData(); | |||||
| const loading = ref(true); | |||||
| let policyInfo = ref({}); | |||||
| const $route = useRoute(); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| policyInfo.value = await getReleasePolicyDetail($route.query.releasePolicyId); | |||||
| loading.value = false; | |||||
| updatePageView($route.query.releasePolicyId); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .detail { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto; | |||||
| padding: 60px 0 58px; | |||||
| .title { | |||||
| @include font(24px, $color-black); | |||||
| font-weight: bold; | |||||
| } | |||||
| .subtitle { | |||||
| @include font(18px, rgba(97, 96, 96, 1)); | |||||
| margin: 20px 0 30px; | |||||
| span { | |||||
| margin-right: 100px; | |||||
| } | |||||
| } | |||||
| .content { | |||||
| @include font(16px, $color-black); | |||||
| line-height: 34px; | |||||
| white-space: pre-wrap; | |||||
| } | |||||
| } | |||||
| </style> |
| import { | |||||
| getReleasePolicyList, | |||||
| getPickListByKey, | |||||
| updateReleasePolicyPageView, | |||||
| getReleasePolicyById, | |||||
| } from "@/apis/index"; | |||||
| import { ref } from "vue"; | |||||
| import { toast } from "@/utils/common.js"; | |||||
| export function getReleasePolicyData() { | |||||
| const params = ref({ | |||||
| policyTypeId: "", | |||||
| search: "", | |||||
| page: 1, | |||||
| pageSize: 10, | |||||
| }); | |||||
| const getList = async params => { | |||||
| let data; | |||||
| try { | |||||
| let res = await getReleasePolicyList(params.value); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| toast("获取数据失败,请刷新重试!", "error"); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| const getPickList = async() => { | |||||
| const params = { | |||||
| key: "zhengcefabuguanli_zhengceleixing", | |||||
| }; | |||||
| let data; | |||||
| try { | |||||
| let res = await getPickListByKey(params); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| toast("获取数据失败,请刷新重试!", "error"); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| const getReleasePolicyDetail = async releasePolicyId => { | |||||
| let data; | |||||
| try { | |||||
| let res = await getReleasePolicyById({ releasePolicyId }); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| const updatePageView = async p => { | |||||
| let data; | |||||
| try { | |||||
| let res = await updateReleasePolicyPageView(p); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| } | |||||
| return data; | |||||
| }; | |||||
| return { params, getList, getPickList, updatePageView, getReleasePolicyDetail }; | |||||
| } |
| <template> | |||||
| <div class="investment"> | |||||
| <div class="container" v-if="!loading"> | |||||
| <van-sticky class="form-tab"> | |||||
| <el-tabs | |||||
| class="wd-tabs" | |||||
| type="card" | |||||
| :stretch="true" | |||||
| v-model="currentTab" | |||||
| @tab-click="changeTab" | |||||
| > | |||||
| <el-tab-pane | |||||
| v-for="(item, index) in dataList" | |||||
| :key="item.attractInvestmentProjectId" | |||||
| :label="item.productName" | |||||
| :name="index" | |||||
| ></el-tab-pane> | |||||
| </el-tabs> | |||||
| </van-sticky> | |||||
| <div | |||||
| v-for="(item, index) in dataList" | |||||
| :key="item.attractInvestmentProjectId" | |||||
| class="form-right scroll-item" | |||||
| scroll-item | |||||
| :id="'tab' + index" | |||||
| > | |||||
| <Project :projectItem="item"></Project> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script setup> | |||||
| import Project from "./Project.vue"; | |||||
| import { getReleasePolicyData } from "@/views/pc/project/project"; | |||||
| import { onMounted, onUnmounted, ref } from "vue"; | |||||
| import VueScrollTo from "vue-scrollto"; | |||||
| import { debounce } from "@/utils/common.js"; | |||||
| const { getList } = getReleasePolicyData(); | |||||
| let dataList = ref([]); | |||||
| const currentTab = ref(0); | |||||
| const loading = ref(false); | |||||
| const changeTab = targetName => { | |||||
| currentTab.value = targetName.paneName; | |||||
| VueScrollTo.scrollTo(`#tab${targetName.paneName}`, 500, { offset: -84 }); | |||||
| }; | |||||
| const scrollListenerHandler = debounce(() => { | |||||
| const scrollTop = | |||||
| window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; // 滚动条偏移量 | |||||
| document.querySelectorAll(".scroll-item").forEach((item, index) => { | |||||
| if (item.offsetTop - 84 <= scrollTop) { | |||||
| currentTab.value = index; | |||||
| } | |||||
| }); | |||||
| }, 100); | |||||
| onMounted(async () => { | |||||
| loading.value = true; | |||||
| dataList = await getList(); | |||||
| loading.value = false; | |||||
| window.addEventListener("scroll", scrollListenerHandler); | |||||
| }); | |||||
| onUnmounted(() => { | |||||
| window.removeEventListener("scroll", scrollListenerHandler); | |||||
| }); | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .investment { | |||||
| padding: 30px 0 58px; | |||||
| background: rgba(245, 245, 245, 1); | |||||
| } | |||||
| .container { | |||||
| @include size($contentWidth, auto); | |||||
| margin: 0 auto; | |||||
| // @include flex(row, space-between, flex-start, nowrap); | |||||
| .form-tab { | |||||
| margin: 24px auto; | |||||
| } | |||||
| .form-right { | |||||
| width: 100%; | |||||
| } | |||||
| :deep() { | |||||
| .el-tabs--card > .el-tabs__header { | |||||
| background: rgba(245, 245, 245, 1); | |||||
| height: 82px; | |||||
| border: none; | |||||
| } | |||||
| .el-tabs__nav-next, | |||||
| .el-tabs__nav-prev { | |||||
| line-height: 82px; | |||||
| } | |||||
| .el-tabs--card > .el-tabs__header .el-tabs__nav { | |||||
| border: none; | |||||
| } | |||||
| .el-tabs--card > .el-tabs__header .el-tabs__item { | |||||
| width: auto; | |||||
| height: 82px; | |||||
| border-radius: 20px; | |||||
| border: none; | |||||
| @include font(24px, $color-black); | |||||
| font-weight: 500; | |||||
| } | |||||
| .el-tabs--card > .el-tabs__header .el-tabs__item.is-active { | |||||
| @include font(24px, $color-white); | |||||
| background: rgba(0, 153, 255, 1); | |||||
| } | |||||
| .el-tabs__item { | |||||
| // width: 200px; | |||||
| // height: 82px; | |||||
| // @include font(24px, $color-black); | |||||
| // font-weight: 500; | |||||
| // @include flex(row, center, center, nowrap); | |||||
| // border-radius: 20px; | |||||
| // cursor: pointer; | |||||
| // @include border-box; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| <template> | |||||
| <div class="project"> | |||||
| <img :src="formatImg(propsData.projectItem.productUrl[0])" alt="招商项目图片" /> | |||||
| <div class="project-right"> | |||||
| <div class="content"> | |||||
| <span class="content-title">{{ propsData.projectItem.productName }}</span> | |||||
| <div class="content-content" :title="propsData.projectItem.productText"> | |||||
| {{ propsData.projectItem.productText }} | |||||
| </div> | |||||
| </div> | |||||
| <span class="project-right-consult" @click="showTipInfo">立 即 咨 询</span> | |||||
| </div> | |||||
| </div> | |||||
| <TipDialog ref="tipRefPC"></TipDialog> | |||||
| </template> | |||||
| <script setup> | |||||
| import { formatImg } from "@/utils/common.js"; | |||||
| const propsData = defineProps({ | |||||
| projectItem: { | |||||
| type: Object, | |||||
| }, | |||||
| }); | |||||
| import TipDialog from "@/components/pc/TipDialogPC.vue"; | |||||
| const tipRefPC = ref(null); | |||||
| const showTipInfo = () => { | |||||
| tipRefPC.value.showTip(); | |||||
| }; | |||||
| </script> | |||||
| <style lang="scss" scoped> | |||||
| .project { | |||||
| background: rgba(255, 255, 255, 1); | |||||
| border-radius: 20px; | |||||
| padding: 24px 12px; | |||||
| @include border-box; | |||||
| @include flex(row, space-between, center, nowrap); | |||||
| margin-bottom: 24px; | |||||
| img { | |||||
| @include size(526px, 460px); | |||||
| margin-right: 32px; | |||||
| } | |||||
| &-right { | |||||
| flex: 1; | |||||
| @include size(auto, 460px); | |||||
| @include flex(column, space-between, flex-start, nowrap); | |||||
| .content { | |||||
| flex: 1; | |||||
| padding-bottom: 20px; | |||||
| @include flex(column, flex-start, flex-start, nowrap); | |||||
| &-title { | |||||
| @include font(24px, $color-black); | |||||
| font-weight: bold; | |||||
| margin-bottom: 25px; | |||||
| } | |||||
| &-content { | |||||
| @include font(18px, $color-black); | |||||
| line-height: 30px; | |||||
| @include text-ellipsis-multiple(11); | |||||
| white-space: pre-wrap; | |||||
| } | |||||
| } | |||||
| &-consult { | |||||
| @include size(100%, 50px); | |||||
| border-radius: 50px; | |||||
| background: rgba(0, 153, 255, 1); | |||||
| @include flex(row, center, center, nowrap); | |||||
| @include font(20px, $color-white); | |||||
| cursor: pointer; | |||||
| } | |||||
| } | |||||
| } | |||||
| </style> |
| import { getAttractInvestmentProjectList } from "@/apis/index"; | |||||
| import { ref } from "vue"; | |||||
| import { toast } from "@/utils/common.js"; | |||||
| export function getReleasePolicyData() { | |||||
| const getList = async() => { | |||||
| let data; | |||||
| try { | |||||
| let res = await getAttractInvestmentProjectList(); | |||||
| if (res.data.status == 0) { | |||||
| data = res.data.data; | |||||
| } else { | |||||
| toast(res.data.msg, "error"); | |||||
| } | |||||
| } catch (error) { | |||||
| toast("获取数据失败,请刷新重试!", "error"); | |||||
| } | |||||
| return ref(data); | |||||
| }; | |||||
| return { getList }; | |||||
| } |
| import { defineConfig, loadEnv } from "vite"; | |||||
| import vue from "@vitejs/plugin-vue"; | |||||
| import { resolve } from "path"; | |||||
| import AutoImport from "unplugin-auto-import/vite"; | |||||
| import Components from "unplugin-vue-components/vite"; | |||||
| // 按需引入 ElementPlus vant | |||||
| import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; | |||||
| import { VantResolver } from "unplugin-vue-components/resolvers"; | |||||
| // 生成.gz文件 | |||||
| import viteCompression from "vite-plugin-compression"; | |||||
| // https://vitejs.dev/config/ | |||||
| export default defineConfig(({ mode }) => { | |||||
| let env = loadEnv(mode, process.cwd()); | |||||
| return { | |||||
| plugins: [ | |||||
| vue(), | |||||
| AutoImport({ | |||||
| // 自动导入vue相关的Api | |||||
| imports: ["vue", "vue-router"], | |||||
| resolvers: [ElementPlusResolver()], | |||||
| }), | |||||
| Components({ | |||||
| resolvers: [ElementPlusResolver(), VantResolver()], | |||||
| }), | |||||
| { | |||||
| ...viteCompression(), | |||||
| apply: "build", | |||||
| }, | |||||
| ], | |||||
| resolve: { | |||||
| // 配置路径别名 | |||||
| alias: { | |||||
| "@": resolve(__dirname, "./src"), | |||||
| }, | |||||
| }, | |||||
| css: { | |||||
| // CSS 预处理器 | |||||
| preprocessorOptions: { | |||||
| //define global scss variable | |||||
| scss: { | |||||
| javascriptEnabled: true, | |||||
| additionalData: `@import "@/styles/variables.scss";`, | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| server: { | |||||
| host: "0.0.0.0", | |||||
| port: 8080, | |||||
| open: true, | |||||
| https: false, | |||||
| proxy: { | |||||
| "/api": { | |||||
| target: env.VITE_BASE_URL, | |||||
| changeOrigin: true, | |||||
| ws: true, | |||||
| rewrite: path => path.replace(/^\/api/, ""), | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| build: { | |||||
| rollupOptions: { | |||||
| output: { | |||||
| manualChunks: { | |||||
| vue: ["vue", "pinia", "vue-router"], | |||||
| elementIcons: ["@element-plus/icons-vue"], | |||||
| }, | |||||
| chunkFileNames: "wap/js/[name]-[hash].js", | |||||
| entryFileNames: "wap/js/[name]-[hash].js", | |||||
| assetFileNames: "wap/[ext]/[name]-[hash].[ext]", | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| }); |