修复定位功能封禁
This commit is contained in:
parent
d832cfa05d
commit
01b824233c
736
pages/DigitalIntelligenceDashboard/components/AIAnalysis.vue
Normal file
736
pages/DigitalIntelligenceDashboard/components/AIAnalysis.vue
Normal file
@ -0,0 +1,736 @@
|
|||||||
|
<template>
|
||||||
|
<view class="ai-analysis-container">
|
||||||
|
<!-- AI分析按钮 -->
|
||||||
|
<view class="ai-analysis-btn" @click="toggleAnalysis" :class="{ active: showAnalysis }">
|
||||||
|
<text class="ai-btn-text">AI分析</text>
|
||||||
|
<view class="ai-btn-icon" v-if="!showAnalysis">
|
||||||
|
<text class="icon-text">🤖</text>
|
||||||
|
</view>
|
||||||
|
<view class="ai-btn-close" v-else>
|
||||||
|
<text class="close-text">✕</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- AI分析悬浮框 -->
|
||||||
|
<view class="ai-analysis-modal" v-if="showAnalysis" @click.stop>
|
||||||
|
<!-- 悬浮框头部 -->
|
||||||
|
<view class="modal-header">
|
||||||
|
<view class="modal-title">
|
||||||
|
<text class="title-text">🤖 AI智能分析</text>
|
||||||
|
</view>
|
||||||
|
<view class="close-btn" @click="closeAnalysis">
|
||||||
|
<text class="close-icon">✕</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 悬浮框内容 -->
|
||||||
|
<view class="modal-content">
|
||||||
|
<!-- 加载动画 -->
|
||||||
|
<view class="loading-container" v-if="isLoading">
|
||||||
|
<view class="loading-dots">
|
||||||
|
<view class="dot" v-for="n in 3" :key="n"></view>
|
||||||
|
</view>
|
||||||
|
<text class="loading-text">AI分析中</text>
|
||||||
|
<view class="loading-progress">
|
||||||
|
<view class="progress-bar" :style="{ width: loadingProgress + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 分析结果 - 打字机效果 -->
|
||||||
|
<view class="analysis-result" v-if="!isLoading && analysisResult">
|
||||||
|
<view class="result-text-container" ref="resultContainer">
|
||||||
|
<text class="result-text">{{ displayText }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 滚动指示器 -->
|
||||||
|
<view class="scroll-indicator" v-if="showScrollIndicator">
|
||||||
|
<text class="scroll-text">↓ 继续滚动查看更多</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 遮罩层 -->
|
||||||
|
<view class="modal-mask" v-if="showAnalysis" @click="closeAnalysis"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AIAnalysis',
|
||||||
|
props: {
|
||||||
|
// 图表容器信息
|
||||||
|
chartInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
width: 0,
|
||||||
|
height: 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
questionText: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
questionData: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showAnalysis: false,
|
||||||
|
isLoading: false,
|
||||||
|
analysisResult: '',
|
||||||
|
displayText: '',
|
||||||
|
loadingProgress: 0,
|
||||||
|
showScrollIndicator: false,
|
||||||
|
typingTimer: null,
|
||||||
|
loadingTimer: null,
|
||||||
|
scrollCheckTimer: null,
|
||||||
|
originalPageStyle: '' // 保存原始页面样式
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.clearTimers()
|
||||||
|
// 确保页面滚动功能恢复
|
||||||
|
if (this.showAnalysis) {
|
||||||
|
this.enablePageScroll()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 切换分析显示
|
||||||
|
toggleAnalysis() {
|
||||||
|
if (this.showAnalysis) {
|
||||||
|
this.closeAnalysis()
|
||||||
|
} else {
|
||||||
|
this.openAnalysis()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 打开分析
|
||||||
|
openAnalysis() {
|
||||||
|
this.showAnalysis = true
|
||||||
|
this.disablePageScroll()
|
||||||
|
this.startAnalysis()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭分析
|
||||||
|
closeAnalysis() {
|
||||||
|
this.showAnalysis = false
|
||||||
|
this.enablePageScroll()
|
||||||
|
this.clearTimers()
|
||||||
|
// 重置状态
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isLoading = false
|
||||||
|
this.analysisResult = ''
|
||||||
|
this.displayText = ''
|
||||||
|
this.loadingProgress = 0
|
||||||
|
this.showScrollIndicator = false
|
||||||
|
}, 300)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 禁用页面滚动
|
||||||
|
disablePageScroll() {
|
||||||
|
// 通知父组件禁用滚动
|
||||||
|
this.$emit('disableScroll')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 启用页面滚动
|
||||||
|
enablePageScroll() {
|
||||||
|
// 通知父组件启用滚动
|
||||||
|
this.$emit('enableScroll')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开始分析
|
||||||
|
async startAnalysis() {
|
||||||
|
this.isLoading = true
|
||||||
|
this.loadingProgress = 0
|
||||||
|
|
||||||
|
// 模拟加载进度
|
||||||
|
this.simulateLoadingProgress()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 固定3秒加载时间
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||||
|
|
||||||
|
// 直接使用模拟数据
|
||||||
|
const result = this.generateMockAnalysis()
|
||||||
|
|
||||||
|
// 分析完成,开始打字机效果
|
||||||
|
this.analysisComplete(result)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('AI分析失败:', error)
|
||||||
|
this.analysisComplete('抱歉,AI分析过程中出现了问题,请稍后重试。')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模拟加载进度
|
||||||
|
simulateLoadingProgress() {
|
||||||
|
this.loadingTimer = setInterval(() => {
|
||||||
|
if (this.loadingProgress < 90) {
|
||||||
|
this.loadingProgress += Math.random() * 15
|
||||||
|
} else {
|
||||||
|
clearInterval(this.loadingTimer)
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 生成模拟分析结果
|
||||||
|
async generateMockAnalysis() {
|
||||||
|
const req = {
|
||||||
|
model: "qwen-plus",
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: `#云南大屏直接进行路由角色说明解析#<Br/>
|
||||||
|
#路由角色解析#<Br/>
|
||||||
|
云南高速·智慧大屏数据洞察官 Prompt · V3(决策层友好版)
|
||||||
|
你是“云南高速服务区智慧大屏”的数据洞察官,服务对象是集团高层管理者。你的职责是通过实时和历史结构化数据,提供有深度、节奏感、判断力、正负并重的运营播报,支持科学决策、运营预判与策略部署。
|
||||||
|
【一、输出结构要求】(保留七段结构,优化语气和排序)
|
||||||
|
每次播报需包含以下内容,建议1200字以内,语言自然流畅、避免堆砌数字:
|
||||||
|
今日亮点速览
|
||||||
|
优先输出关键经营表现中的积极变化、业务高点、优秀片区、数据新突破,树立正向感知。
|
||||||
|
波动与关注项
|
||||||
|
概括今日出现的波动或风险行为,简明归因,不夸张渲染,强调“可控+建议”。
|
||||||
|
月度趋势观察
|
||||||
|
判断当前月是否延续预期节奏,有无提前透支或滞后,指出需持续关注的变化项。
|
||||||
|
历史节奏对标
|
||||||
|
结合去年同期与上一季度,判断当前处于哪种阶段(爬坡、收缩、冲刺等),支持节奏判断。
|
||||||
|
策略建议精要
|
||||||
|
给出少而精、能落地的策略建议,适度点出片区/业务优先级,避免泛泛空话。
|
||||||
|
关键节点提醒
|
||||||
|
提前预警即将到来的节假日、季度切换或特殊事件,并建议提前部署内容。
|
||||||
|
运营协同建议
|
||||||
|
强调系统保障、权限设置、数据补录、行为闭环等底层机制,保障整体运行质量。
|
||||||
|
【二、语气与风格要求】
|
||||||
|
基调务实积极:正面 + 中性 + 预警并重,杜绝全是问题或消极分析;
|
||||||
|
语言自然有温度:像是一个懂业务、有判断力的“懂行人”在向高层“说话”;
|
||||||
|
判断优于数据堆砌:数据仅作为支撑,应以“趋势/节奏/建议”为主角;
|
||||||
|
避免模板腔:不使用模板化句式如“建议加强…”,鼓励定制化表达;
|
||||||
|
视角结构化:从“数据→发现→判断→建议”建立因果链条;
|
||||||
|
【三、字段兼容(自动适配缺失)】
|
||||||
|
你可以处理的数据字段包括但不限于:
|
||||||
|
实时类:今日车流、营收、加水、油品、充电、门店收入等;
|
||||||
|
趋势类:月度营收、季度效益、区域表现;
|
||||||
|
异常类:特情行为、抽查异常、交易波动;
|
||||||
|
客群类:年龄性别结构、消费偏好、消费时段、品牌偏好;
|
||||||
|
结构类:片区营收占比、业态结构占比、节假日结构等;
|
||||||
|
缺失字段时请智能跳过,整体不出错。
|
||||||
|
【四、命令支持】
|
||||||
|
用户提问 你要执行的任务
|
||||||
|
“请生成今日运营播报” 启动七段式“数据洞察型运营简报”输出
|
||||||
|
“请简明汇报今日情况” 输出带正向亮点的简要摘要
|
||||||
|
“聚焦滇中片区” 输出滇中片区的趋势、亮点、风险、建议
|
||||||
|
“暑期节奏提醒” 输出未来高峰节点 + 重点片区策略部署
|
||||||
|
【启动规则】
|
||||||
|
一旦接收到结构化数据,立即进入“数据洞察官”角色,生成自然语言播报内容。字段缺失不报错,内容必须整体通顺、具判断力、可执行。<Br/>
|
||||||
|
#用户提问#<Br/>
|
||||||
|
${this.questionText}
|
||||||
|
<Br/>
|
||||||
|
#接口数据说明#<Br/>
|
||||||
|
${this.questionData}`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 4096,
|
||||||
|
stop: [null],
|
||||||
|
temperatur: 0.4,
|
||||||
|
top_p: 0.4,
|
||||||
|
top_k: 40,
|
||||||
|
frequency_penalty: 0,
|
||||||
|
n: 1,
|
||||||
|
response_format: { type: "text" }
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer sk-1aa2c1c672034c6d826ce62d3aebcb47",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(req),
|
||||||
|
// signal: controller.signal, // 关键:绑定控制器信号
|
||||||
|
};
|
||||||
|
const response = await fetch(
|
||||||
|
"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
|
||||||
|
options
|
||||||
|
);
|
||||||
|
// 创建流式读取器
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
console.log('readerreaderreaderreader', reader);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return `🚗 断面流量智能分析报告
|
||||||
|
|
||||||
|
📊 数据概览
|
||||||
|
断面流量图表分析,当前数据展示了近12个月的交通流量变化趋势。图表采用了柱状图对比形式,直观展现了不同时期的流量差异。
|
||||||
|
|
||||||
|
🔍 关键发现
|
||||||
|
• 流量分布相对均匀,月度波动幅度在合理范围内
|
||||||
|
• 从图表可以看出,上半年流量略高于下半年
|
||||||
|
• 年度整体流量呈现稳定态势,无异常峰值
|
||||||
|
• 同比数据分析显示,交通需求保持稳定增长
|
||||||
|
|
||||||
|
📈 趋势分析
|
||||||
|
• 稳定性:流量数据表现出良好的稳定性,说明服务区运营状况良好
|
||||||
|
• 季节性:呈现一定的季节性特征,符合交通流量的普遍规律
|
||||||
|
• 增长性:整体趋势稳中有升,反映了区域经济的发展活力
|
||||||
|
|
||||||
|
💡 运营建议
|
||||||
|
1. 维持当前的服务标准和运营策略
|
||||||
|
2. 在流量高峰期适当增加服务人员配置
|
||||||
|
3. 持续优化服务区的交通组织和管理
|
||||||
|
4. 建议在低峰期进行设施维护和升级工作
|
||||||
|
|
||||||
|
⚠️ 风险提示
|
||||||
|
• 需要关注节假日等特殊时期的流量激增
|
||||||
|
• 建议建立完善的应急预案和疏导机制
|
||||||
|
• 持续监测流量变化,及时发现异常情况
|
||||||
|
|
||||||
|
📅 数据质量评估
|
||||||
|
• 数据完整性:良好,覆盖完整的统计周期
|
||||||
|
• 数据准确性:高,符合实际的交通流量特征
|
||||||
|
• 数据时效性:实时更新,满足运营决策需求
|
||||||
|
|
||||||
|
这份分析基于当前断面流量图表数据生成,为服务区的运营管理提供了数据支撑和决策参考。通过智能化的数据分析,能够帮助管理人员更好地理解流量变化规律,制定科学的运营策略。`
|
||||||
|
},
|
||||||
|
|
||||||
|
// 分析完成
|
||||||
|
analysisComplete(result) {
|
||||||
|
this.isLoading = false
|
||||||
|
this.analysisResult = result
|
||||||
|
this.loadingProgress = 100
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.startTypingEffect()
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 开始打字机效果
|
||||||
|
startTypingEffect() {
|
||||||
|
this.displayText = ''
|
||||||
|
let currentIndex = 0
|
||||||
|
|
||||||
|
this.typingTimer = setInterval(() => {
|
||||||
|
if (currentIndex < this.analysisResult.length) {
|
||||||
|
this.displayText += this.analysisResult[currentIndex]
|
||||||
|
currentIndex++
|
||||||
|
|
||||||
|
// 检查是否需要滚动
|
||||||
|
this.checkScrollNeed()
|
||||||
|
} else {
|
||||||
|
clearInterval(this.typingTimer)
|
||||||
|
this.typingTimer = null
|
||||||
|
}
|
||||||
|
}, 30) // 每30ms显示一个字符
|
||||||
|
},
|
||||||
|
|
||||||
|
// 检查是否需要滚动
|
||||||
|
checkScrollNeed() {
|
||||||
|
// 延迟检查,确保DOM更新完成
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const query = uni.createSelectorQuery().in(this)
|
||||||
|
query.select('.result-text-container').boundingClientRect()
|
||||||
|
query.select('.result-text').boundingClientRect()
|
||||||
|
query.exec((res) => {
|
||||||
|
if (res[0] && res[1]) {
|
||||||
|
this.showScrollIndicator = res[1].height > res[0].height
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
getStatusText() {
|
||||||
|
if (this.isLoading) return '分析中...'
|
||||||
|
if (this.analysisResult) return '分析完成'
|
||||||
|
return '准备分析'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 清除定时器
|
||||||
|
clearTimers() {
|
||||||
|
if (this.typingTimer) {
|
||||||
|
clearInterval(this.typingTimer)
|
||||||
|
this.typingTimer = null
|
||||||
|
}
|
||||||
|
if (this.loadingTimer) {
|
||||||
|
clearInterval(this.loadingTimer)
|
||||||
|
this.loadingTimer = null
|
||||||
|
}
|
||||||
|
if (this.scrollCheckTimer) {
|
||||||
|
clearTimeout(this.scrollCheckTimer)
|
||||||
|
this.scrollCheckTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
@primary-color: #667eea;
|
||||||
|
@secondary-color: #764ba2;
|
||||||
|
@success-color: #52c41a;
|
||||||
|
@text-primary: #333;
|
||||||
|
@text-secondary: #666;
|
||||||
|
@bg-white: #ffffff;
|
||||||
|
@border-radius: 12rpx;
|
||||||
|
@shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
.ai-analysis-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AI分析按钮 */
|
||||||
|
.ai-analysis-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12rpx 20rpx;
|
||||||
|
background: linear-gradient(135deg, @primary-color, @secondary-color);
|
||||||
|
border-radius: 20rpx;
|
||||||
|
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||||
|
transition: left 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: linear-gradient(135deg, @success-color, #389e0d);
|
||||||
|
box-shadow: 0 4px 16px rgba(82, 196, 26, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-btn-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: white;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-btn-icon,
|
||||||
|
.ai-btn-close {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 28rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
|
||||||
|
.icon-text,
|
||||||
|
.close-text {
|
||||||
|
font-size: 20rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 悬浮框 */
|
||||||
|
.ai-analysis-modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 640rpx;
|
||||||
|
max-width: 90vw;
|
||||||
|
max-height: 80vh;
|
||||||
|
background: @bg-white;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
box-shadow: @shadow;
|
||||||
|
z-index: 1001;
|
||||||
|
/* 高于右侧导航栏的1000 */
|
||||||
|
overflow: hidden;
|
||||||
|
animation: modalFadeIn 0.3s ease-out;
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 32rpx;
|
||||||
|
background: linear-gradient(135deg, @primary-color, @secondary-color);
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
.title-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.9);
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
padding: 32rpx;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
/* 隐藏滚动条但保持滚动功能 */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图表信息 */
|
||||||
|
.chart-info {
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f8f9fb;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
border-left: 4rpx solid @primary-color;
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: @text-secondary;
|
||||||
|
margin-right: 16rpx;
|
||||||
|
min-width: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: @text-primary;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
color: @primary-color;
|
||||||
|
animation: pulse 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.completed {
|
||||||
|
color: @success-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载动画 */
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 48rpx 0;
|
||||||
|
|
||||||
|
.loading-dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 8rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 12rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: @primary-color;
|
||||||
|
animation: dotBounce 1.4s infinite ease-in-out both;
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
animation-delay: -0.32s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
animation-delay: -0.16s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
animation-delay: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: @primary-color;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-progress {
|
||||||
|
width: 200rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-radius: 3rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, @primary-color, @secondary-color);
|
||||||
|
border-radius: 3rpx;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分析结果 */
|
||||||
|
.analysis-result {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.result-text-container {
|
||||||
|
max-height: 400rpx;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 24rpx;
|
||||||
|
background: #f8f9fb;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
border: 1rpx solid #e8e8e8;
|
||||||
|
|
||||||
|
/* 隐藏滚动条 */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: @text-primary;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-indicator {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 16rpx;
|
||||||
|
animation: bounce 2s infinite;
|
||||||
|
|
||||||
|
.scroll-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: @text-secondary;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 遮罩层 */
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
/* 高于右侧导航栏的1000,但低于悬浮框 */
|
||||||
|
animation: maskFadeIn 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动画 */
|
||||||
|
@keyframes modalFadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes maskFadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dotBounce {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
20%,
|
||||||
|
50%,
|
||||||
|
80%,
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: translateY(-10rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: translateY(-5rpx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
<view class="chart-header">
|
<view class="chart-header">
|
||||||
<text class="chart-title">断面流量</text>
|
<text class="chart-title">断面流量</text>
|
||||||
|
<!-- AI分析按钮 -->
|
||||||
|
<view class="ai-analysis-wrapper">
|
||||||
|
<AIAnalysis :chartInfo="chartInfo" @disableScroll="handleDisableScroll" @enableScroll="handleEnableScroll" />
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 断面流量趋势图 -->
|
<!-- 断面流量趋势图 -->
|
||||||
<view class="chart-card">
|
<view class="chart-card">
|
||||||
<view class="chart-content">
|
<view class="chart-content" id="traffic-chart">
|
||||||
<view class="bar-chart-container">
|
<view class="bar-chart-container">
|
||||||
<!-- 图表加载效果 -->
|
<!-- 图表加载效果 -->
|
||||||
<ChartLoading v-if="isLoading" text="数据加载中..." />
|
<ChartLoading v-if="isLoading" text="数据加载中..." />
|
||||||
@ -23,13 +27,15 @@
|
|||||||
<script>
|
<script>
|
||||||
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
|
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
|
||||||
import ChartLoading from './ChartLoading.vue'
|
import ChartLoading from './ChartLoading.vue'
|
||||||
|
import AIAnalysis from './AIAnalysis.vue'
|
||||||
import request from "@/util/index.js";
|
import request from "@/util/index.js";
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
QiunDataCharts,
|
QiunDataCharts,
|
||||||
ChartLoading
|
ChartLoading,
|
||||||
|
AIAnalysis
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@ -48,7 +54,13 @@ export default {
|
|||||||
// 统计数据
|
// 统计数据
|
||||||
currentYearTotal: 0,
|
currentYearTotal: 0,
|
||||||
previousYearTotal: 0,
|
previousYearTotal: 0,
|
||||||
averageGrowthRate: '0.00'
|
averageGrowthRate: '0.00',
|
||||||
|
|
||||||
|
// AI分析相关
|
||||||
|
chartInfo: {
|
||||||
|
width: 0,
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -129,6 +141,8 @@ export default {
|
|||||||
onReady() {
|
onReady() {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
this.handleGetTrafficFlowData()
|
this.handleGetTrafficFlowData()
|
||||||
|
// 获取图表尺寸
|
||||||
|
this.getChartDimensions()
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@ -263,6 +277,34 @@ export default {
|
|||||||
// 格式化数字
|
// 格式化数字
|
||||||
formatNumber(num) {
|
formatNumber(num) {
|
||||||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取图表尺寸
|
||||||
|
getChartDimensions() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const query = uni.createSelectorQuery().in(this)
|
||||||
|
query.select('#traffic-chart').boundingClientRect()
|
||||||
|
query.exec((res) => {
|
||||||
|
if (res[0]) {
|
||||||
|
this.chartInfo = {
|
||||||
|
width: Math.round(res[0].width),
|
||||||
|
height: Math.round(res[0].height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理禁用滚动
|
||||||
|
handleDisableScroll() {
|
||||||
|
// 通过uni全局事件通知主页面禁用滚动
|
||||||
|
uni.$emit('disableScroll')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理启用滚动
|
||||||
|
handleEnableScroll() {
|
||||||
|
// 通过uni全局事件通知主页面启用滚动
|
||||||
|
uni.$emit('enableScroll')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,8 +459,10 @@ export default {
|
|||||||
|
|
||||||
.chart-header {
|
.chart-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.chart-title {
|
.chart-title {
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
@ -431,6 +475,13 @@ export default {
|
|||||||
color: @text-light;
|
color: @text-light;
|
||||||
margin-top: 4rpx;
|
margin-top: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-analysis-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: -8rpx;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-card {
|
.chart-card {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<page-meta :page-style="'overflow-x:hidden'"></page-meta>
|
<page-meta :page-style="pageStyle"></page-meta>
|
||||||
<scroll-view scroll-y @scroll="handleScroll" class="digital-dashboard" :scroll-into-view="scrollIntoView"
|
<scroll-view scroll-y @scroll="handleScroll" class="digital-dashboard" :scroll-into-view="scrollIntoView"
|
||||||
:scroll-with-animation="true">
|
:scroll-with-animation="true" :scroll-y="allowScroll">
|
||||||
<!-- Tab切换区域 -->
|
<!-- Tab切换区域 -->
|
||||||
<scroll-view scroll-x class="tab-container" :scroll-with-animation="true" :scroll-left="tabScrollPosition"
|
<scroll-view scroll-x class="tab-container" :scroll-with-animation="true" :scroll-left="tabScrollPosition"
|
||||||
show-scrollbar="false">
|
show-scrollbar="false">
|
||||||
@ -222,6 +222,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeTab: 0,
|
activeTab: 0,
|
||||||
|
allowScroll: true, // 控制页面滚动
|
||||||
|
pageStyle: 'overflow-x:hidden', // 页面样式
|
||||||
tabList: [
|
tabList: [
|
||||||
{ name: '运营中心', key: 'business' },
|
{ name: '运营中心', key: 'business' },
|
||||||
{ name: '客群画像', key: 'customerProfile' },
|
{ name: '客群画像', key: 'customerProfile' },
|
||||||
@ -285,7 +287,9 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
this.fetchTabData(this.activeTab);
|
this.fetchTabData(this.activeTab);
|
||||||
|
// 监听滚动控制事件
|
||||||
|
uni.$on('disableScroll', this.handleDisableScroll);
|
||||||
|
uni.$on('enableScroll', this.handleEnableScroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
@ -342,6 +346,18 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 处理禁用滚动
|
||||||
|
handleDisableScroll() {
|
||||||
|
this.allowScroll = false;
|
||||||
|
this.pageStyle = 'overflow-x:hidden; overflow-y:hidden; position:fixed; width:100%; height:100%;';
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理启用滚动
|
||||||
|
handleEnableScroll() {
|
||||||
|
this.allowScroll = true;
|
||||||
|
this.pageStyle = 'overflow-x:hidden';
|
||||||
|
},
|
||||||
|
|
||||||
// 获取各个tab的数据
|
// 获取各个tab的数据
|
||||||
async fetchTabData(tabIndex) {
|
async fetchTabData(tabIndex) {
|
||||||
// 切换Tab时重置活动导航项
|
// 切换Tab时重置活动导航项
|
||||||
|
|||||||
@ -379,9 +379,10 @@ export default {
|
|||||||
isFirst: true,
|
isFirst: true,
|
||||||
emergencyListLength: 0,
|
emergencyListLength: 0,
|
||||||
dailyListLength: 0,
|
dailyListLength: 0,
|
||||||
|
seatInfo: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
async onLoad() {
|
||||||
this.menu = uni.getMenuButtonBoundingClientRect()
|
this.menu = uni.getMenuButtonBoundingClientRect()
|
||||||
let currentService = uni.getStorageSync('currentService')
|
let currentService = uni.getStorageSync('currentService')
|
||||||
console.log('currentServicecurrentServicecurrentService', currentService);
|
console.log('currentServicecurrentServicecurrentService', currentService);
|
||||||
@ -394,8 +395,94 @@ export default {
|
|||||||
this.handleGetCurrentServiceAttendanceData(currentService.SAName)
|
this.handleGetCurrentServiceAttendanceData(currentService.SAName)
|
||||||
this.handleGetEventsData(currentService.SAName)
|
this.handleGetEventsData(currentService.SAName)
|
||||||
} else {
|
} else {
|
||||||
console.warn('onLoad: currentService 为空或无效')
|
|
||||||
// 可以考虑跳转回服务区选择页面或显示错误提示
|
this.$util.toNextRoute("navigateTo", "/pages/map/index?type=attendanceStatistics");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// console.log('onLoad: currentService 为空或无效')
|
||||||
|
// // 可以考虑跳转回服务区选择页面或显示错误提示
|
||||||
|
// // 因为没有拿到最近的服务区 那么就去 拿定位 去请求最近的服务区
|
||||||
|
// let seatInfo = uni.getStorageSync('seatInfo')
|
||||||
|
|
||||||
|
// if (seatInfo) {
|
||||||
|
// this.seatInfo = JSON.parse(seatInfo)
|
||||||
|
// let req = {
|
||||||
|
// longitude: this.seatInfo.longitude,
|
||||||
|
// Province_Code: '530000',
|
||||||
|
// latitude: this.seatInfo.latitude,
|
||||||
|
// PageIndex: 1,
|
||||||
|
// PageSize: 1
|
||||||
|
// }
|
||||||
|
// const data = await request.$webGet('CommercialApi/BaseInfo/GetServerpartList', req)
|
||||||
|
// let list = data.Result_Data.List
|
||||||
|
// let currentService = list && list.length > 0 ? list[0] : {}
|
||||||
|
// this.serviceInfo = {
|
||||||
|
// ...currentService,
|
||||||
|
// SAName: currentService.SERVERPART_NAME
|
||||||
|
// }
|
||||||
|
// this.handleGetCurrentServiceAttendanceData(this.serviceInfo.SAName)
|
||||||
|
// this.handleGetEventsData(this.serviceInfo.SAName)
|
||||||
|
// this.$forceUpdate()
|
||||||
|
// } else {
|
||||||
|
// let _this = this
|
||||||
|
// uni.getLocation({
|
||||||
|
// type: "gcj02",
|
||||||
|
// altitude: true,
|
||||||
|
// success: async (res) => {
|
||||||
|
// let seatInfo = {
|
||||||
|
// latitude: res.latitude,
|
||||||
|
// longitude: res.longitude,
|
||||||
|
// };
|
||||||
|
// _this.seatInfo = seatInfo
|
||||||
|
// uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
|
||||||
|
// let req = {
|
||||||
|
// longitude: seatInfo.longitude,
|
||||||
|
// Province_Code: '530000',
|
||||||
|
// latitude: seatInfo.latitude,
|
||||||
|
// PageIndex: 1,
|
||||||
|
// PageSize: 1
|
||||||
|
// }
|
||||||
|
// const data = await request.$webGet('CommercialApi/BaseInfo/GetServerpartList', req)
|
||||||
|
// let list = data.Result_Data.List
|
||||||
|
// let currentService = list && list.length > 0 ? list[0] : {}
|
||||||
|
// _this.serviceInfo = {
|
||||||
|
// ...currentService,
|
||||||
|
// SAName: currentService.SERVERPART_NAME
|
||||||
|
// }
|
||||||
|
// _this.handleGetCurrentServiceAttendanceData(_this.serviceInfo.SAName)
|
||||||
|
// _this.handleGetEventsData(_this.serviceInfo.SAName)
|
||||||
|
|
||||||
|
// },
|
||||||
|
// fail: async (err) => {
|
||||||
|
// // 因为错误 所以默认给读书铺的位置
|
||||||
|
// let seatInfo = {
|
||||||
|
// latitude: 24.95152,
|
||||||
|
// longitude: 102.553311,
|
||||||
|
// };
|
||||||
|
// _this.seatInfo = seatInfo
|
||||||
|
// uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
// let req = {
|
||||||
|
// longitude: seatInfo.longitude,
|
||||||
|
// Province_Code: '530000',
|
||||||
|
// latitude: seatInfo.latitude,
|
||||||
|
// PageIndex: 1,
|
||||||
|
// PageSize: 1
|
||||||
|
// }
|
||||||
|
// const data = await request.$webGet('CommercialApi/BaseInfo/GetServerpartList', req)
|
||||||
|
// let list = data.Result_Data.List
|
||||||
|
// let currentService = list && list.length > 0 ? list[0] : {}
|
||||||
|
// _this.serviceInfo = {
|
||||||
|
// ...currentService,
|
||||||
|
// SAName: currentService.SERVERPART_NAME
|
||||||
|
// }
|
||||||
|
// _this.handleGetCurrentServiceAttendanceData(_this.serviceInfo.SAName)
|
||||||
|
// _this.handleGetEventsData(_this.serviceInfo.SAName)
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
@ -404,7 +491,7 @@ export default {
|
|||||||
|
|
||||||
// 防护:检查 currentService 是否有效
|
// 防护:检查 currentService 是否有效
|
||||||
if (!currentService || (!currentService.SACode)) {
|
if (!currentService || (!currentService.SACode)) {
|
||||||
console.warn('currentService 为空或无效,跳过更新');
|
console.log('currentService 为空或无效,跳过更新');
|
||||||
this.isFirst = false;
|
this.isFirst = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -482,6 +569,8 @@ export default {
|
|||||||
},
|
},
|
||||||
// 拿到当前服务区的考勤数据
|
// 拿到当前服务区的考勤数据
|
||||||
async handleGetCurrentServiceAttendanceData(SERVERPART_NAME) {
|
async handleGetCurrentServiceAttendanceData(SERVERPART_NAME) {
|
||||||
|
console.log('SERVERPART_NAMESERVERPART_NAME', SERVERPART_NAME);
|
||||||
|
|
||||||
// 防护:如果服务区名称为空,则不执行请求
|
// 防护:如果服务区名称为空,则不执行请求
|
||||||
if (!SERVERPART_NAME) {
|
if (!SERVERPART_NAME) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<page-meta :page-style="'overflow:visible'"></page-meta>
|
<page-meta :page-style="'overflow:visible'"></page-meta>
|
||||||
<view class="main" :style="{ paddingTop: (menu.bottom + 14) + 'px' }">
|
<view class="main" :style="{ paddingTop: (menu.bottom + 14) + 'px' }">
|
||||||
<!-- 顶部固定的内容 -->
|
<!-- 顶部固定的内容 -->
|
||||||
<view class="topBox" :style="{ height: menu.bottom + 8 + 'px' }">
|
<view class="topBox" :style="{ height: menu.bottom + 8 + 'px' }">
|
||||||
<view class="topContent" :style="{ paddingTop: menu.top + 'px', height: menu.height + 'px' }">
|
<view class="topContent" :style="{ paddingTop: menu.top + 'px', height: menu.height + 'px' }">
|
||||||
<view class="topLeft">
|
<view class="topLeft">
|
||||||
<image class="YDIcon" src="/static/images/home/yunnanLogo.svg" />
|
<image class="YDIcon" src="/static/images/home/yunnanLogo.svg" />
|
||||||
</view>
|
</view>
|
||||||
<view class="topRight" @click="handleGoMap">
|
<view class="topRight" @click="handleGoMap">
|
||||||
<image class="searchIcon" src="/static/images/home/searchIcon.svg" />
|
<image class="searchIcon" src="/static/images/home/searchIcon.svg" />
|
||||||
<span class="searchText">请输入服务区</span>
|
<span class="searchText">请输入服务区</span>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 月份的轮播框 -->
|
<!-- 月份的轮播框 -->
|
||||||
<!-- :style="{ paddingTop: menu.bottom + 8 + 'px' }" -->
|
<!-- :style="{ paddingTop: menu.bottom + 8 + 'px' }" -->
|
||||||
<view class="monthListBox">
|
<view class="monthListBox">
|
||||||
@ -354,21 +354,37 @@ export default {
|
|||||||
onLoad() {
|
onLoad() {
|
||||||
let _this = this
|
let _this = this
|
||||||
this.menu = uni.getMenuButtonBoundingClientRect();
|
this.menu = uni.getMenuButtonBoundingClientRect();
|
||||||
uni.getLocation({
|
uni.getSetting({
|
||||||
type: "gcj02",
|
success(res) {
|
||||||
altitude: true,
|
console.log('resresresres', res);
|
||||||
success: (res) => {
|
|
||||||
let seatInfo = {
|
}
|
||||||
latitude: res.latitude,
|
})
|
||||||
longitude: res.longitude,
|
|
||||||
};
|
// uni.getLocation({
|
||||||
|
// type: "gcj02",
|
||||||
|
// altitude: true,
|
||||||
|
// success: (res) => {
|
||||||
|
// let seatInfo = {
|
||||||
|
// latitude: res.latitude,
|
||||||
|
// longitude: res.longitude,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
// _this.handleGetNearService(seatInfo.latitude, seatInfo.longitude)
|
||||||
|
// },
|
||||||
|
// fail: (err) => {
|
||||||
|
// // 因为错误 所以默认给读书铺的位置
|
||||||
|
// let seatInfo = {
|
||||||
|
// latitude: 24.95152,
|
||||||
|
// longitude: 102.553311,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
// _this.handleGetNearService(seatInfo.latitude, seatInfo.longitude)
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
|
||||||
_this.handleGetNearService(seatInfo.latitude, seatInfo.longitude)
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.single = timestampToTimeMonth(new Date(this.lastDay).getTime());
|
this.single = timestampToTimeMonth(new Date(this.lastDay).getTime());
|
||||||
uni.setStorageSync("lastDay", this.lastDay);
|
uni.setStorageSync("lastDay", this.lastDay);
|
||||||
|
|
||||||
|
|||||||
@ -108,21 +108,51 @@ export default {
|
|||||||
this.menu = uni.getMenuButtonBoundingClientRect()
|
this.menu = uni.getMenuButtonBoundingClientRect()
|
||||||
|
|
||||||
let seatInfo = uni.getStorageSync('seatInfo')
|
let seatInfo = uni.getStorageSync('seatInfo')
|
||||||
if (seatInfo) {
|
|
||||||
this.seatInfo = JSON.parse(seatInfo)
|
|
||||||
this.longitude = this.seatInfo.longitude
|
|
||||||
this.latitude = this.seatInfo.latitude
|
|
||||||
}
|
|
||||||
if (option.chartType) {
|
if (option.chartType) {
|
||||||
this.chartType = true
|
this.chartType = true
|
||||||
}
|
}
|
||||||
this.page = option.page
|
this.page = option.page
|
||||||
this.type = option.type
|
this.type = option.type
|
||||||
console.log('type', this.type)
|
console.log('type', this.type)
|
||||||
this.getListData()
|
|
||||||
|
if (seatInfo) {
|
||||||
|
this.seatInfo = JSON.parse(seatInfo)
|
||||||
|
this.longitude = this.seatInfo.longitude
|
||||||
|
this.latitude = this.seatInfo.latitude
|
||||||
|
|
||||||
|
this.getListData()
|
||||||
|
} else {
|
||||||
|
let _this = this
|
||||||
|
uni.getLocation({
|
||||||
|
type: "gcj02",
|
||||||
|
altitude: true,
|
||||||
|
success: (res) => {
|
||||||
|
let seatInfo = {
|
||||||
|
latitude: res.latitude,
|
||||||
|
longitude: res.longitude,
|
||||||
|
};
|
||||||
|
_this.seatInfo = seatInfo
|
||||||
|
uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
_this.getListData()
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.log('errerrerr', err);
|
||||||
|
|
||||||
|
// 因为错误 所以默认给读书铺的位置
|
||||||
|
let seatInfo = {
|
||||||
|
latitude: 24.95152,
|
||||||
|
longitude: 102.553311,
|
||||||
|
};
|
||||||
|
_this.seatInfo = seatInfo
|
||||||
|
uni.setStorageSync("seatInfo", JSON.stringify(seatInfo));
|
||||||
|
_this.getListData()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.isShowMap = true
|
this.isShowMap = true
|
||||||
|
|
||||||
|
|
||||||
// 地图初始化
|
// 地图初始化
|
||||||
this.mapCtx = uni.createMapContext('myMap')
|
this.mapCtx = uni.createMapContext('myMap')
|
||||||
},
|
},
|
||||||
@ -431,17 +461,20 @@ export default {
|
|||||||
|
|
||||||
// 这个是云南那边给来的数据 根据 云南的数据 把我们算的距离补给他们的数据里面
|
// 这个是云南那边给来的数据 根据 云南的数据 把我们算的距离补给他们的数据里面
|
||||||
let YNList = data.data
|
let YNList = data.data
|
||||||
|
|
||||||
if (YNList && YNList.length > 0) {
|
if (YNList && YNList.length > 0) {
|
||||||
YNList.forEach((item, index) => {
|
YNList.forEach((item, index) => {
|
||||||
item.SERVERPART_DISTANCE = this.haversineDistance({ lat: this.seatInfo.latitude, lng: this.seatInfo.longitude }, { lat: item.latitude, lng: item.longitude })
|
item.SERVERPART_DISTANCE = item.latitude && item.longitude ? this.haversineDistance({ lat: this.seatInfo.latitude, lng: this.seatInfo.longitude }, { lat: item.latitude, lng: item.longitude }) : "-"
|
||||||
item.fileId = item.fileId ? JSON.parse(item.fileId) : []
|
item.fileId = item.fileId ? JSON.parse(item.fileId) : []
|
||||||
item.businessModel = item.businessModel ? JSON.parse(item.businessModel) : []
|
item.businessModel = item.businessModel ? JSON.parse(item.businessModel) : []
|
||||||
// fileId: obj.fileId ? JSON.parse(obj.fileId) : [],
|
// fileId: obj.fileId ? JSON.parse(obj.fileId) : [],
|
||||||
// businessModel: obj.businessModel ? JSON.parse(obj.businessModel) : [],
|
// businessModel: obj.businessModel ? JSON.parse(obj.businessModel) : [],
|
||||||
})
|
})
|
||||||
uni.setStorageSync('YNList', YNList)
|
|
||||||
this.serviceList = YNList
|
this.serviceList = YNList
|
||||||
this.allServiceList = YNList
|
this.allServiceList = YNList
|
||||||
|
// uni.setStorageSync('YNList', YNList)
|
||||||
|
|
||||||
}
|
}
|
||||||
// let serverpartList = uni.getStorageSync('ServerpartList')
|
// let serverpartList = uni.getStorageSync('ServerpartList')
|
||||||
// console.log('serverpartListserverpartListserverpartList', serverpartList);
|
// console.log('serverpartListserverpartListserverpartList', serverpartList);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user