26 changed files with 11907 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||
NODE_ENV='development' |
|||
# 请求域名前缀 |
|||
VUE_APP_URL='https://tongli.sz-trip.com' |
|||
# 打包后输出目录 |
|||
VUE_APP_OUTPUTDIR='dist_dev' |
@ -0,0 +1,5 @@ |
|||
NODE_ENV='production' |
|||
# 请求域名前缀 |
|||
VUE_APP_URL='https://tongli.sz-trip.com' |
|||
# 打包后输出目录 |
|||
VUE_APP_OUTPUTDIR='dist' |
@ -0,0 +1,5 @@ |
|||
NODE_ENV='production' |
|||
# 请求域名前缀 |
|||
VUE_APP_URL='https://tongli.sz-trip.com' |
|||
# 打包后输出目录 |
|||
VUE_APP_OUTPUTDIR='dist_test' |
@ -0,0 +1,23 @@ |
|||
.DS_Store |
|||
node_modules |
|||
/dist |
|||
|
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
'@vue/cli-plugin-babel/preset' |
|||
] |
|||
} |
@ -0,0 +1,19 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "es5", |
|||
"module": "esnext", |
|||
"baseUrl": "./", |
|||
"moduleResolution": "node", |
|||
"paths": { |
|||
"@/*": [ |
|||
"src/*" |
|||
] |
|||
}, |
|||
"lib": [ |
|||
"esnext", |
|||
"dom", |
|||
"dom.iterable", |
|||
"scripthost" |
|||
] |
|||
} |
|||
} |
File diff suppressed because it is too large
@ -0,0 +1,63 @@ |
|||
{ |
|||
"name": "taihulake", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"serve": "vue-cli-service serve --open", |
|||
"build": "vue-cli-service build", |
|||
"test": "vue-cli-service build --mode test", |
|||
"lint": "vue-cli-service lint" |
|||
}, |
|||
"dependencies": { |
|||
"amfe-flexible": "^2.2.1", |
|||
"axios": "^1.3.2", |
|||
"core-js": "^3.8.3", |
|||
"html-webpack-plugin": "^5.5.1", |
|||
"moment": "^2.30.1", |
|||
"postcss-px2rem-exclude": "0.0.6", |
|||
"postcss-pxtorem": "^6.1.0", |
|||
"qs": "^6.11.0", |
|||
"vant": "^2.12.53", |
|||
"vue": "^2.6.14", |
|||
"vue-router": "^3.5.3", |
|||
"vuex": "^3.6.2", |
|||
"webpack-bundle-analyzer": "^4.8.0" |
|||
}, |
|||
"devDependencies": { |
|||
"@babel/core": "^7.12.16", |
|||
"@babel/eslint-parser": "^7.12.16", |
|||
"@vue/cli-plugin-babel": "~5.0.0", |
|||
"@vue/cli-plugin-eslint": "~5.0.0", |
|||
"@vue/cli-service": "~5.0.0", |
|||
"babel-plugin-import": "^1.13.6", |
|||
"eslint": "^7.32.0", |
|||
"eslint-plugin-vue": "^8.0.3", |
|||
"node-sass": "^4.14.1", |
|||
"postcss": "^8.4.45", |
|||
"postcss-loader": "^3.0.0", |
|||
"px2rem-loader": "^0.1.9", |
|||
"sass-loader": "^7.3.1", |
|||
"vue-template-compiler": "^2.6.14" |
|||
}, |
|||
"eslintConfig": { |
|||
"root": true, |
|||
"env": { |
|||
"node": true |
|||
}, |
|||
"extends": [ |
|||
"plugin:vue/essential", |
|||
"eslint:recommended" |
|||
], |
|||
"parserOptions": { |
|||
"parser": "@babel/eslint-parser" |
|||
}, |
|||
"rules": { |
|||
"no-mixed-spaces-and-tabs": 0 |
|||
} |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions", |
|||
"not dead" |
|||
] |
|||
} |
@ -0,0 +1,16 @@ |
|||
const autoprefixer = require('autoprefixer'); |
|||
const px2rem = require('postcss-pxtorem'); |
|||
|
|||
module.exports = { |
|||
plugins: [ |
|||
autoprefixer(), |
|||
px2rem({ |
|||
rootValue(res) { |
|||
return res.file.indexOf('vant') !== -1 ? 37.5 : 75 //换算基数,1rem相当于75px
|
|||
}, |
|||
unitPrecision: 5, //保留rem小数点多少位
|
|||
propList: ['*'], |
|||
minPixelValue: 12 //px小于12的不会被转换
|
|||
}) |
|||
] |
|||
} |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,24 @@ |
|||
<!DOCTYPE html> |
|||
<html lang=""> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
|||
<link rel="icon" href="<%= htmlWebpackPlugin.options.url %>favicon.ico"> |
|||
<title>地图</title> |
|||
<!-- 腾讯地图 --> |
|||
<script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=YVOBZ-MWJ3Z-34IXK-7J2GL-O33US-QLF5X"> |
|||
</script> |
|||
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> |
|||
<!-- 引入uniSDK --> |
|||
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript |
|||
enabled. Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
@ -0,0 +1,59 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<keep-alive> |
|||
<router-view v-if="$route.meta.keepAlive"></router-view> |
|||
</keep-alive> |
|||
<router-view v-if="!$route.meta.keepAlive"></router-view> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App', |
|||
mounted() { |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
div { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.flex-between { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.flex-around { |
|||
display: flex; |
|||
justify-content: space-around; |
|||
align-items: center; |
|||
} |
|||
|
|||
.flex-center { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
/*单行隐藏*/ |
|||
.text-overflow { |
|||
overflow-x: hidden; |
|||
overflow-y: inherit; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
/* 两行隐藏 */ |
|||
.text-overflowRows { |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
-webkit-line-clamp: 2; |
|||
word-break: break-all; |
|||
display: -webkit-box; |
|||
-webkit-box-orient: vertical; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,91 @@ |
|||
import Vue from 'vue' |
|||
/**引入axios*/ |
|||
import axios from "axios"; |
|||
/**引入参数处理*/ |
|||
// import Qs from 'qs';
|
|||
import {Dialog, Toast} from "vant"; |
|||
import store from '@/store'; |
|||
const http = axios.create({ |
|||
baseURL: process.env.VUE_APP_URL, |
|||
timeout: 6000 // 请求超时时间 当请求时间超过`秒还未取得结果时 提示用户请求超时
|
|||
}) |
|||
|
|||
//添加请求拦截器
|
|||
http.interceptors.request.use((config) => { |
|||
const token = store.state.user.userInfo.token; |
|||
config.headers['token'] = token |
|||
config.headers['Content-Type'] = 'application/json;charset=UTF-8' |
|||
// if(config.loading === true){
|
|||
Toast.loading({ |
|||
message: '加载中...', |
|||
forbidClick: true, |
|||
duration: 0 |
|||
}); |
|||
// }
|
|||
return config; |
|||
}, (error) => { |
|||
return Promise.reject(error); |
|||
}); |
|||
|
|||
// 添加响应拦截器
|
|||
http.interceptors.response.use(response => { |
|||
Toast.clear() |
|||
if(response.status === 200 || response.status === 1){ |
|||
return response.data; |
|||
} |
|||
},error => { |
|||
if(error.response && error.response.status){ |
|||
switch(error.response.status){ |
|||
case 401: |
|||
Dialog.confirm({ |
|||
title: '提示', |
|||
message: '请登录后操作', |
|||
confirmButtonText: '去登录' |
|||
}).then(() => { |
|||
// 登录操作
|
|||
}); |
|||
break; |
|||
case 404: |
|||
Toast.fail({ |
|||
type: "fail", |
|||
message: '网络繁忙,请刷新再试', |
|||
forbidClick: true, |
|||
duration: 2000 |
|||
}); |
|||
break; |
|||
default: |
|||
Toast.fail({ |
|||
type: "fail", |
|||
message: '网络繁忙,请刷新再试', |
|||
forbidClick: true, |
|||
duration: 2000 |
|||
}); |
|||
break; |
|||
} |
|||
} |
|||
}) |
|||
|
|||
// 请求
|
|||
Vue.prototype.get = (params, url, loading) => { |
|||
return new Promise((resolve, reject) => { |
|||
http.get(url, params, loading) |
|||
.then(res => { |
|||
resolve(res); |
|||
}) |
|||
.catch(err => { |
|||
reject(err); |
|||
}); |
|||
}) |
|||
} |
|||
|
|||
Vue.prototype.post = (data, url, loading) => { |
|||
return new Promise((resolve, reject) => { |
|||
http.post(url, data, loading) |
|||
.then(res => { |
|||
resolve(res); |
|||
}) |
|||
.catch(err => { |
|||
reject(err); |
|||
}); |
|||
}) |
|||
} |
@ -0,0 +1,55 @@ |
|||
import { |
|||
validatenull |
|||
} from '@/libs/tools'; |
|||
|
|||
const keyName = '' + '-'; //随便写个自己的标识
|
|||
|
|||
//存储sessionStorage
|
|||
export const setStore = (params = {}) => { |
|||
let { |
|||
name, |
|||
content, |
|||
type, |
|||
} = params; |
|||
name = keyName + name |
|||
let obj = { |
|||
dataType: typeof(content), |
|||
content: content, |
|||
type: type, |
|||
datetime: new Date().getTime() |
|||
} |
|||
if (type) window.sessionStorage.setItem(name, JSON.stringify(obj)); |
|||
else window.localStorage.setItem(name, JSON.stringify(obj)); |
|||
} |
|||
|
|||
//获取sessionStorage
|
|||
export const getStore = (params = {}) => { |
|||
let { |
|||
name, |
|||
debug |
|||
} = params; |
|||
name = keyName + name |
|||
let obj = {}, |
|||
content; |
|||
obj = window.sessionStorage.getItem(name); |
|||
if (validatenull(obj)) obj = window.localStorage.getItem(name); |
|||
if (validatenull(obj)) return; |
|||
try { |
|||
obj = JSON.parse(obj); |
|||
} catch { |
|||
return obj; |
|||
} |
|||
if (debug) { |
|||
return obj; |
|||
} |
|||
if (obj.dataType == 'string') { |
|||
content = obj.content; |
|||
} else if (obj.dataType == 'number') { |
|||
content = Number(obj.content); |
|||
} else if (obj.dataType == 'boolean') { |
|||
content = eval(obj.content); |
|||
} else if (obj.dataType == 'object') { |
|||
content = obj.content; |
|||
} |
|||
return content; |
|||
} |
@ -0,0 +1,18 @@ |
|||
//判断是否为空
|
|||
export function validatenull(val) { |
|||
if (typeof val == 'boolean') { |
|||
return false; |
|||
} |
|||
if (typeof val == 'number') { |
|||
return false; |
|||
} |
|||
if (val instanceof Array) { |
|||
if (val.length == 0) return true; |
|||
} else if (val instanceof Object) { |
|||
if (JSON.stringify(val) === '{}') return true; |
|||
} else { |
|||
if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true; |
|||
return false; |
|||
} |
|||
return false; |
|||
} |
@ -0,0 +1,76 @@ |
|||
export default { |
|||
install(Vue) { |
|||
Vue.prototype.util = { |
|||
// 格式化富文本
|
|||
formateRichText(str) { |
|||
if (!str) return ""; |
|||
var reg = new RegExp("<img", "g"); |
|||
str = str.replace(reg, "<img class='sz-xcx-fwb-img' width='100%'") |
|||
reg = new RegExp("<IMG", "g"); |
|||
str = str.replace(reg, "<img class='sz-xcx-fwb-img' width='100%'") |
|||
reg = new RegExp(" ", "g"); |
|||
str = str.replace(reg, '<span style="width: 8rpx;display: inline-block;"></span>') |
|||
reg = new RegExp("section", "g"); |
|||
str = str.replace(reg, 'div'); |
|||
reg = new RegExp("↵", "g"); |
|||
str = str.replace(reg, '<br />'); |
|||
str = str.replace(/<table/g, '<table border="1" cellspacing="0" style="border-collapse:collapse"') |
|||
return str; |
|||
}, |
|||
// 手机号验证规则
|
|||
mobileValid(val) { |
|||
return /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/.test(val); |
|||
}, |
|||
// 身份证验证规则
|
|||
idNumberValid(val) { |
|||
return /^\d{17}(\d{1}|[X|x])$/.test(val); |
|||
}, |
|||
// 护照验证正则
|
|||
passportValid(val) { |
|||
return /^([a-zA-z]|[0-9]){5,17}$/.test(val); |
|||
}, |
|||
// 台胞证正则
|
|||
taiwanValid(val) { |
|||
return /^\d{8}|^[a-zA-Z0-9]{10}|^\d{18}$/.test(val); |
|||
}, |
|||
// 港澳通行证正则
|
|||
gangaoValid(val) { |
|||
return /^([A-Z]\d{6,10}(\(\w{1}\))?)$/.test(val); |
|||
}, |
|||
// 外国人永久居留证正则
|
|||
foreignerValid(val) { |
|||
return /(^[A-Za-z]{3})([0-9]{12}$)/.test(val); |
|||
}, |
|||
// 军官证正则
|
|||
officerValid(val) { |
|||
return /^[\u4E00-\u9FA5](字第)([0-9a-zA-Z]{4,8})(号?)$/.test(val); |
|||
}, |
|||
// 邮箱验证正则
|
|||
emailValid(val) { |
|||
return /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(val) |
|||
}, |
|||
// 获取路径参数
|
|||
getUrlPara(url) { |
|||
let arrUrl = url.split("?"); |
|||
let para = arrUrl[1]; |
|||
return para ? para.split('&') : false; |
|||
}, |
|||
openMap(item) { |
|||
uni.openLocation({ |
|||
longitude: item.lon, // 经度
|
|||
latitude: item.lat, //纬度
|
|||
name: item.address || item.title || item.name, // 位置名称
|
|||
address: item.address, //详细地址
|
|||
}) |
|||
}, |
|||
showImg(img) { |
|||
if(!img) return; |
|||
if (img.indexOf('https://') != -1 || img.indexOf('http://') != -1) { |
|||
return img; |
|||
} else { |
|||
return 'https://tongli.sz-trip.com' + img; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
import Vue from 'vue' |
|||
import App from './App.vue' |
|||
import store from './store' |
|||
import '../src/libs/axios.js' // axios处理
|
|||
// 引入amfe-flexible做rem适配
|
|||
import "amfe-flexible" |
|||
import router from "./router" |
|||
|
|||
import utils from './libs/utils.js' |
|||
Vue.use(utils) |
|||
|
|||
import Vant from 'vant'; |
|||
import 'vant/lib/index.css'; |
|||
Vue.use(Vant); |
|||
|
|||
// Vue.prototype.ShowLoading = (title) => {
|
|||
// Vue.prototype.$toast.loading({
|
|||
// message: title ? title : '请求中',
|
|||
// forbidClick: true,
|
|||
// duration: 0
|
|||
// })
|
|||
// }
|
|||
|
|||
Vue.config.productionTip = false |
|||
|
|||
new Vue({ |
|||
store, |
|||
router, |
|||
render: h => h(App), |
|||
}).$mount('#app') |
@ -0,0 +1,27 @@ |
|||
import Vue from "vue"; |
|||
import VueRouter from "vue-router"; |
|||
import Index from "../views/Index.vue"; |
|||
|
|||
Vue.use(VueRouter); |
|||
|
|||
const routes = [{ |
|||
path: "/", |
|||
name: "index", |
|||
meta: {title: "首页", keepAlive: true}, |
|||
component: Index, |
|||
}, |
|||
{ |
|||
path: "/lineList", |
|||
name: "lineList", |
|||
meta: {title: "", keepAlive: true}, |
|||
component: () =>import("../views/LineList.vue"), |
|||
}, |
|||
]; |
|||
|
|||
const router = new VueRouter({ |
|||
mode: "history", |
|||
base: process.env.BASE_URL, |
|||
routes, |
|||
}); |
|||
|
|||
export default router; |
@ -0,0 +1,19 @@ |
|||
import Vue from 'vue' |
|||
import Vuex from 'vuex' |
|||
import user from './modules/user' |
|||
|
|||
Vue.use(Vuex) |
|||
|
|||
export default new Vuex.Store({ |
|||
state: { |
|||
|
|||
}, |
|||
mutations: { |
|||
|
|||
}, |
|||
actions: {}, |
|||
modules: { |
|||
namespaced: true, // 为了解决不同模块命名冲突的问题
|
|||
user |
|||
} |
|||
}) |
@ -0,0 +1,19 @@ |
|||
import { setStore, getStore } from '@/libs/storage' |
|||
export default { |
|||
state: { |
|||
userInfo: getStore({ name: 'userInfo' }) || '', // 保存用户登录信息
|
|||
}, |
|||
mutations: { |
|||
changeUserInfo(state, data) { |
|||
state.userInfo = data |
|||
setStore({ name: 'userInfo', content: state.userInfo, type: 'session' }) |
|||
if(data && data.token)localStorage.setItem('userInfo', JSON.stringify(data)) |
|||
}, |
|||
}, |
|||
getters: { |
|||
|
|||
}, |
|||
actions: { |
|||
|
|||
} |
|||
} |
@ -0,0 +1,566 @@ |
|||
<template> |
|||
<div> |
|||
<div id="mapContainer" class="mapContainer"></div> |
|||
|
|||
<!-- 点位分类 --> |
|||
<div class="type-box"> |
|||
<div :class="['type-item',{'type-active': index == typeIndex}]" v-for="(item,index) in mapType" |
|||
@click="getSpotsByCategory(index)">{{item.name}}</div> |
|||
</div> |
|||
|
|||
<div class="area-box"> |
|||
<!-- 区域分类 --> |
|||
<div> |
|||
<div class="area-item area-items" @click="areaMore = !areaMore"> |
|||
<img :src="'https://static.ticket.sz-trip.com/yandu/images/map/'+ (areaMore ? 'topIcon.png' : 'bottomIcon.png')" |
|||
alt="" /> |
|||
{{areaMore ? '收起' : '展开'}} |
|||
</div> |
|||
<div v-if="areaMore"> |
|||
<div v-for="(item,index) in areaList" :key="index" |
|||
:class="['area-item',{'area-active':index == areaIndex}]" @click="changeArea(index)"> |
|||
{{item.name}} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- 行程线路 --> |
|||
<div> |
|||
<div class="area-item area-items" @click="addLine"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/addLine.png" alt="" /> |
|||
添加<br>行程 |
|||
</div> |
|||
<div class="area-item area-items" @click="gotoLine"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/line.png" alt="" /> |
|||
线路<br>推荐 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 详情弹框 --> |
|||
<van-popup v-model="detailShow" @close="audioPause" :overlay-style="{'background-color': 'rgba(0, 0, 0, 0)'}" |
|||
position="bottom" round> |
|||
<ProductDetail ref="detailRef" /> |
|||
</van-popup> |
|||
|
|||
<!-- 输入线路信息弹框 --> |
|||
<van-popup v-model="addLineShow" position="center" round> |
|||
<div class="addLine-box"> |
|||
添加行程 |
|||
<div class="addLine-item"> |
|||
线路名称: <input type="text" v-model="lineName" placeholder="请输入线路名称" /> |
|||
</div> |
|||
<div class="addLine-item"> |
|||
开始时间: <input type="text" v-model="lineDate" placeholder="请选择出发时间" readonly |
|||
@click="lineDateShow = true" /> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/dateRight.png" alt=""> |
|||
</div> |
|||
<div class="addLine-btn flex-around"> |
|||
<div @click="addLineShow = false">取消</div> |
|||
<div @click="lineClick">下一步</div> |
|||
</div> |
|||
</div> |
|||
</van-popup> |
|||
|
|||
<!-- 日期选择 --> |
|||
<van-popup v-model="lineDateShow" round position="bottom"> |
|||
<van-datetime-picker v-model="currentDate" type="date" title="选择年月日" @confirm="lineDateConfirm" /> |
|||
</van-popup> |
|||
|
|||
<!-- 添加线路行程弹框 --> |
|||
<van-popup v-model="lineRouteShow" round position="bottom"> |
|||
<LineRoute :id="lineId" :lineDate="lineDate" ref="lineRouteRef" /> |
|||
</van-popup> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import moment from 'moment' |
|||
import ProductDetail from './compoents/productDetail' |
|||
import LineRoute from './compoents/lineRoute' |
|||
export default { |
|||
components: { |
|||
ProductDetail, |
|||
LineRoute |
|||
}, |
|||
data() { |
|||
return { |
|||
mapObj: null, |
|||
mapMarker: null, |
|||
basics: {}, |
|||
mapType: [], |
|||
typeIndex: -1, |
|||
areaList: [], |
|||
areaIndex: 0, |
|||
areaMore: true, |
|||
detailShow: false, // 详情弹框 |
|||
addLineShow: false, // 输入线路名称和日期弹框 |
|||
lineName: '', |
|||
lineDate: '', |
|||
lineDateShow: false, // 选择日期弹框 |
|||
currentDate: new Date(), |
|||
lineRouteShow: false, // 添加线路行程弹框 |
|||
lineAddStatus: false, // 点击添加行程时为true,地图景点图标改变为加号 |
|||
lineId: '', |
|||
maps: [], //热点 |
|||
}; |
|||
}, |
|||
mounted() { |
|||
this.getAreaList() |
|||
}, |
|||
methods: { |
|||
// 获取全部区域 |
|||
getAreaList() { |
|||
this.post({}, '/api/emap/get_map_list').then(res => { |
|||
this.areaList = res.data |
|||
if (res.data.length > 0) { |
|||
this.getAreaDetail() |
|||
this.getCategory() |
|||
} |
|||
}) |
|||
}, |
|||
// 更改地图区域 |
|||
changeArea(index) { |
|||
this.areaIndex = index |
|||
this.getAreaDetail() |
|||
}, |
|||
// 根据code获取当前区域信息 |
|||
getAreaDetail() { |
|||
this.post({ |
|||
code: this.areaList[this.areaIndex].code |
|||
}, '/api/emap/get_init').then(res => { |
|||
this.basics = res.data |
|||
this.basics.center_poi = JSON.parse(this.basics.center_poi) |
|||
this.basics.lb_poi = JSON.parse(this.basics.lb_poi) |
|||
this.basics.rt_poi = JSON.parse(this.basics.rt_poi) |
|||
this.$nextTick(() => { |
|||
this.initMap() |
|||
}) |
|||
}) |
|||
}, |
|||
// 根据code获取热点分类 |
|||
getCategory() { |
|||
this.post({ |
|||
code: this.areaList[this.areaIndex].code |
|||
}, '/api/emap/getByCategory').then(res => { |
|||
this.mapType = Array.from(res.data) |
|||
if(this.mapType.length > 0) this.getSpotsByCategory(0) |
|||
}) |
|||
}, |
|||
// 根据code、热点分类获取热点 |
|||
getSpotsByCategory(index) { |
|||
this.typeIndex = index |
|||
this.post({ |
|||
code: this.areaList[this.areaIndex].code, |
|||
category_id: this.mapType[this.typeIndex].id |
|||
},'/api/emap/getSpotsByCategory').then(res => { |
|||
console.log(res) |
|||
this.maps = res.data |
|||
// 移除原先点位 |
|||
this.clearMarkers() |
|||
if(this.maps.length > 0) this.setMarkers() |
|||
}) |
|||
}, |
|||
initMap() { |
|||
let centerLat = this.basics.center_poi[1] |
|||
let centerLon = this.basics.center_poi[0] |
|||
var center = new TMap.LatLng(this.basics.center_poi[1], this.basics.center_poi[0]) //设置中心点坐标 |
|||
var sw = new TMap.LatLng(this.basics.rt_poi[1], this.basics.rt_poi[0]); //东北角坐标, |
|||
var ne = new TMap.LatLng(this.basics.lb_poi[1], this.basics.lb_poi[0]); //西南角坐标, |
|||
var latlngBounds = new TMap.LatLngBounds(ne, sw); |
|||
// 初始化地图 |
|||
this.mapObj = new TMap.Map("mapContainer", { |
|||
center: center, |
|||
boundary: latlngBounds, |
|||
zoom: 12, // 地图默认缩放级别 |
|||
minZoom: 12, |
|||
maxZoom: 15, |
|||
showControl: true, // 是否显示地图上的控件 |
|||
// viewMode: '2D', // 地图视图模式,支持2D和3D,默认为3D。2D模式下俯仰角和旋转角度始终为0 |
|||
rotation: 0, //设置地图旋转角度 |
|||
}); |
|||
|
|||
this.mapObj.removeControl(TMap.constants.DEFAULT_CONTROL_ID.ZOOM); // 移除缩放控件 |
|||
this.mapObj.removeControl(TMap.constants.DEFAULT_CONTROL_ID.ROTATION); // 移除旋转控件 |
|||
|
|||
// 初始化瓦片 |
|||
// 瓦片图需要切好每个位置的图 |
|||
// x,y,z 为上图的坐标 |
|||
new TMap.ImageTileLayer({ |
|||
getTileUrl: function(x, y, z) { |
|||
console.log(x, y, z) |
|||
//拼接瓦片URL |
|||
let url = |
|||
`https://static.ticket.sz-trip.com/yandu/images/maps/` + |
|||
z + |
|||
"/" + |
|||
x + |
|||
"/" + |
|||
y + |
|||
".png"; |
|||
return url; |
|||
}, |
|||
tileSize: 256, //瓦片像素尺寸 |
|||
minZoom: 12, //显示自定义瓦片的最小级别 |
|||
maxZoom: 15, //显示自定义瓦片的最大级别 |
|||
visible: true, //是否可见 |
|||
zIndex: 5000, //层级高度(z轴) |
|||
opacity: 1, //图层透明度:1不透明,0为全透明 |
|||
map: this.mapObj, //设置图层显示到哪个地图实例中 |
|||
}); |
|||
|
|||
// 创建点聚合实例 |
|||
// this.markerCluster = new TMap.MarkerCluster({ |
|||
// id: "cluster", |
|||
// map: this.mapObj, |
|||
// enableDefaultStyle: true, // 是否启用默认样式 |
|||
// minimumClusterSize: 5, // 形成聚合簇的最小个数 |
|||
// geometries: [], // 点数组 |
|||
// zoomOnClick: true, |
|||
// gridSize: 60, |
|||
// averageCenter: true, |
|||
// }); |
|||
}, |
|||
// 地图打点 |
|||
setMarkers() { |
|||
// 聚合点点位 |
|||
// this.markerCluster.setGeometries([ |
|||
// { |
|||
// position: new TMap.LatLng(33.332682, 120.16451) |
|||
// }, |
|||
// { |
|||
// position: new TMap.LatLng(33.329281, 120.161117) |
|||
// } |
|||
// ]); |
|||
|
|||
let markers = [] |
|||
let labels = [] |
|||
this.maps.forEach(item => { |
|||
markers.push({ |
|||
"styleId": 'marker', |
|||
text: item.name, |
|||
position: new TMap.LatLng(item.poi_gcj02[1], item.poi_gcj02[0]) |
|||
}) |
|||
|
|||
labels.push({ |
|||
id: 'label', // 点图形数据的标志信息 |
|||
styleId: 'label', // 样式id |
|||
position: new TMap.LatLng(item.poi_gcj02[1], item.poi_gcj02[0]), // 标注点位置 |
|||
content: item.name, // 标注文本 |
|||
properties: { |
|||
// 标注点的属性数据 |
|||
title: 'label', |
|||
}, |
|||
}) |
|||
}) |
|||
|
|||
// 添加marker点 |
|||
this.multiMarker = new TMap.MultiMarker({ |
|||
id: 'marker-layer', |
|||
map: this.mapObj, |
|||
styles: { |
|||
"marker": new TMap.MarkerStyle({ |
|||
"width": 24, |
|||
"height": 30, |
|||
"src": 'https://static.ticket.sz-trip.com/yandu/images/map/scenic.png', |
|||
"src": this.util.showImg(this.mapType.find(i => {return i.id == this.maps[0].category_id}).icon_image) |
|||
}) |
|||
}, |
|||
// 点数组 |
|||
geometries: markers, |
|||
}) |
|||
|
|||
// 标记点点击事件 |
|||
this.multiMarker.on("click", this.markerClick) |
|||
|
|||
// 文本标记 |
|||
this.multiLabel = new TMap.MultiLabel({ |
|||
id: 'label-layer', |
|||
map: this.mapObj, |
|||
collisionOptions: { |
|||
sameSource: true, |
|||
}, //开启图层内部的文本标注碰撞 |
|||
styles: { |
|||
label: new TMap.LabelStyle({ |
|||
color: '#FFF', // 颜色属性 |
|||
size: 13, // 文字大小属性 |
|||
offset: { |
|||
x: 0, |
|||
y: 15 |
|||
}, // 文字偏移属性单位为像素 |
|||
angle: 0, // 文字旋转属性 |
|||
alignment: 'center', // 文字水平对齐属性 |
|||
verticalAlignment: 'middle', // 文字垂直对齐属性 |
|||
backgroundColor: 'rgba(0, 0, 0, .5)', |
|||
borderRadius: 7, |
|||
padding: '2px 8px', |
|||
}), |
|||
}, |
|||
geometries: labels, |
|||
}) |
|||
|
|||
// 标记文本点击事件 |
|||
// this.multiLabel.on("click", this.markerClick) |
|||
}, |
|||
// 移除点位 |
|||
clearMarkers() { |
|||
if (this.multiMarker) { |
|||
this.multiMarker.setMap(null); |
|||
this.multiMarker = null; |
|||
} |
|||
|
|||
if(this.multiLabel) { |
|||
this.multiLabel.setMap(null); |
|||
this.multiLabel = null; |
|||
} |
|||
}, |
|||
// 改变地图中心 |
|||
changeMapCenter() { |
|||
this.mapObj.panTo(new TMap.LatLng(33.37307, 120.18467)); |
|||
}, |
|||
// 标记点点击事件 |
|||
markerClick(evt) { |
|||
console.log(evt, evt.geometry.text) |
|||
if (this.lineAddStatus) { |
|||
//添加行程时 |
|||
this.$dialog.confirm({ |
|||
title: '', |
|||
message: '是否将' + evt.geometry.text + '加入行程?' |
|||
}).then(() => { |
|||
this.lineId = 1 |
|||
this.$refs.lineRouteRef.addLineList() |
|||
}).catch(() => { |
|||
|
|||
}) |
|||
} else { |
|||
this.detailShow = true |
|||
} |
|||
}, |
|||
// 路线规划 |
|||
gotoLine() { |
|||
// this.MultiPolyline = new TMap.MultiPolyline({ |
|||
// id: 'polyline-layer', |
|||
// map: this.mapObj, |
|||
// styles: { |
|||
// "style_blue": new TMap.PolylineStyle({ |
|||
// "width": 4, |
|||
// 'color': '#3777FF', //线填充色 |
|||
// 'borderWidth': 2, //边线宽度 |
|||
// 'borderColor': '#FFF', //边线颜色 |
|||
// 'lineCap': 'butt' //线端头方式 |
|||
// }) |
|||
// }, |
|||
// // 折线数据定义 |
|||
// geometries: [{ |
|||
// "id": 'style_blue', |
|||
// "styleId": 'style_blue', |
|||
// "paths": [new TMap.LatLng(33.347305, 120.136504), new TMap.LatLng(33.323448, |
|||
// 120.157053), new TMap.LatLng(33.338249, 120.1832)] |
|||
// }] |
|||
// }) |
|||
|
|||
this.$router.push({ |
|||
path: '/lineList', |
|||
query: { |
|||
code: this.areaList[this.areaIndex].code |
|||
} |
|||
}) |
|||
}, |
|||
// 关闭弹框后暂停音频 |
|||
audioPause() { |
|||
this.$refs.detailRef.audioPlay(false) |
|||
}, |
|||
// 添加线路 |
|||
addLine() { |
|||
this.lineName = '' |
|||
this.lineDate = '' |
|||
this.addLineShow = true |
|||
}, |
|||
// 确认日期 |
|||
lineDateConfirm() { |
|||
this.lineDate = moment(this.currentDate).format('YYYY-MM-DD') |
|||
this.lineDateShow = false |
|||
}, |
|||
// 输入线路名称和时间,下一步 |
|||
lineClick() { |
|||
if (this.lineName.trim().length == 0 || this.lineDate.trim().length == 0) { |
|||
this.$toast('请输入行程信息') |
|||
} else { |
|||
this.addLineShow = false |
|||
this.lineRouteShow = true |
|||
} |
|||
}, |
|||
// 点击添加行程、关闭添加行程弹框,改变景点标识图标 |
|||
addlineRoute(status) { |
|||
this.lineRouteShow = false |
|||
|
|||
if (status) { |
|||
// 更换marker样式方法 |
|||
this.multiMarker.setStyles({ |
|||
"marker": new TMap.MarkerStyle({ |
|||
"width": 24, |
|||
"height": 30, |
|||
"src": 'https://static.ticket.sz-trip.com/yandu/images/map/add.png' |
|||
}) |
|||
}) |
|||
|
|||
// 添加行程时为true |
|||
this.lineAddStatus = true |
|||
} else { |
|||
this.typeIndex = -1 |
|||
this.setMarkers(0) |
|||
} |
|||
} |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
div { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.mapContainer { |
|||
width: 100%; |
|||
height: 100vh; |
|||
} |
|||
|
|||
.type-box { |
|||
position: fixed; |
|||
z-index: 2000; |
|||
width: 723px; |
|||
height: 53px; |
|||
top: 22px; |
|||
left: 27px; |
|||
display: flex; |
|||
overflow-x: auto; |
|||
|
|||
.type-item { |
|||
padding: 0 26px; |
|||
line-height: 53px; |
|||
background: #FFFFFF; |
|||
border-radius: 13px; |
|||
font-weight: 500; |
|||
font-size: 27px; |
|||
color: #000000; |
|||
margin-right: 27px; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.type-active { |
|||
background: linear-gradient(130deg, #9EE4FE, #7FD491); |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
|
|||
.type-box::-webkit-scrollbar { |
|||
display: none; |
|||
} |
|||
|
|||
.area-box { |
|||
position: fixed; |
|||
z-index: 2000; |
|||
top: 153px; |
|||
right: 17px; |
|||
|
|||
&>div { |
|||
width: 87px; |
|||
height: auto; |
|||
background: #FFFFFF; |
|||
border-radius: 43px; |
|||
border: 2px solid #FFFFFF; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
&>div:last-child { |
|||
margin-top: 24px; |
|||
|
|||
.area-items { |
|||
height: 133px !important; |
|||
} |
|||
} |
|||
|
|||
.area-item { |
|||
height: 93px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
text-align: center; |
|||
border-top: 1px solid #D8D8D8; |
|||
font-weight: 500; |
|||
font-size: 22px; |
|||
color: #666666; |
|||
} |
|||
|
|||
.area-items { |
|||
flex-direction: column; |
|||
justify-content: space-around; |
|||
height: 100px; |
|||
|
|||
img { |
|||
width: 38px; |
|||
height: 38px; |
|||
} |
|||
} |
|||
|
|||
.area-active { |
|||
background: linear-gradient(130deg, #9EE4FE, #7FD491); |
|||
color: #000000; |
|||
font-weight: bold; |
|||
} |
|||
} |
|||
|
|||
// 线路弹框 |
|||
.addLine-box { |
|||
width: 673px; |
|||
height: 413px; |
|||
background: #FFFFFF; |
|||
border-radius: 27px; |
|||
padding: 32px 33px 0 37px; |
|||
font-weight: bold; |
|||
font-size: 40px; |
|||
color: #000000; |
|||
|
|||
.addLine-item { |
|||
font-weight: 400; |
|||
font-size: 29px; |
|||
margin-top: 40px; |
|||
|
|||
input { |
|||
outline: none; |
|||
border: none; |
|||
height: 27px; |
|||
width: 380px; |
|||
margin-left: 30px; |
|||
} |
|||
|
|||
input::placeholder { |
|||
color: #BEBEBE; |
|||
} |
|||
|
|||
img { |
|||
width: 20px; |
|||
height: 20px; |
|||
} |
|||
} |
|||
|
|||
.addLine-btn { |
|||
margin-top: 50px; |
|||
|
|||
div { |
|||
width: 233px; |
|||
line-height: 67px; |
|||
background: #EAEAEA; |
|||
border-radius: 13px; |
|||
text-align: center; |
|||
font-weight: 500; |
|||
font-size: 29px; |
|||
color: #000000; |
|||
} |
|||
|
|||
div:last-child { |
|||
background: #71B580; |
|||
color: #FFFFFF; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,100 @@ |
|||
<template> |
|||
<div class="bg"> |
|||
<div class="item" v-for="(item,index) in list" :key="index"> |
|||
<img :src="util.showImg(item.image)" alt="" /> |
|||
|
|||
<div class="content"> |
|||
<div class="title">{{item.name}}</div> |
|||
<div class="subtitle">{{item.points.length}}个景点</div> |
|||
<div class="tags" v-if="item.goods_new_tag"> |
|||
<div class="tag" v-for="(tagItem,tagIndex) in item.goods_new_tag.split(',').slice(0,2)">{{tagItem}}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
list: [] |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.getList() |
|||
}, |
|||
methods: { |
|||
// 根据code获取推荐线路 |
|||
getList() { |
|||
this.post({ |
|||
code: this.$route.query.code |
|||
},'/api/emap/getLineByCode').then(res => { |
|||
this.list = res.data |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.bg { |
|||
width: 100%; |
|||
min-height: 100vh; |
|||
background: #F7F7F7; |
|||
padding-top: 31px; |
|||
} |
|||
|
|||
.item { |
|||
width: 697px; |
|||
height: 240px; |
|||
background: #FFFFFF; |
|||
box-shadow: 0px 1px 16px 0px rgba(153,153,153,0.35); |
|||
border-radius: 20px; |
|||
margin: 0 auto 33px; |
|||
padding: 13px; |
|||
display: flex; |
|||
|
|||
img { |
|||
object-fit: cover; |
|||
width: 213px; |
|||
height: 213px; |
|||
border-radius: 13px; |
|||
} |
|||
|
|||
.content { |
|||
margin-left: 25px; |
|||
padding: 15px 0; |
|||
width: 410px; |
|||
|
|||
.title { |
|||
font-weight: bold; |
|||
font-size: 33px; |
|||
color: #111111; |
|||
} |
|||
|
|||
.subtitle { |
|||
margin-top: 8px; |
|||
font-weight: 500; |
|||
font-size: 27px; |
|||
color: #666666; |
|||
} |
|||
|
|||
.tags { |
|||
display: flex; |
|||
margin-top: 15px; |
|||
|
|||
.tag { |
|||
font-weight: 500; |
|||
font-size: 23px; |
|||
color: #71B580; |
|||
line-height: 40px; |
|||
border-radius: 5px; |
|||
border: 1px solid #69AF78; |
|||
padding: 0 12px; |
|||
margin-right: 13px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,245 @@ |
|||
|
|||
<template> |
|||
<div class="bg"> |
|||
<div class="top"> |
|||
线路标题 |
|||
<span>{{lineDate}}</span> |
|||
</div> |
|||
|
|||
<div class="center"> |
|||
<div class="center-items flex-between" v-for="(item,index) in list" :key="index"> |
|||
<div class="center-line"></div> |
|||
<div class="center-num">{{index + 1}}</div> |
|||
<div class="center-item"> |
|||
<img :src="util.showImg(item.image)" class="center-img"> |
|||
<div class="center-content"> |
|||
<div class="title text-overflow">{{item.title}}{{index}}</div> |
|||
<div class="subtitle text-overflow">营业时间:{{item.open_time}}-{{item.close_time}}</div> |
|||
<div class="subtitle text-overflow">地址:{{item.address}}</div> |
|||
<div class="location" @click="util.openMap(item)"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/lineLocation.png" alt=""> |
|||
导航 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/delLine.png" alt="" @click="delLine(index)"> |
|||
</div> |
|||
|
|||
<div class="center-btns flex-between" @click="addLine"> |
|||
<div class="center-line" :style="{top: list.length == 0 ? '20px' : ''}" v-if="list.length == 0"></div> |
|||
<div class="center-num">{{list.length == 0 ? '1' : ''}}</div> |
|||
<div class="center-btn"> |
|||
+添加行程 |
|||
</div> |
|||
<div></div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="btns flex-around"> |
|||
<div @click="submit(0)">取消</div> |
|||
<div @click="submit(1)">保存</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['id','lineDate'], |
|||
data() { |
|||
return { |
|||
list: [], |
|||
itemObj: { |
|||
image: '/uploads/20240826/a87488f6225789aa19dbb437671d388d.png', |
|||
title: '线路推荐-测试', |
|||
open_time: '', |
|||
close_time: '', |
|||
address: '地址' |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
|
|||
}, |
|||
methods: { |
|||
addLine() { |
|||
this.$parent.$parent.addlineRoute(1) |
|||
}, |
|||
addLineList() { |
|||
this.list.push(this.itemObj) |
|||
this.$parent.$parent.lineRouteShow = true |
|||
}, |
|||
// 删除线路 |
|||
delLine(index) { |
|||
this.list.splice(index,1) |
|||
}, |
|||
submit(status) { |
|||
if(status) { |
|||
// 确认 |
|||
}else { |
|||
// 取消 |
|||
this.$parent.$parent.addlineRoute(0) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.bg { |
|||
width: 750px; |
|||
max-height: 60vh; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
padding: 40px 27px 180px 27px; |
|||
position: relative; |
|||
} |
|||
|
|||
.top { |
|||
font-weight: 500; |
|||
font-size: 40px; |
|||
color: #000000; |
|||
|
|||
span { |
|||
font-weight: 400; |
|||
font-size: 24px; |
|||
color: #666666; |
|||
margin-left: 20px; |
|||
vertical-align: text-bottom; |
|||
} |
|||
} |
|||
|
|||
.center { |
|||
height: 650px; |
|||
overflow-y: auto; |
|||
margin-top: 50px; |
|||
|
|||
.center-items { |
|||
position: relative; |
|||
padding-bottom: 27px; |
|||
|
|||
.center-item { |
|||
width: 573px; |
|||
height: 201px; |
|||
background: #FFFFFF; |
|||
box-shadow: 0px 0px 20px 0px rgba(142,142,142,0.3); |
|||
border-radius: 13px; |
|||
padding: 7px; |
|||
display: flex; |
|||
|
|||
.center-img { |
|||
width: 187px; |
|||
height: 187px; |
|||
border-radius: 7px; |
|||
} |
|||
|
|||
.center-content { |
|||
padding: 7px 0; |
|||
margin-left: 15px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
width: 344px; |
|||
|
|||
.title { |
|||
font-weight: bold; |
|||
font-size: 29px; |
|||
color: #333333; |
|||
width: 344px; |
|||
} |
|||
|
|||
.subtitle { |
|||
font-weight: 500; |
|||
font-size: 23px; |
|||
color: #666666; |
|||
width: 344px; |
|||
} |
|||
|
|||
.location { |
|||
font-weight: bold; |
|||
font-size: 23px; |
|||
color: #71B580; |
|||
display: flex; |
|||
align-items: center; |
|||
margin-left: auto; |
|||
|
|||
img { |
|||
width: 32px; |
|||
height: 32px; |
|||
margin-right: 5px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
img { |
|||
width: 33px; |
|||
height: 33px; |
|||
} |
|||
} |
|||
|
|||
.center-btns { |
|||
position: relative; |
|||
|
|||
.center-btn { |
|||
width: 573px; |
|||
line-height: 73px; |
|||
background: #71B580; |
|||
border-radius: 13px; |
|||
text-align: center; |
|||
font-weight: 400; |
|||
font-size: 29px; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
div:last-child { |
|||
width: 33px; |
|||
} |
|||
} |
|||
|
|||
.center-num { |
|||
width: 38px; |
|||
line-height: 38px; |
|||
background: #71B580; |
|||
border-radius: 50%; |
|||
text-align: center; |
|||
font-weight: 500; |
|||
font-size: 32px; |
|||
color: #FFFFFF; |
|||
position: relative; |
|||
} |
|||
.center-line { |
|||
position: absolute; |
|||
width: 2px; |
|||
height: 100%; |
|||
background: #71B580; |
|||
top: 85px; |
|||
left: 18px; |
|||
} |
|||
} |
|||
|
|||
.btns { |
|||
width: 750px; |
|||
height: 173px; |
|||
background: #FFFFFF; |
|||
box-shadow: 0px 0px 20px 0px rgba(142,142,142,0.3); |
|||
padding: 0 20px; |
|||
position: absolute; |
|||
left: 0; |
|||
|
|||
div { |
|||
width: 233px; |
|||
line-height: 67px; |
|||
background: #EAEAEA; |
|||
border-radius: 13px; |
|||
text-align: center; |
|||
font-weight: 400; |
|||
font-size: 27px; |
|||
color: #000000; |
|||
} |
|||
|
|||
div:last-child { |
|||
background: #71B580; |
|||
color: #FFFFFF; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,176 @@ |
|||
|
|||
<template> |
|||
<div class="bg"> |
|||
<div class="top flex-between"> |
|||
标题标题 |
|||
<div class="top-btn" v-if="type">购买</div> |
|||
</div> |
|||
|
|||
<div class="img-box" v-if="type"> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
<img src="https://tongli.sz-trip.com/uploads/20240912/bfc1df32e7bc7cd53781ef6671f88cda.png" alt="" /> |
|||
</div> |
|||
|
|||
<div class="scenic-detail flex-between" :style="{marginTop: type ? '' : '0'}"> |
|||
<div class="scenic-left flex-between"> |
|||
<div class="text-overflow" v-if="type">营业时间:09:00-17:00</div> |
|||
<div :class="[type ? 'text-overflow' : 'text-overflowRows']">地址:盐城市盐都区学富镇周伙盐城市盐都区学富镇周伙</div> |
|||
</div> |
|||
<div class="scenic-right flex-between"> |
|||
<div v-if="type"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/pause.png" v-if="isAudioPlay" @click="audioPlay(false)"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/play.png" v-else @click="audioPlay(true)"> |
|||
<div>讲解</div> |
|||
</div> |
|||
<div v-else></div> |
|||
|
|||
<div @click="util.openMap()"> |
|||
<img src="https://static.ticket.sz-trip.com/yandu/images/map/navigation.png" alt=""> |
|||
<div>导航</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="scenic-content" v-if="type"> |
|||
简介: |
|||
<div> |
|||
草房子乐园是童话文学的IP实景还原,是国内较早儿童文学实景体验基地、较早乡野童话体验基地和儿童文学研学基地。致力于打造集旅游住宿、餐饮服务、休闲娱乐、文化传播、研学美育、亲子互动、青少年实践、爱心公益于一体的社会化服务新平台。研学赋能景区瞄准“研学+”新领域,建设标准化研学场景,葳蕤的田园风光,推出亲子研学个性化的消费体验产品和游玩项目 |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 音频讲解 --> |
|||
<audio src="" ref="audio" controls v-show="false"></audio> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
type: { |
|||
type: Boolean, |
|||
default: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
isAudioPlay: false, |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$refs.audio.src = "https://static.ticket.sz-trip.com/uploads/20220419/47fcfa763aa0d3283a2d47e3cce71428.mp3" |
|||
}, |
|||
methods: { |
|||
audioPlay(status) { |
|||
console.log(this.$refs.audio.paused) |
|||
if(status) { |
|||
this.$refs.audio.play() |
|||
this.isAudioPlay = true |
|||
}else { |
|||
this.$refs.audio.pause() |
|||
this.isAudioPlay = false |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.bg { |
|||
width: 750px; |
|||
max-height: 60vh; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
padding: 0 40px 40px; |
|||
} |
|||
.top { |
|||
height: 156px; |
|||
font-weight: 500; |
|||
font-size: 40px; |
|||
color: #000000; |
|||
|
|||
.top-btn { |
|||
width: 133px; |
|||
line-height: 59px; |
|||
background: #F74A57; |
|||
border-radius: 13px; |
|||
text-align: center; |
|||
font-size: 32px; |
|||
color: #FFFFFF; |
|||
} |
|||
} |
|||
.img-box { |
|||
overflow-x: auto; |
|||
display: flex; |
|||
overflow-x: auto; |
|||
|
|||
img { |
|||
width: 180px; |
|||
height: 180px; |
|||
border-radius: 27px; |
|||
margin-right: 27px; |
|||
object-fit: cover; |
|||
} |
|||
} |
|||
.img-box::-webkit-scrollbar { |
|||
display: none; |
|||
} |
|||
|
|||
.scenic-detail { |
|||
width: 670px; |
|||
height: 145px; |
|||
background: #E8F6EB; |
|||
border-radius: 13px; |
|||
margin-top: 36px; |
|||
padding: 30px 20px 30px 25px; |
|||
font-weight: 500; |
|||
font-size: 27px; |
|||
color: #000000; |
|||
|
|||
.scenic-left { |
|||
flex-direction: column; |
|||
align-items: left; |
|||
width: 450px; |
|||
height: 100%; |
|||
|
|||
div { |
|||
width: 450px; |
|||
} |
|||
} |
|||
|
|||
.scenic-right { |
|||
width: 150px; |
|||
font-weight: 500; |
|||
font-size: 24px; |
|||
color: #71B580; |
|||
|
|||
img { |
|||
width: 37px; |
|||
height: 37px; |
|||
margin-bottom: 5px; |
|||
} |
|||
|
|||
div { |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.scenic-content { |
|||
margin-top: 42px; |
|||
font-weight: bold; |
|||
font-size: 32px; |
|||
color: #000000; |
|||
|
|||
div { |
|||
font-weight: 500; |
|||
font-size: 27px; |
|||
color: #333333; |
|||
line-height: 44px; |
|||
margin-top: 10px; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,79 @@ |
|||
const path = require('path') // 引入path模块
|
|||
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; |
|||
|
|||
function resolve(dir) { |
|||
return path.join(__dirname, dir) // path.join(__dirname)设置绝对路径
|
|||
} |
|||
const { |
|||
defineConfig |
|||
} = require('@vue/cli-service') |
|||
module.exports = defineConfig({ |
|||
lintOnSave: false, // 关闭eslint校验
|
|||
transpileDependencies: true, |
|||
publicPath: '/', |
|||
// 将构建好的文件输出到哪里
|
|||
outputDir: process.env.VUE_APP_OUTPUTDIR, |
|||
// 放置生成的静态资源(js、css、img、fonts)的目录
|
|||
assetsDir: 'static', |
|||
// 指定生成的 index.html 的输出路径
|
|||
indexPath: 'index.html', |
|||
// 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度
|
|||
productionSourceMap: false, |
|||
// 是一个函数,允许对内部的 webpack 配置进行更细粒度的修改。
|
|||
chainWebpack: (config) => { |
|||
// 配置别名
|
|||
config.resolve.alias |
|||
.set('@', resolve('src')) |
|||
.set('assets', resolve('src/assets')) |
|||
.set('components', resolve('src/components')) |
|||
.set('views', resolve('src/views')) |
|||
|
|||
config.optimization.minimizer('terser').tap((args) => { |
|||
// 去除生产环境console
|
|||
args[0].terserOptions.compress.drop_console = true |
|||
return args |
|||
}) |
|||
}, |
|||
// 配置 Webpack 相关的配置项
|
|||
configureWebpack: config => { |
|||
// 配置 Webpack 插件
|
|||
// config.plugins.push(new HtmlWebpackPlugin({
|
|||
// template: './public/index.html'
|
|||
// }))
|
|||
if(process.env.NODE_ENV == 'production'){ |
|||
config.plugins.push(new BundleAnalyzerPlugin({ |
|||
analyzerMode: 'server', |
|||
analyzerHost: '127.0.0.1', |
|||
analyzerPort: 8888, //注意是否有端口冲突
|
|||
reportFilename: 'report.html', |
|||
defaultSizes: 'parsed', |
|||
openAnalyzer: true, |
|||
generateStatsFile: false, |
|||
statsFilename: 'stats.json', |
|||
statsOptions: null, |
|||
logLevel: 'info' |
|||
})) |
|||
} |
|||
}, |
|||
// 配置开发服务器
|
|||
// 本地项目运行时的环境配置
|
|||
devServer: { |
|||
host: 'localhost', |
|||
port: 8080, // 端口号
|
|||
https: false, |
|||
open: false, // 配置自动启动浏览器 open: 'Google Chrome'-默认启动谷歌
|
|||
hot: true, // 热更新
|
|||
|
|||
proxy: { |
|||
'/api': { |
|||
target: 'http://localhost:3000', // 要访问的跨域的域名
|
|||
ws: true, // 是否启用websockets
|
|||
changeOrigin: true, // 开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样客户端端和服务端进行数据的交互就不会有跨域问题
|
|||
pathRewrite: { |
|||
'^/api': '' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}) |
Loading…
Reference in new issue