Commit 3286187e by 李宁

1:Merge branch 'master' into channelBusi

2 parents 6f1d956b f76422e3
......@@ -5,7 +5,14 @@ if(pa){
pa = {}
}
if(pa.orderId == '3356158'){
//3205:苏州市
let cheatArea = '3205'
if(cheatArea.includes(pa.areaType)){
indow.noShootNum = 5
window.snInputNum = 6
window.accountInputNum = 6
}else if(pa.orderId == '3356158'){
window.noShootNum = 2
window.snInputNum = 2
window.accountInputNum = 2
......
......@@ -8,7 +8,7 @@
data: {
info: {},
busiFlag: '--',
busiFlag: '',
areaCode: ''
},
created: function() {
......@@ -20,9 +20,11 @@
},
methods: {
httpRequest:function(param){
let origin = "https://hhzj.lgyzpt.com"
let origin = window.origin
if(origin.includes('localhost')>0 || origin=='null' || origin.includes('file:')>0 || window.origin.includes('testznzl')){
origin = 'https://testznzl.lgyzpt.com'
}else{
origin = "https://hhzj.lgyzpt.com"
}
return new Promise(function(resolve, reject){
......@@ -63,14 +65,17 @@
url = "https://testznzl.lgyzpt.com/activity/zjbPhone/addBusi.html"
}
window.location.replace(url+"?source=zhijian&phone="+this.info.accNbr+"&areaCode="+this.areaCode+"&campaignId="+this.info.campaignId)
//window.location.replace(url+"?source=zhijian&phone="+this.info.accNbr+"&areaCode="+this.areaCode+"&campaignId="+this.info.campaignId)
// window.location.replace(
// `${url}?source=zhijian\
// &phone=${this.info.accNbr}\
// &areaCode=${this.areaCode}\
// &campaignId=${this.info.campaignId}`
// );
window.location.replace(
`${url}?source=zhijian` +
`&areaCode=${this.areaCode}` +
`&accNbr=${this.info.accNbr}` +
`&sysId=${this.info.sysId}` +
`&orderId=${this.info.orderId}` +
`&areaType=${this.info.areaType}` +
`&campaignId=${this.info.campaignId}`
)
},
goBack(){
history.go(-1)
......
......@@ -36,6 +36,6 @@
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/result.js?666633"></script>
<script src="js/result.js?6666399300"></script>
</body>
</html>
\ No newline at end of file
......@@ -2,7 +2,8 @@
"permissions": {
"allow": [
"Bash(tree src/ -I node_modules)",
"Bash(npm run serve)"
"Bash(npm run serve)",
"Bash(tree src/)"
],
"deny": [],
"ask": []
......
<template>
<div id="app">
<router-view/>
<keep-alive>
<router-view/>
</keep-alive>
</div>
</template>
......
......@@ -20,7 +20,7 @@
/>
</div>
<el-select v-model="formData.personnelTypes" placeholder="人员类型" class="filter-select" multiple clearable>
<el-option label="装维师傅" value="1"></el-option>
<el-option label="工维人员" value="1"></el-option>
<el-option label="支撑人员" value="2"></el-option>
</el-select>
<template v-if="addressStore.cityArr.length>0">
......@@ -174,7 +174,7 @@
<el-col :span="12">
<el-form-item label="人员类型" prop="personnelType">
<el-select v-model="updatePersonStore.personnelType" :disabled="!!updatePersonStore.row.id" @change="personnelTypeChange" style="width: 100%;">
<el-option label="装维师傅" value="1"></el-option>
<el-option label="工维人员" value="1"></el-option>
<el-option label="支撑人员" value="2"></el-option>
</el-select>
</el-form-item>
......@@ -340,6 +340,7 @@ export default {
personnelName: '',
personnelCode: '',
personnelType: '',
relatedMarketingCode: '',
phone: '',
status: '',
......
......@@ -26,7 +26,10 @@ const routes = [
{
path: '/opportunities',
name: 'OpportunityManagement',
component: OpportunityManagement
component: OpportunityManagement,
meta: {
keepAlive: true
}
},
{
path: '/opportunitiesDetail',
......
......@@ -123,7 +123,7 @@
</el-header>
<!-- 页面内容 -->
<el-main class="dashboard-main">
<el-main class="dashboard-main" id="mainContain">
<router-view />
</el-main>
</el-container>
......
......@@ -36,6 +36,7 @@
v-model="addressStore.city"
placeholder="选择地市"
@change="cityChange"
:disabled="getData.city!=''"
clearable>
<el-option
v-for="item in addressStore.cityArr"
......@@ -49,7 +50,7 @@
<el-select
v-model="addressStore.county"
placeholder="选择区县"
@change="countyChange"
:disabled="getData.county!=''"
clearable>
<el-option
v-for="item in addressStore.countyArr"
......@@ -121,6 +122,10 @@ export default {
county: '',
countyArr: [],
},
getData:{
city: '',
county: ''
},
formData:{
gridName: '',
gridCode: '',
......@@ -134,6 +139,9 @@ export default {
}
},
created(){
let pa = JSON.parse(localStorage.getItem('accountInfo'))
this.getData.city = pa.cityCode||''
this.getData.county = pa.countyCode||''
this.queryArea()
this.handleQuery()
......@@ -146,9 +154,24 @@ export default {
}).then(res=>{
if(res.code == 200){
this.addressStore.cityArr = res.data
this.setAddressShow()
}
})
},
setAddressShow(){
let ad = this.addressStore
let gd = this.getData
if(gd.city){
ad.city = gd.city
this.cityChange(ad.city)
if(gd.county){
ad.county = gd.county
}
}
},
cityChange(value){
let ad = this.addressStore
ad.city = value
......
......@@ -362,7 +362,7 @@
v-model="audioBusiStore.reason"
type="textarea"
:rows="4"
placeholder="请输入审核不通过的理由"
placeholder="请输入理由"
></el-input>
</el-form-item>
</el-form>
......@@ -646,7 +646,7 @@ export default {
let ad = this.audioBusiStore
if(!ad.reason){
this.$message.error('请输入不通过理由')
this.$message.error('请输入理由')
return
}
......@@ -672,6 +672,7 @@ export default {
},
goBack() {
// 使用浏览器返回,这样可以触发列表页的 beforeRouteLeave 钩子
this.$router.go(-1)
},
getStatusType(status) {
......
......@@ -408,12 +408,12 @@
</el-radio-group>
</el-form-item>
<el-form-item v-if="auditForm.result == '0'" label="不通过理由" required>
<el-form-item label="理由" required>
<el-input
v-model="auditForm.reason"
type="textarea"
:rows="4"
placeholder="请输入审核不通过的理由"
placeholder="请输入理由"
></el-input>
</el-form-item>
</el-form>
......@@ -523,6 +523,10 @@ export default {
// 分页
currentPage: 1,
pageSize: 20,
// 滚动位置相关
savedScrollPosition: 0,
currentScrollPosition: 0,
scrollTimer: null,
}
},
created(){
......@@ -532,12 +536,123 @@ export default {
this.getData.grid = pa.gridCode||''
this.queryArea()
this.queryBusi()
this.queryStatistics()
this.queryStatus()
this.queryAllBusiLabel()
},
mounted() {
// 延迟注册滚动事件监听器,确保DOM已完全加载
this.$nextTick(() => {
setTimeout(() => {
document.querySelector('#mainContain').addEventListener('scroll', this.handleScroll, { passive: true })
console.log('滚动事件监听器已注册')
}, 100)
})
},
// keep-alive 激活时的生命周期钩子
activated() {
// 重新注册滚动事件监听器
window.addEventListener('scroll', this.handleScroll, { passive: true })
console.log('组件被激活,重新注册滚动监听')
},
// 组件失活时移除监听器
deactivated() {
window.removeEventListener('scroll', this.handleScroll)
console.log('组件失活,移除滚动监听')
},
// 组件销毁时移除监听器
beforeDestroy() {
if (this.scrollTimer) {
clearTimeout(this.scrollTimer)
}
window.removeEventListener('scroll', this.handleScroll)
console.log('组件销毁,清理资源')
},
// 添加页面生命周期钩子
beforeRouteLeave(to, from, next) {
// 保存当前状态到 localStorage
this.saveState()
next()
},
methods: {
// 保存页面状态
saveState() {
const state = {
formData: this.formData,
addressStore: this.addressStore,
pageStore: this.pageStore,
scrollPosition: this.currentScrollPosition
}
localStorage.setItem('opportunityManagementState', JSON.stringify(state))
},
// 恢复页面状态
restoreState() {
const savedState = localStorage.getItem('opportunityManagementState')
if (savedState) {
try {
const state = JSON.parse(savedState)
// 恢复筛选条件
if (state.formData) {
this.formData = { ...this.formData, ...state.formData }
}
// 恢复地址选择
if (state.addressStore) {
this.addressStore = { ...this.addressStore, ...state.addressStore }
}
// 恢复分页
if (state.pageStore) {
this.pageStore = { ...this.pageStore, ...state.pageStore }
}
// 恢复滚动位置
if (state.scrollPosition !== undefined) {
this.savedScrollPosition = state.scrollPosition
}
// 清除保存的状态,避免过期数据
localStorage.removeItem('opportunityManagementState')
} catch (error) {
console.error('恢复状态失败:', error)
}
}else{
this.setAddressShow()
}
this.queryBusi()
},
// 滚动事件处理函数
handleScroll() {
// 使用节流优化性能
if (this.scrollTimer) {
clearTimeout(this.scrollTimer)
}
this.scrollTimer = setTimeout(() => {
this.currentScrollPosition = document.querySelector('#mainContain').scrollTop
console.log('当前滚动位置:', this.currentScrollPosition)
}, 100)
},
// 恢复滚动位置
restoreScrollPosition() {
if (this.savedScrollPosition > 0) {
// 使用多种方式确保兼容性
document.querySelector('#mainContain').scrollTop = this.savedScrollPosition
console.log('恢复滚动位置到:', this.savedScrollPosition)
// 重置保存的滚动位置
this.savedScrollPosition = 0
}
},
ifCanAudio(row){
return row.status!=3 || (row.opportunityType==2&&this.getData.grid)
},
......@@ -603,7 +718,8 @@ export default {
if(res.code == 200){
this.addressStore.cityArr = res.data
this.setAddressShow()
this.restoreState()
}
})
},
......@@ -671,7 +787,6 @@ export default {
}
}
}
},
cityChange(value){
let ad = this.addressStore
......@@ -765,8 +880,12 @@ export default {
}).then(res=>{
if(res.code == 200){
this.tableData = res.data.records
this.pageStore.total = res.data.total
// 数据加载完成后恢复滚动位置
this.$nextTick(() => {
this.restoreScrollPosition()
})
}else{
this.$message.error(res.message)
}
......@@ -846,8 +965,14 @@ export default {
this.selectedTag = ''
this.dateRange = []
this.currentPage = 1
// 清除保存的状态
localStorage.removeItem('opportunityManagementState')
},
checkDetail(row){
// 保存当前状态
this.saveState()
localStorage.setItem('detailId',row.id)
this.$router.push(`/opportunitiesDetail`)
......@@ -871,8 +996,8 @@ export default {
return
}
if (this.auditForm.result == '0' && !this.auditForm.reason.trim()) {
this.$message.error('审核不通过时必须填写理由')
if (!this.auditForm.reason.trim()) {
this.$message.error('请输入理由')
return
}
......
......@@ -23,7 +23,10 @@
"Bash(lsof -ti:8080)",
"Bash(python3 -m http.server 8081)",
"Bash(open \"http://localhost:8081/zjbPhone/busiDetail.html\")",
"Bash(open \"http://localhost:8081/zjbPhone/addBusi.html\")"
"Bash(open \"http://localhost:8081/zjbPhone/addBusi.html\")",
"Bash(lsof -ti:8080,8081)",
"Bash(kill 33038 46309)",
"Bash(open \"http://localhost:8081/myBusi.html\")"
],
"deny": [],
"ask": []
......
......@@ -25,8 +25,8 @@
</div>
<!-- 用户地址 -->
<div class="section" v-if="isAlone">
<div class="section-card" data-node-id="6:249">
<div class="section">
<div class="section-card" data-node-id="6:249" v-if="isAlone">
<h2 class="section-title" data-node-id="6:253">用户地址</h2>
<div class="addressLi">
<div class="name">所在地区</div>
......@@ -40,6 +40,12 @@
<input type="text" placeholder="门牌号、楼栋号" v-model="detailAddress">
</div>
</div>
<div class="section-card" v-if="haZjData.address">
<div class="addressLi" style="align-items: flex-start;">
<div class="name">用户地址</div>
<div style="font-size: .28rem;">{{haZjData.address}}</div>
</div>
</div>
</div>
<!-- 商机类型 -->
......@@ -211,6 +217,6 @@
<script src="js/vue.min.js"></script>
<script src="js/util.js"></script>
<script src="js/addressData.js"></script>
<script src="js/addBusi.js?0911"></script>
<script src="js/addBusi.js?0910001"></script>
</body>
</html>
\ No newline at end of file
......@@ -54,7 +54,7 @@
</div>
</div>
<!-- 营销人员 -->
<div class="info-row" data-node-id="294:2298" v-else>
<div class="info-row" data-node-id="294:2298" v-else-if="businessDetail.marketingStaffPhone">
<span class="info-label" data-node-id="294:2299">营销人员</span>
<div class="phone-container" data-node-id="294:2300">
<span class="info-value" data-node-id="294:2301">{{ businessDetail.marketingStaffPhone }}</span>
......@@ -228,7 +228,7 @@
<div class="cancel" @click="cdStore.isShow=false">取消</div>
<div class="submit" @click="cdSubmit">确认成单</div>
</div>
<div class="botTs">提交后将进入审核流程,审核通过前可以撤回</div>
<div class="botTs">提交后将进入审核流程</div>
</div>
</div>
......@@ -282,12 +282,20 @@
</div>
</div>
</div>
<!-- 全页面加载遮罩 -->
<div class="global-loading" v-if="gjStore.isLoading">
<div class="loading-overlay">
<div class="loading-spinner"></div>
<div class="loading-text">提交中...</div>
</div>
</div>
</div>
<!-- 引入Vue.js -->
<script src="js/vue.min.js"></script>
<script src="js/axios.min.js"></script>
<script src="js/util.js"></script>
<script src="js/busiDetail.js?000"></script>
<script src="js/busiDetail.js?099911100"></script>
</body>
</html>
\ No newline at end of file
......@@ -133,6 +133,7 @@ body {
color: #333;
font-size: .28rem;
width: 1.5rem;
flex-shrink: 0;
}
.addressLi .selectCity{
display: flex;
......
......@@ -161,6 +161,63 @@ body {
.alertCon .alertButt div.submit{
color: #fff;
background: #0068EE;
transition: all 0.3s ease;
}
.alertCon .alertButt div.submit.loading {
background: #ccc;
cursor: not-allowed;
opacity: 0.7;
}
.alertCon .alertButt div.submit.loading:hover {
background: #ccc;
}
/* 全页面加载遮罩 */
.global-loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
}
.loading-overlay {
background: rgba(255, 255, 255, 0.95);
border-radius: 12px;
padding: 40px 60px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #0068EE;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 16px;
}
.loading-text {
font-size: 16px;
color: #333;
font-weight: 500;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.alertCon .botTs{
color: #666;
......@@ -528,7 +585,7 @@ body {
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
background: rgba(0, 0, 0, 0.7);
z-index: 99999;
display: flex;
align-items: center;
......
......@@ -256,14 +256,59 @@ new Vue({
*/
initData() {
this.haZjData = {
accNbr: utils.getUrlParam('phone'),
sysId: utils.getUrlParam('sysId'),
accNbr: utils.getUrlParam('accNbr'),
orderId: utils.getUrlParam('orderId'),
campaignId: utils.getUrlParam('campaignId'),
areaType: utils.getUrlParam('areaType'),
areaCode: utils.getUrlParam('areaCode'),
address: ''
}
this.getAddress()
this.contactPhone = this.haZjData.accNbr
},
getAddress(){
this.httpRequest({
url: '/zhijian/ha/getOrderInfo',
data: {...this.haZjData,...{
realAddress: '无所谓',
latitude: '123.123',
longitude: '123.2123',
cmcc: false
}}
}).then(res=>{
if(res.code == '200'){
this.haZjData.address = res.data.addressName||''
}
})
},
httpRequest:function(param){
let origin = window.origin
if(origin.includes('localhost')>0 || origin=='null' || origin.includes('file:')>0 || window.origin.includes('testznzl')){
origin = 'https://testznzl.lgyzpt.com'
}else{
origin = "https://hazj.lgyzpt.com"
}
return new Promise(function(resolve, reject){
axios ({
method: 'post',
url:origin + param.url,
timeout: param.time||15000,
data:param.data,
headers: {
'Content-Type': 'application/json'
}
}).then((res) => {
resolve(res.data)
}).catch(res => {
reject(res)
})
})
},
/**
* 手机号脱敏处理
*/
......
......@@ -121,6 +121,9 @@ new Vue({
// return
// }
// 设置加载状态
d.isLoading = true
const fd = new FormData();
fd.append('followContent',d.des)
fd.append('opportunityId',this.detailId)
......@@ -128,19 +131,27 @@ new Vue({
fd.append('images',item.file)
})
// 调用API提交
const result = await utils.httpRequest({
url: '/opportunity/follow',
data: fd
})
try {
// 调用API提交
const result = await utils.httpRequest({
url: '/opportunity/follow',
data: fd
})
if (result.code == 200) {
utils.toast('跟进提交成功!');
this.gjStore.isShow = false
this.queryDetail()
this.queryFollow()
} else {
utils.toast(result.message || '提交失败,请重试');
if (result.code == 200) {
utils.toast('跟进提交成功!');
this.gjStore.isShow = false
this.queryDetail()
this.queryFollow()
} else {
utils.toast(result.message || '提交失败,请重试');
}
} catch (error) {
console.error('提交跟进失败:', error);
utils.toast('网络错误,请重试');
} finally {
// 无论成功或失败,都取消加载状态
d.isLoading = false
}
},
completeBusi(){
......
......@@ -18,7 +18,8 @@ new Vue({
{ id: '4', name: '已成单', selected: false, nodeId: '355:540' },
{ id: '5', name: '已关闭', selected: false, nodeId: '355:543' }
],
businessList: []
businessList: [],
scrollTop: 0
},
computed: {
......@@ -61,6 +62,11 @@ new Vue({
}).then(res=>{
if(res.code == 200){
this.detail = res.data
this.$nextTick(() => {
this.updateActiveIndicator(this.activeTab);
document.querySelector('#listDiv').scrollTop = this.scrollTop||0
});
}
})
},
......@@ -109,6 +115,8 @@ new Vue({
// 查看商机详情
viewBusinessDetail(business) {
console.log('查看商机详情:', business);
// 保存当前页面状态
this.savePageState();
// 实际项目中这里应该跳转到详情页面
window.location.href = `busiDetail.html?id=${business.id}`;
},
......@@ -147,9 +155,50 @@ new Vue({
return 'completed'
}
},
// 保存页面状态
savePageState() {
const state = {
searchKeyword: this.searchKeyword,
activeTab: this.activeTab,
tagId: this.tagId,
scrollTop: document.querySelector('#listDiv').scrollTop,
timestamp: Date.now()
};
localStorage.setItem('myBusiPageState', JSON.stringify(state));
},
// 恢复页面状态
restorePageState() {
const savedState = localStorage.getItem('myBusiPageState');
if (savedState) {
try {
const state = JSON.parse(savedState);
// 检查状态是否在30分钟内保存的(避免过期状态)
const isRecent = (Date.now() - state.timestamp) < 30 * 60 * 1000;
if (isRecent) {
this.searchKeyword = state.searchKeyword || '';
this.activeTab = state.activeTab || 'all';
this.tagId = state.tagId || 'all';
this.scrollTop = state.scrollTop
}
} catch (e) {
console.error('恢复页面状态失败:', e);
}
this.clearPageState()
}
},
// 清除页面状态
clearPageState() {
localStorage.removeItem('myBusiPageState');
},
loginOut(){
localStorage.removeItem('userInfo')
localStorage.removeItem('tokenInfo')
this.clearPageState()
location.replace('login.html?platform='+localStorage.getItem('platform'))
}
......@@ -170,10 +219,8 @@ new Vue({
mounted() {
this.isWorker = localStorage.getItem('platform')=='gw'
// 延迟更新指示器位置,确保DOM已渲染
this.$nextTick(() => {
this.updateActiveIndicator(this.activeTab);
});
// 恢复页面状态
this.restorePageState();
this.queryBusiList()
},
......
......@@ -72,6 +72,6 @@
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/util.js"></script>
<script src="js/login.js?1233"></script>
<script src="js/login.js?123333"></script>
</body>
</html>
\ No newline at end of file
......@@ -70,7 +70,7 @@
</div>
<!-- 商机列表 -->
<div class="business-list">
<div class="business-list" id="listDiv">
<div
v-for="(business, index) in detail.records"
:key="business.id"
......@@ -168,6 +168,6 @@
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/util.js"></script>
<script src="js/myBusi.js"></script>
<script src="js/myBusi.js?123123"></script>
</body>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!