Commit fc86c70c by 李宁

1

1 parent da7b0e06
Showing 43 changed files with 766 additions and 394 deletions
import request from '../../request' import request from '../../request'
/** /**
* * 查询账号列表
*/ */
export function queryAllMissionRecord() { export function queryAccountList(data) {
return request({ return request({
url: 'hallserver/companyJob/queryAllCompanyJob', url: '/compass/api/system/account/page',
data: {} data,
})
}
/**
* 查询角色列表
*/
export function queryRoleList(data) {
return request({
url: '/compass/api/common/enums/account-roles',
method: 'GET'
})
}
/**
* 删除账号
*/
export function deleteRole(data) {
return request({
url: '/compass/api/system/account/delete',
data,
})
}
/**
* 添加/更新账号
*/
export function addAndUpdateRole(data) {
return request({
url: '/compass/api/system/account/create' + (data.id?'/update':''),
data,
}) })
} }
\ No newline at end of file \ No newline at end of file
...@@ -11,6 +11,76 @@ export function queryAllBusi(data) { ...@@ -11,6 +11,76 @@ export function queryAllBusi(data) {
} }
/** /**
* 全部商机-商机审核
*/
export function audioBusi(data) {
return request({
url: '/compass/api/opportunity/audit',
data,
})
}
/**
* 全部商机-商机详情
*/
export function queryBusiDetail(data) {
return request({
url: '/compass/api/opportunity/detail',
data,
})
}
/**
* 全部商机-商机跟进记录查询
*/
export function queryBusiFollowList(data) {
return request({
url: '/compass/api/opportunity/follow/page',
data,
})
}
/**
* 全部商机-关闭商机
*/
export function closeBusi(data) {
return request({
url: '/compass/api/opportunity/close',
data,
})
}
/**
* 全部商机-标记成单
*/
export function dealBusi(data) {
return request({
url: '/compass/api/opportunity/deal',
data,
})
}
/**
* 全部商机-分配商机
*/
export function reassignBusi(data) {
return request({
url: '/compass/api/opportunity/reassign',
data,
})
}
/**
* 全部商机-记录管理员备注
*/
export function updateRemark(data) {
return request({
url: '/compass/api/opportunity/admin-remark',
data,
})
}
/**
* 全部商机-数据统计 * 全部商机-数据统计
*/ */
export function queryAllBusiStatistics(data) { export function queryAllBusiStatistics(data) {
...@@ -21,11 +91,81 @@ export function queryAllBusiStatistics(data) { ...@@ -21,11 +91,81 @@ export function queryAllBusiStatistics(data) {
} }
/** /**
* 全部商机-查询商机标签列表 * 全部商机-查询所有商机标签列表
*/ */
export function queryBusiLabel(data) { export function queryBusiLabelList(data) {
return request({ return request({
url: '/compass/api/opportunity/tag/page', url: '/compass/api/opportunity/tag/page',
data, data,
}) })
} }
/**
* 商机标签的开始和关闭
*/
export function updateBusiLabelStatus(data) {
return request({
url: '/compass/api/opportunity/tag/status',
data,
})
}
/**
* 商机标签的删除
*/
export function deleteBusiLabel(data) {
return request({
url: '/compass/api/opportunity/tag/delete',
data,
})
}
/**
* 商机标签的创建和更新
*/
export function createAndUpdateTag(data) {
return request({
url: '/compass/api/opportunity/tag' + (data.id?'/update':''),
data,
})
}
/**
* 商机关闭原因列表查询
*/
export function queryBusiCloseReansonList(data) {
return request({
url: '/compass/api/opportunity/close-reason/page',
data,
})
}
/**
* 商机关闭原因添加和更新
*/
export function busiCloseReasonUpdate(data) {
return request({
url: '/compass/api/opportunity/close-reason'+(data.id?'/update':''),
data,
})
}
/**
* 商机关闭原因删除
*/
export function busiCloseReasonDel(data) {
return request({
url: '/compass/api/opportunity/close-reason/delete',
data,
})
}
/**
* 全部商机-新增商机
*/
export function createBusi(data) {
return request({
url: '/compass/api/opportunity/create',
data,
})
}
\ No newline at end of file \ No newline at end of file
import request from '../../request' import request from '../../request'
/** /**
* 查询区域列表 * 根据级别查询区域列表
* 1-省级,2-市级,3-区级,4-网格级 * 1-省级,2-市级,3-区级,4-网格级
*/ */
export function queryAllArea(data) { export function queryLevelAllArea(data) {
return request({ return request({
url: '/compass/api/common/areas/level?areaLevel='+data.areaLevel+'&parentAreaCode='+data.parentAreaCode, url: '/compass/api/common/areas/level?areaLevel='+data.areaLevel+'&parentAreaCode='+data.parentAreaCode,
method: 'GET' method: 'GET'
......
import request from '../../request' import request from '../../request'
/** /**
* 资金管理-发票管理-开票订单查询 * 网格列表查询
* @returns {AxiosPromise} * @returns {AxiosPromise}
*/ */
export function queryTicketOrderList() { export function queryAllGridList(data) {
return request({ return request({
url: 'hallserver/v1/invoiceApply/queryCompanyOrder', url: '/compass/api/grid/list',
data: {} data,
})
}
/**
* 获取该账号下可选的网格列表
*/
export function queryGridList(data) {
return request({
url: '/compass/api/grid/options',
data,
}) })
} }
\ No newline at end of file \ No newline at end of file
import request from '../../request' import request from '../../request'
/**
* 查询人员列表
*/
export function queryAllPerson(data) {
return request({
url: '/compass/api/personnel/list',
data,
})
}
/**
* 添加人员
*/
export function addNewPerson(data) {
return request({
url: '/compass/api/personnel/create',
data,
})
}
/** /**
* * 删除人员
*/ */
export function companyInfoQuery(companyId) { export function deletePerson(data) {
return request({ return request({
url: 'hallserver/hallCompanyInfo/getCompanyInfo', url: '/compass/api/personnel/delete',
data: { data,
'companyId': companyId
}
}) })
} }
/**
* 批量导入工维人员
*/
export function importGwPerson(data) {
return request({
url: '/compass/api/personnel/import-maintenance-preview',
data,
})
}
/**
* 批量导入营销人员
*/
export function importYxPerson(data) {
return request({
url: '/compass/api/marketing/import-preview',
data,
})
}
...@@ -5,7 +5,7 @@ import request from './request' ...@@ -5,7 +5,7 @@ import request from './request'
*/ */
export function logout() { export function logout() {
return request({ return request({
url: 'hallserver/admin/logout', url: '/compass/api/auth/logout',
data: {} data: {}
}) })
} }
...@@ -23,24 +23,36 @@ export function login(data) { ...@@ -23,24 +23,36 @@ export function login(data) {
} }
/** /**
* 获取登录验证码 * 手机账号登录
*/
export function pohoneLogin(data) {
return request({
url: '/compass/api/auth/phone-login',
data,
})
}
/**
* 获取图形验证码
* @param loginName * @param loginName
* @param password * @param password
*/ */
export function loginCode(data) { export function getImgCode(data) {
return request({ return request({
url: 'hallserver/admin/loginCode', url: '/compass/api/auth/getCaptCha',
method: 'GET',
data, data,
}) })
} }
/** /**
* 获取路由权限 * 获取短信验证码
* @returns {AxiosPromise} * @param loginName
* @param password
*/ */
export function getMenus() { export function getTelCode(data) {
return request({ return request({
url: 'hallserver/admin/function', url: '/compass/api/auth/send-sms',
data: {} data,
}) })
} }
...@@ -51,7 +51,7 @@ let catchFun = function (msg) { ...@@ -51,7 +51,7 @@ let catchFun = function (msg) {
service.interceptors.response.use( service.interceptors.response.use(
(response) => { (response) => {
console.log(response); console.log(response);
if (response.status === 200) { if (response.status == 200) {
if (response.data.code == "401") { if (response.data.code == "401") {
//登陆失效,重新登陆 //登陆失效,重新登陆
catchFun("账户状态异常"); catchFun("账户状态异常");
...@@ -100,9 +100,9 @@ service.interceptors.response.use( ...@@ -100,9 +100,9 @@ service.interceptors.response.use(
}; };
} }
} }
} else if (response.status === 302) { } else if (response.status == 302) {
catchFun("登陆失效,请重新登陆"); catchFun("登陆失效,请重新登陆");
} else if (response.status === 401 || response.status == 403) { } else if (response.status == 401 || response.status == 403) {
catchFun("账户状态异常"); catchFun("账户状态异常");
} else { } else {
if (sessionStorage.notFirstIn) { if (sessionStorage.notFirstIn) {
......
...@@ -212,9 +212,9 @@ export default { ...@@ -212,9 +212,9 @@ export default {
* @returns * @returns
*/ */
hideIdNumber: function(idCard) { hideIdNumber: function(idCard) {
if (idCard.length === 18) { if (idCard.length == 18) {
return idCard.substr(0, 6) + '********' + idCard.substr(-4, 4) return idCard.substr(0, 6) + '********' + idCard.substr(-4, 4)
} else if (idCard.length === 15) { } else if (idCard.length == 15) {
return idCard.substr(0, 6) + '******' + idCard.substr(-3, 3) return idCard.substr(0, 6) + '******' + idCard.substr(-3, 3)
} else { } else {
return idCard return idCard
......
...@@ -2,21 +2,21 @@ ...@@ -2,21 +2,21 @@
<div class="close-reason-management"> <div class="close-reason-management">
<div class="toolbar"> <div class="toolbar">
<p class="description">管理商机关闭时可选择的原因</p> <p class="description">管理商机关闭时可选择的原因</p>
<el-button @click="isAddDialogOpen = true" type="primary" size="small"> <el-button @click="addReason" type="primary" size="small">
<i class="el-icon-plus"></i> <i class="el-icon-plus"></i>
添加原因 添加原因
</el-button> </el-button>
</div> </div>
<div class="reason-table"> <div class="reason-table">
<el-table :data="reasons" style="width: 100%"> <el-table :data="reasonsList" style="width: 100%" border>
<el-table-column prop="reason" label="关闭原因" width="300"></el-table-column> <el-table-column prop="closeReason" label="关闭原因" width="300"></el-table-column>
<el-table-column prop="category" label="分类" width="200"> <el-table-column prop="category" label="分类" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag size="mini">{{ scope.row.category }}</el-tag> <el-tag size="mini">{{ scope.row.category }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="150"> <el-table-column label="操作" min-width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
type="text" type="text"
...@@ -37,6 +37,20 @@ ...@@ -37,6 +37,20 @@
</el-table> </el-table>
</div> </div>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageStore.currentPage"
:page-sizes="[20, 50, 100]"
:page-size="pageStore.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageStore.total"
>
</el-pagination>
</div>
<!-- 添加/编辑原因对话框 --> <!-- 添加/编辑原因对话框 -->
<el-dialog <el-dialog
:title="editingReason ? '编辑关闭原因' : '添加关闭原因'" :title="editingReason ? '编辑关闭原因' : '添加关闭原因'"
...@@ -44,9 +58,9 @@ ...@@ -44,9 +58,9 @@
width="500px" width="500px"
> >
<el-form :model="reasonForm" :rules="reasonRules" ref="reasonForm" label-width="100px"> <el-form :model="reasonForm" :rules="reasonRules" ref="reasonForm" label-width="100px">
<el-form-item label="关闭原因" prop="reason"> <el-form-item label="关闭原因" prop="closeReason">
<el-input <el-input
v-model="reasonForm.reason" v-model="reasonForm.closeReason"
placeholder="请输入关闭原因" placeholder="请输入关闭原因"
></el-input> ></el-input>
</el-form-item> </el-form-item>
...@@ -68,21 +82,18 @@ ...@@ -68,21 +82,18 @@
</template> </template>
<script> <script>
// 模拟关闭原因数据
const mockCloseReasons = [
{ id: '1', reason: '客户价格不接受', category: '价格因素' },
{ id: '2', reason: '客户暂无需求', category: '需求因素' },
{ id: '3', reason: '竞品已安装', category: '竞争因素' },
{ id: '4', reason: '客户联系不上', category: '联系因素' },
{ id: '5', reason: '技术不支持', category: '技术因素' },
{ id: '6', reason: '其他原因', category: '其他' }
]
export default { export default {
name: 'CloseReasonManagement', name: 'CloseReasonManagement',
data() { data() {
return { return {
reasons: mockCloseReasons, reasonsList: [],
pageStore:{
currentPage: 1,
pageSize: 20,
total: 0
},
isAddDialogOpen: false, isAddDialogOpen: false,
editingReason: null, editingReason: null,
reasonForm: { reasonForm: {
...@@ -90,7 +101,7 @@ export default { ...@@ -90,7 +101,7 @@ export default {
category: '' category: ''
}, },
reasonRules: { reasonRules: {
reason: [ closeReason: [
{ required: true, message: '请输入关闭原因', trigger: 'blur' } { required: true, message: '请输入关闭原因', trigger: 'blur' }
], ],
category: [ category: [
...@@ -99,7 +110,46 @@ export default { ...@@ -99,7 +110,46 @@ export default {
} }
} }
}, },
created(){
this.handleFilter()
},
methods: { methods: {
handleSizeChange(size) {
this.pageStore.pageSize = size
this.handleFilter()
},
handleCurrentChange(page) {
this.pageStore.currentPage = page
this.queryCloseList()
},
handleFilter(){
this.pageStore.currentPage = 1
this.queryCloseList()
},
queryCloseList(){
this.apiReq.queryBusiCloseReansonList({
pageNum: this.pageStore.currentPage,
pageSize: this.pageStore.pageSize
}).then(res=>{
if(res.code == 200){
this.reasonsList = res.data.records
this.pageStore.total = res.data.total
}
})
},
addReason(){
this.editingReason = null
this.reasonForm = {
category: '',
closeReason: ''
}
this.isAddDialogOpen = true
},
editReason(reason) { editReason(reason) {
this.editingReason = reason this.editingReason = reason
this.reasonForm = { ...reason } this.reasonForm = { ...reason }
...@@ -111,44 +161,46 @@ export default { ...@@ -111,44 +161,46 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.reasons = this.reasons.filter(r => r.id !== id) this.apiReq.busiCloseReasonDel({
this.$message.success('关闭原因删除成功') id,
}).catch(() => { }).then(res=>{
// 用户取消删除 if(res.code == 200){
let __this = this
this.$alert('删除成功', '温馨提示', {
confirmButtonText: '确定',
callback: () => {
__this.handleFilter()
}
});
}else{
this.$message.error(res.message)
}
})
}) })
}, },
submitReasonForm() { submitReasonForm() {
this.$refs.reasonForm.validate((valid) => { this.$refs.reasonForm.validate((valid) => {
if (valid) { if (valid) {
if (this.editingReason) { this.apiReq.busiCloseReasonUpdate({
// 更新原因信息 id: this.editingReason?this.editingReason.id: '',
const index = this.reasons.findIndex(r => r.id === this.editingReason.id) category: this.reasonForm.category,
if (index !== -1) { closeReason: this.reasonForm.closeReason
this.$set(this.reasons, index, { ...this.editingReason, ...this.reasonForm }) }).then(res=>{
this.$message.success('关闭原因更新成功') if(res.code == '200'){
} let __this = this
} else { this.$alert(this.editingReason?'修改成功':'添加成功', '温馨提示', {
// 添加新原因 confirmButtonText: '确定',
const newReason = { callback: () => {
...this.reasonForm, __this.handleFilter()
id: `REASON${Date.now()}` __this.isAddDialogOpen = false
} }
this.reasons.push(newReason) });
this.$message.success('关闭原因添加成功') }else{
} this.$message.error(res.message)
// 重置表单和状态
this.resetReasonForm()
this.isAddDialogOpen = false
this.editingReason = null
} }
}) })
},
resetReasonForm() {
this.reasonForm = {
reason: '',
category: ''
} }
})
} }
} }
} }
......
...@@ -91,7 +91,7 @@ export default new Vuex.Store({ ...@@ -91,7 +91,7 @@ export default new Vuex.Store({
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 模拟登录验证 // 模拟登录验证
const userData = mockUsers[username] const userData = mockUsers[username]
if (userData && userData.password === password) { if (userData && userData.password == password) {
commit('SET_USER', userData.user) commit('SET_USER', userData.user)
localStorage.setItem('user', JSON.stringify(userData.user)) localStorage.setItem('user', JSON.stringify(userData.user))
resolve(true) resolve(true)
......
...@@ -35,10 +35,9 @@ ...@@ -35,10 +35,9 @@
<template v-for="item in menuItems"> <template v-for="item in menuItems">
<!-- 有子菜单的项 --> <!-- 有子菜单的项 -->
<el-submenu <el-submenu
v-if="item.subItems && hasPermission(item.permissions)" v-if="item.subItems"
:key="item.title" :key="item.title"
:index="item.title" :index="item.title" >
>
<template slot="title"> <template slot="title">
<i :class="item.icon"></i> <i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span> <span slot="title">{{ item.title }}</span>
...@@ -46,8 +45,8 @@ ...@@ -46,8 +45,8 @@
<el-menu-item <el-menu-item
v-for="subItem in item.subItems" v-for="subItem in item.subItems"
:key="subItem.url" :key="subItem.url"
:index="subItem.url" v-if="hasPermissionChild(subItem.url)"
> :index="subItem.url">
<i :class="subItem.icon"></i> <i :class="subItem.icon"></i>
<span slot="title">{{ subItem.title }}</span> <span slot="title">{{ subItem.title }}</span>
</el-menu-item> </el-menu-item>
...@@ -55,7 +54,7 @@ ...@@ -55,7 +54,7 @@
<!-- 无子菜单的项 --> <!-- 无子菜单的项 -->
<el-menu-item <el-menu-item
v-else-if="item.url && hasPermission(item.permissions)" v-else-if="item.url && hasPermission(item.url)"
:key="item.title" :key="item.title"
:index="item.url" :index="item.url"
> >
...@@ -75,17 +74,17 @@ ...@@ -75,17 +74,17 @@
</el-avatar> </el-avatar>
<transition name="fade"> <transition name="fade">
<div v-if="!isCollapse" class="user-details"> <div v-if="!isCollapse" class="user-details">
<span class="user-name">{{ currentUser.name }}</span> <span class="user-name">{{ acc.accountName }}</span>
<span class="user-region">{{ currentUser.region }}</span> <span class="user-region">{{ acc.areaName }}</span>
</div> </div>
</transition> </transition>
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="profile"> <!-- <el-dropdown-item command="profile">
<i class="el-icon-user"></i> <i class="el-icon-user"></i>
个人信息 个人信息
</el-dropdown-item> </el-dropdown-item> -->
<el-dropdown-item divided command="logout"> <el-dropdown-item command="logout">
<i class="el-icon-switch-button"></i> <i class="el-icon-switch-button"></i>
退出登录 退出登录
</el-dropdown-item> </el-dropdown-item>
...@@ -120,7 +119,7 @@ ...@@ -120,7 +119,7 @@
<div class="header-right"> <div class="header-right">
<span v-if="isDemoMode" class="demo-badge">演示模式</span> <span v-if="isDemoMode" class="demo-badge">演示模式</span>
<span class="current-region">当前区域: {{ currentUser.region }}</span> <span class="current-region">当前区域: {{ acc.areaName }}</span>
</div> </div>
</el-header> </el-header>
...@@ -201,22 +200,19 @@ export default { ...@@ -201,22 +200,19 @@ export default {
return { return {
isCollapse: false, isCollapse: false,
menuItems: menuItems, menuItems: menuItems,
breadcrumbMap: breadcrumbMap breadcrumbMap: breadcrumbMap,
acc: JSON.parse(localStorage.getItem('accountInfo'))
} }
}, },
computed: { computed: {
...mapGetters(['user', 'isAuthenticated']),
currentUser() {
return this.user || {}
},
userInitial() { userInitial() {
return this.currentUser.name ? this.currentUser.name.charAt(0) : '' return this.acc.accountName ? this.acc.accountName.charAt(0) : ''
}, },
userAvatar() { userAvatar() {
return '' return ''
}, },
isDemoMode() { isDemoMode() {
return sessionStorage.getItem('demoMode') === 'true' return sessionStorage.getItem('demoMode') == 'true'
}, },
activeMenu() { activeMenu() {
const { meta, path } = this.$route const { meta, path } = this.$route
...@@ -245,18 +241,43 @@ export default { ...@@ -245,18 +241,43 @@ export default {
toggleCollapse() { toggleCollapse() {
this.isCollapse = !this.isCollapse this.isCollapse = !this.isCollapse
}, },
hasPermission(permissions) { hasPermission(url) {
if (!this.user || !this.user.permissions) return false if(url=='/grid-query' && this.acc.gridCode){
return permissions.some(permission => this.user.permissions.includes(permission)) return false
}
return true
},
hasPermissionChild(url){
if(url == '/system/opportunity-config'){
if(this.acc.cityCode && !this.acc.countyCode){
return true
}
return false
}
return true
}, },
async handleUserCommand(command) { async handleUserCommand(command) {
if (command === 'logout') { this.apiReq.logout().then(res=>{
await this.logout() if(res.code == '200'){
this.$message.success('退出登录成功') localStorage.removeItem('accountInfo')
localStorage.removeItem('tokenInfo')
this.$router.push('/login') this.$router.push('/login')
} else if (command === 'profile') { }else{
this.$message.info('个人信息功能开发中') this.$message.error(res.message)
} }
})
// if (command == 'logout') {
// await this.logout()
// this.$message.success('退出登录成功')
// this.$router.push('/login')
// } else if (command == 'profile') {
// this.$message.info('个人信息功能开发中')
// }
} }
}, },
created() { created() {
......
...@@ -5,28 +5,15 @@ ...@@ -5,28 +5,15 @@
</div> </div>
<el-card class="filter-card"> <el-card class="filter-card">
<div class="filter-header">
<h3 class="filter-title">查询条件</h3>
<div class="filter-actions">
<el-button size="small" @click="handleQuery">
<i class="el-icon-search"></i>
查询
</el-button>
<el-button size="small" @click="resetQuery" type="default">
<i class="el-icon-refresh-left"></i>
重置
</el-button>
</div>
</div>
<div class="filter-content"> <div class="filter-content">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="3"> <el-col :span="3">
<div class="search-wrapper"> <div class="search-wrapper">
<el-input <el-input
v-model="selectedGridName" v-model="formData.gridName"
placeholder="请输入网格名称" placeholder="请输入网格名称"
style="padding-left: 0;" style="padding-left: 0;"
clearable
@keyup.enter.native="handleFilter" @keyup.enter.native="handleFilter"
/> />
</div> </div>
...@@ -35,9 +22,10 @@ ...@@ -35,9 +22,10 @@
<el-col :span="3"> <el-col :span="3">
<div class="search-wrapper"> <div class="search-wrapper">
<el-input <el-input
v-model="selectedGrid" v-model="formData.gridCode"
placeholder="请输入网格ID" placeholder="请输入网格ID"
style="padding-left: 0;" style="padding-left: 0;"
clearable
@keyup.enter.native="handleFilter" @keyup.enter.native="handleFilter"
/> />
</div> </div>
...@@ -48,13 +36,12 @@ ...@@ -48,13 +36,12 @@
v-model="addressStore.city" v-model="addressStore.city"
placeholder="选择地市" placeholder="选择地市"
@change="cityChange" @change="cityChange"
:disabled="getData.city!=''"
clearable> clearable>
<el-option <el-option
v-for="item in addressStore.cityArr" v-for="item in addressStore.cityArr"
:key="item.value" :key="item.areaCode"
:label="item.name" :label="item.areaName"
:value="item.value" :value="item.areaCode"
></el-option> ></el-option>
</el-select> </el-select>
</el-col> </el-col>
...@@ -63,16 +50,28 @@ ...@@ -63,16 +50,28 @@
v-model="addressStore.county" v-model="addressStore.county"
placeholder="选择区县" placeholder="选择区县"
@change="countyChange" @change="countyChange"
:disabled="getData.county!=''"
clearable> clearable>
<el-option <el-option
v-for="item in addressStore.countyArr" v-for="item in addressStore.countyArr"
:key="item.value" :key="item.areaCode"
:label="item.name" :label="item.areaName"
:value="item.value" :value="item.areaCode"
></el-option> ></el-option>
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="3">
<div class="filter-actions">
<el-button size="small" @click="handleQuery">
<i class="el-icon-search"></i>
查询
</el-button>
<el-button size="small" @click="resetQuery" type="default">
<i class="el-icon-refresh-left"></i>
重置
</el-button>
</div>
</el-col>
</el-row> </el-row>
</div> </div>
</el-card> </el-card>
...@@ -88,9 +87,9 @@ ...@@ -88,9 +87,9 @@
:data="tableData" :data="tableData"
border border
> >
<el-table-column prop="name" label="网格名称" width="220"></el-table-column> <el-table-column prop="gridName" label="网格名称" width="220"></el-table-column>
<el-table-column prop="id" label="网格ID" width="220"></el-table-column> <el-table-column prop="gridCode" label="网格ID" width="220"></el-table-column>
<el-table-column prop="region" label="所属区域" min-width="250"></el-table-column> <el-table-column prop="areaName" label="所属区域" min-width="250"></el-table-column>
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
...@@ -118,100 +117,103 @@ export default { ...@@ -118,100 +117,103 @@ export default {
return { return {
addressStore:{ addressStore:{
city: '', city: '',
cityName: '', cityArr: [],
cityArr: this.addressStoreData,
county: '', county: '',
countyName: '',
countyArr: [], countyArr: [],
}, },
getData:{ formData:{
city: '', gridName: '',
cityName: '', gridCode: '',
county: '',
countyName: ''
}, },
pageStore: {
selectedRegion: [],
selectedGrid: '',
selectedGridName: '',
tableData: [],
pageStore:{
currentPage: 1, currentPage: 1,
pageSize: 20, pageSize: 20,
total: 0 total: 0
} },
tableData: []
} }
}, },
created(){ created(){
this.queryArea()
this.handleQuery()
}, },
methods: { methods: {
setAddressShow(){ queryArea(){
let ad = this.addressStore this.apiReq.queryLevelAllArea({
let gd = this.getData areaLevel: 2,
parentAreaCode: '320000'
if(gd.city){ }).then(res=>{
ad.city = gd.city if(res.code == 200){
ad.cityArr.forEach(item=>{ this.addressStore.cityArr = res.data
if(item.value == ad.city){
ad.countyArr = item.children
}
})
if(gd.county){
ad.county = gd.county
ad.countyArr.forEach(item=>{
if(item.value == ad.county){
ad.gridArr = item.children
} }
}) })
if(ad.gridArr.length == 1){
gd.grid = 'moren'
}
if(gd.grid){
ad.grid = gd.grid
}
}
}
}, },
cityChange(value){ cityChange(value){
let ad = this.addressStore let ad = this.addressStore
ad.city = value ad.city = value
ad.county = '' ad.county = ''
ad.grid = ''
ad.cityArr.forEach(item=>{ this.apiReq.queryLevelAllArea({
if(item.value == ad.city){ areaLevel: 3,
ad.countyArr = item.children parentAreaCode: value
}).then(res=>{
if(res.code == 200){
ad.countyArr = res.data
} }
}) })
}, },
handleQuery() { handleQuery() {
this.currentPage = 1 this.pageStore.currentPage = 1
this.$message.success('查询成功')
this.queryGridData()
}, },
queryGridData(){
if(this.addressStore.city && !this.addressStore.county){
this.$message.error('请选择区县')
return
}
this.apiReq.queryAllGridList({
areaCode: this.addressStore.county,
pageSize: this.pageStore.pageSize,
pageNum: this.pageStore.currentPage,
...this.formData
}).then(res=>{
if(res.code == 200){
this.tableData = res.data.records
this.pageStore.total = res.data.total
}
})
},
resetQuery() { resetQuery() {
this.selectedRegion = [] this.formData.gridCode = ''
this.selectedGrid = '' this.formData.gridName = ''
this.selectedGridName = '' this.addressStore.city = ''
this.addressStore.county = ''
this.addressStore.countyArr = []
}, },
handleSizeChange(size) { handleSizeChange(size) {
this.pageSize = size this.pageStore.pageSize = size
this.currentPage = 1
this.handleQuery()
}, },
handleCurrentChange(page) { handleCurrentChange(page) {
this.currentPage = page this.pageStore.currentPage = page
}
this.queryGridData()
},
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.grid-query { .grid-query {
.el-button.el-button--small{
padding: 13px 12px;
}
.page-header { .page-header {
margin-bottom: 24px; margin-bottom: 24px;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
智能商机管理<br>助力业务增长 智能商机管理<br>助力业务增长
</h2> </h2>
<p class="login-desc"> <p class="login-desc">
装维师傅上门服务时发现商机,系统自动分配给营销人员跟进,实现业务闭环管理 装维师傅上门服务时发现商机,系统自动分配给支撑人员跟进,实现业务闭环管理
</p> </p>
</div> </div>
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
</div> </div>
<div class="login-feature-text"> <div class="login-feature-text">
<h3 class="login-feature-title">智能分配</h3> <h3 class="login-feature-title">智能分配</h3>
<p class="login-feature-desc">基于网格自动分配给合适的营销人员</p> <p class="login-feature-desc">基于网格自动分配给合适的支撑人员</p>
</div> </div>
</div> </div>
...@@ -75,23 +75,21 @@ ...@@ -75,23 +75,21 @@
<div class="login-tabs"> <div class="login-tabs">
<div <div
class="login-tab" class="login-tab"
:class="{ active: activeTab === 'account' }" :class="{ active: activeTab == 'account' }"
@click="activeTab = 'account'" @click="activeTab = 'account'">
>
账号密码登录 账号密码登录
</div> </div>
<div <div
class="login-tab" class="login-tab"
:class="{ active: activeTab === 'phone' }" :class="{ active: activeTab == 'phone' }"
@click="activeTab = 'phone'" @click="activeTab = 'phone'">
>
手机验证码登录 手机验证码登录
</div> </div>
</div> </div>
<!-- 账号密码登录表单 --> <!-- 账号密码登录表单 -->
<el-form <el-form
v-if="activeTab === 'account'" v-if="activeTab == 'account'"
:model="loginForm" :model="loginForm"
:rules="loginRules" :rules="loginRules"
ref="loginForm" ref="loginForm"
...@@ -143,7 +141,7 @@ ...@@ -143,7 +141,7 @@
<!-- 手机验证码登录表单 --> <!-- 手机验证码登录表单 -->
<el-form <el-form
v-if="activeTab === 'phone'" v-if="activeTab == 'phone'"
:model="phoneForm" :model="phoneForm"
:rules="phoneRules" :rules="phoneRules"
ref="phoneForm" ref="phoneForm"
...@@ -224,10 +222,6 @@ ...@@ -224,10 +222,6 @@
<p class="forgot-password-message"> <p class="forgot-password-message">
忘记密码请联系商机管理员重置密码 忘记密码请联系商机管理员重置密码
</p> </p>
<!-- <div class="forgot-password-tips">
<p><i class="el-icon-phone"></i> 联系电话:400-8888-8888</p>
<p><i class="el-icon-message"></i> 邮箱:admin@shangmensuixiao.com</p>
</div> -->
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button @click="isForgotPasswordDialogVisible = false">确定</el-button> <el-button @click="isForgotPasswordDialogVisible = false">确定</el-button>
...@@ -247,8 +241,8 @@ export default { ...@@ -247,8 +241,8 @@ export default {
return { return {
activeTab: 'account', // 当前激活的登录方式 activeTab: 'account', // 当前激活的登录方式
loginForm: { loginForm: {
username: '', username: 'ntadmin',
password: '' password: 'ntadmin'
}, },
phoneForm: { phoneForm: {
phone: '', phone: '',
...@@ -289,7 +283,7 @@ export default { ...@@ -289,7 +283,7 @@ export default {
computed: { computed: {
// 是否可以发送验证码 // 是否可以发送验证码
canSendCode() { canSendCode() {
return this.phoneForm.phone && this.phoneForm.captcha && this.phoneForm.captcha === this.captchaText return this.phoneForm.phone && this.phoneForm.captcha
} }
}, },
mounted() { mounted() {
...@@ -310,7 +304,6 @@ export default { ...@@ -310,7 +304,6 @@ export default {
try { try {
await this.$refs.loginForm.validate() await this.$refs.loginForm.validate()
this.apiReq.login({ this.apiReq.login({
username: ld.username, username: ld.username,
password: ld.password password: ld.password
...@@ -332,58 +325,24 @@ export default { ...@@ -332,58 +325,24 @@ export default {
}, },
// 刷新图形验证码 // 刷新图形验证码
refreshCaptcha() { refreshCaptcha() {
// 生成随机验证码(模拟) this.apiReq.getImgCode().then(res=>{
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' if(res.code == 200){
let code = '' this.captchaImage = 'data:image/png;base64,'+res.data.img
for (let i = 0; i < 4; i++) { this.captchaId = res.data.codeId
code += chars.charAt(Math.floor(Math.random() * chars.length)) }
} })
this.captchaText = code
// 创建canvas生成验证码图片
const canvas = document.createElement('canvas')
canvas.width = 100
canvas.height = 40
const ctx = canvas.getContext('2d')
// 背景色
ctx.fillStyle = '#f0f0f0'
ctx.fillRect(0, 0, 100, 40)
// 绘制验证码文字
ctx.font = '20px Arial'
ctx.fillStyle = '#333'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
for (let i = 0; i < code.length; i++) {
ctx.save()
ctx.translate(20 + i * 20, 20)
ctx.rotate((Math.random() - 0.5) * 0.3)
ctx.fillText(code[i], 0, 0)
ctx.restore()
}
// 添加干扰线
for (let i = 0; i < 4; i++) {
ctx.strokeStyle = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0.3)`
ctx.beginPath()
ctx.moveTo(Math.random() * 100, Math.random() * 40)
ctx.lineTo(Math.random() * 100, Math.random() * 40)
ctx.stroke()
}
this.captchaImage = canvas.toDataURL()
}, },
// 发送手机验证码 // 发送手机验证码
async sendPhoneCode() { async sendPhoneCode() {
if (this.codeCountdown > 0) return if (this.codeCountdown > 0) return
try { this.apiReq.getTelCode({
await this.$refs.phoneForm.validate(['phone', 'captcha']) phone: this.phoneForm.phone,
captchaCode: this.phoneForm.captcha,
// 模拟发送验证码 captchaId: this.captchaId
this.$message.success('验证码已发送到您的手机') }).then(res=>{
if(res.code == 200){
this.$message.success('验证码发送成功')
// 开始倒计时 // 开始倒计时
this.codeCountdown = 60 this.codeCountdown = 60
...@@ -394,42 +353,31 @@ export default { ...@@ -394,42 +353,31 @@ export default {
this.countdownTimer = null this.countdownTimer = null
} }
}, 1000) }, 1000)
}else{
} catch (error) { this.$message.error(res.message)
if (this.phoneForm.captcha !== this.captchaText) {
this.$message.error('图形验证码错误')
this.refreshCaptcha()
this.phoneForm.captcha = ''
}
} }
})
}, },
// 手机验证码登录 // 手机验证码登录
async handlePhoneLogin() { async handlePhoneLogin() {
try { try {
await this.$refs.phoneForm.validate() await this.$refs.phoneForm.validate()
this.phoneLoading = true
// 模拟手机号登录逻辑
// 这里可以添加手机号到用户名的映射逻辑
const phoneToUserMap = {
'13812345678': { username: 'grid001', password: '123456' },
'13887654321': { username: 'county001', password: '123456' },
'13765432109': { username: 'city001', password: '123456' },
'13654321098': { username: 'province001', password: '123456' }
}
const userInfo = phoneToUserMap[this.phoneForm.phone]
if (userInfo && this.phoneForm.phoneCode === '123456') {
await this.login({
username: userInfo.username,
password: userInfo.password
})
this.$message.success('登录成功') this.apiReq.pohoneLogin({
phone: this.phoneForm.phone,
personnelCode: this.phoneForm.phone,
smsCode: this.phoneForm.phoneCode,
rememberMe: true
}).then(res=>{
if(res.code == 200){
localStorage.setItem('accountInfo',JSON.stringify(res.data.account))
localStorage.setItem('tokenInfo',JSON.stringify(res.data.tokenInfo))
this.$router.push('/') this.$router.push('/')
} else { }else{
this.$message.error('手机号或验证码错误') this.$message.error(res.message)
} }
})
} catch (error) { } catch (error) {
console.error('Phone login error:', error) console.error('Phone login error:', error)
...@@ -659,7 +607,7 @@ export default { ...@@ -659,7 +607,7 @@ export default {
.captcha-image { .captcha-image {
flex-shrink: 0; flex-shrink: 0;
width: 100px; width: 100px;
height: 40px; height: 36px;
border: 1px solid #dcdfe6; border: 1px solid #dcdfe6;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
</div> </div>
<!-- 人员管理页面特殊处理:显示业务类型Tab --> <!-- 人员管理页面特殊处理:显示业务类型Tab -->
<div v-if="activeTab === 'personnel'" class="personnel-management"> <div v-if="activeTab == 'personnel'" class="personnel-management">
<el-tabs v-model="businessTab" @tab-click="handleBusinessTabClick"> <el-tabs v-model="businessTab" @tab-click="handleBusinessTabClick">
<el-tab-pane label="常规业务" name="regular"></el-tab-pane> <el-tab-pane label="常规业务" name="regular"></el-tab-pane>
<el-tab-pane label="政企业务" name="enterprise" v-if="hasEnterprisePermission"></el-tab-pane> <el-tab-pane label="政企业务" name="enterprise" v-if="hasEnterprisePermission"></el-tab-pane>
</el-tabs> </el-tabs>
<!-- 常规业务 --> <!-- 常规业务 -->
<div v-if="businessTab === 'regular'"> <div v-if="businessTab == 'regular'">
<el-card> <el-card>
<div class="card-content"> <div class="card-content">
<PersonnelManagement /> <PersonnelManagement />
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</div> </div>
<!-- 政企业务 --> <!-- 政企业务 -->
<div v-if="businessTab === 'enterprise' && hasEnterprisePermission"> <div v-if="businessTab == 'enterprise' && hasEnterprisePermission">
<el-card> <el-card>
<div class="card-content"> <div class="card-content">
<EnterprisePersonnelManagement /> <EnterprisePersonnelManagement />
...@@ -32,14 +32,14 @@ ...@@ -32,14 +32,14 @@
</div> </div>
<!-- 商机管理配置 --> <!-- 商机管理配置 -->
<div v-else-if="activeTab === 'tags'" class="opportunity-config"> <div v-else-if="activeTab == 'tags'" class="opportunity-config">
<el-tabs v-model="configTab" @tab-click="handleConfigTabClick"> <el-tabs v-model="configTab" @tab-click="handleConfigTabClick">
<el-tab-pane label="商机标签" name="tags"></el-tab-pane> <el-tab-pane label="商机标签" name="tags"></el-tab-pane>
<el-tab-pane label="商机关闭" name="reasons"></el-tab-pane> <el-tab-pane label="商机关闭" name="reasons"></el-tab-pane>
</el-tabs> </el-tabs>
<!-- 商机标签 --> <!-- 商机标签 -->
<div v-if="configTab === 'tags'"> <div v-if="configTab == 'tags'">
<el-card> <el-card>
<div class="card-content"> <div class="card-content">
<TagManagement /> <TagManagement />
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
</div> </div>
<!-- 商机关闭原因 --> <!-- 商机关闭原因 -->
<div v-if="configTab === 'reasons'"> <div v-if="configTab == 'reasons'">
<el-card> <el-card>
<div class="card-content"> <div class="card-content">
<CloseReasonManagement /> <CloseReasonManagement />
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
</div> </div>
<!-- 账号管理 --> <!-- 账号管理 -->
<div v-else-if="activeTab === 'accounts'"> <div v-else-if="activeTab == 'accounts'">
<el-card> <el-card>
<div class="card-content"> <div class="card-content">
<AccountManagement /> <AccountManagement />
...@@ -98,9 +98,10 @@ export default { ...@@ -98,9 +98,10 @@ export default {
} }
}, },
computed: { computed: {
...mapGetters(['user']),
hasEnterprisePermission() { hasEnterprisePermission() {
return this.user?.role === 'city_admin' || this.user?.role === 'province_admin' let accountInfo = JSON.parse(localStorage.getItem('accountInfo'))
return !accountInfo.countyCode && !accountInfo.gridCode
}, },
activeTabLabel() { activeTabLabel() {
const tabLabels = { const tabLabels = {
......
...@@ -5,12 +5,12 @@ module.exports = { ...@@ -5,12 +5,12 @@ module.exports = {
publicPath: './', publicPath: './',
outputDir: 'dist', outputDir: 'dist',
assetsDir: 'static', assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development', lintOnSave: process.env.NODE_ENV == 'development',
productionSourceMap: false, productionSourceMap: false,
devServer: { devServer: {
proxy: { proxy: {
'/compass': { '/compass': {
target: 'http://39.107.104.220:8899', target: 'https://testznzl.lgyzpt.com/',
//target: 'https://hall.51xinpai.cn', //target: 'https://hall.51xinpai.cn',
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
...@@ -27,7 +27,8 @@ module.exports = { ...@@ -27,7 +27,8 @@ module.exports = {
alias: { alias: {
'@': path.resolve(__dirname, 'src') '@': path.resolve(__dirname, 'src')
} }
} },
devtool: 'source-map'
}, },
chainWebpack: config => { chainWebpack: config => {
// 配置SVG图标 // 配置SVG图标
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
<audio ref="audioObj" playsinline></audio> <audio ref="audioObj" playsinline></audio>
<!-- <div class="topBut" v-if="isAlone">
<div class="left" @click="goZj">质检模拟</div>
<div class="right" @click="loginOut">退出</div>
</div> -->
<!-- 联系方式 --> <!-- 联系方式 -->
<div class="section" data-node-id="79:2566"> <div class="section" data-node-id="79:2566">
<div class="section-card" data-node-id="6:249"> <div class="section-card" data-node-id="6:249">
...@@ -20,7 +25,7 @@ ...@@ -20,7 +25,7 @@
<span class="contact-text" data-node-id="6:259">{{ contactPhone }}</span> <span class="contact-text" data-node-id="6:259">{{ contactPhone }}</span>
<button class="edit-button" data-node-id="6:263" @click="editContact">修改</button> <button class="edit-button" data-node-id="6:263" @click="editContact">修改</button>
</div> </div>
<input class="phoneInput" v-else type="text" placeholder="请输入手机号"> <input class="phoneInput" v-model="contactPhone" v-else type="text" placeholder="请输入手机号">
</div> </div>
</div> </div>
...@@ -37,7 +42,7 @@ ...@@ -37,7 +42,7 @@
</div> </div>
<div class="addressLi"> <div class="addressLi">
<div class="name">详细地址</div> <div class="name">详细地址</div>
<input type="text" placeholder="门牌号、楼栋号"> <input type="text" placeholder="门牌号、楼栋号" v-model="detailAddress">
</div> </div>
</div> </div>
</div> </div>
...@@ -51,10 +56,11 @@ ...@@ -51,10 +56,11 @@
v-for="type in businessTypes" v-for="type in businessTypes"
:key="type.id" :key="type.id"
:class="['tag-button', { active: type.selected }]" :class="['tag-button', { active: type.selected }]"
:style="{color: type.ifCho?'#33':'#CECECE'}"
:data-node-id="type.nodeId" :data-node-id="type.nodeId"
@click="selectBusinessType(type.id)" @click="selectBusinessType(type.id)"
> >
{{ type.name }} {{ type.tagName }}
</div> </div>
</div> </div>
</div> </div>
...@@ -67,7 +73,10 @@ ...@@ -67,7 +73,10 @@
<div class="cordList"> <div class="cordList">
<div class="cordLi" v-for="(item,index) in recordingUrlArr"> <div class="cordLi" v-for="(item,index) in recordingUrlArr">
<div class="left" @click="playAudio(index)"> <div class="left" @click="playAudio(index)">
<img class="pause" src="images/pause.png" alt="">
<img v-if="item.isPlay" class="pause" src="images/play.png" alt="">
<img v-else class="pause" src="images/pause.png" alt="">
<img class="voice" src="images/voice.png" alt=""> <img class="voice" src="images/voice.png" alt="">
<div class="time">{{item.time}}</div> <div class="time">{{item.time}}</div>
</div> </div>
...@@ -134,14 +143,20 @@ ...@@ -134,14 +143,20 @@
<div v-else class="submit-button" data-node-id="6:498" @click="submitBusiness"> <div v-else class="submit-button" data-node-id="6:498" @click="submitBusiness">
提交商机 提交商机
</div> </div>
<div class="loginOut" @click="loginOut">
<img src="images/loginout.png" alt="">
<div>退出</div>
</div>
<!-- 底部导航 --> <!-- 底部导航 -->
<div class="bottom-nav" v-if="isAlone"> <div class="bottom-nav" v-if="isAlone">
<div class="nav-item collect-business"> <div class="nav-item collect-business active">
<img class="nav-icon" src="images/collect-icon.svg" alt="收集商机"> <img class="nav-icon" src="images/collect-icon-active.png" alt="收集商机">
<span class="nav-text" data-node-id="355:528">收集商机</span> <span class="nav-text" data-node-id="355:528">收集商机</span>
</div> </div>
<div class="nav-item all-business active"> <div class="nav-item all-business" @click="navigateToList">
<img class="nav-icon" src="images/business-icon.svg" alt="收集商机"> <img class="nav-icon" src="images/business-icon.png" alt="收集商机">
<span class="nav-text" data-node-id="355:532">全部商机</span> <span class="nav-text" data-node-id="355:532">全部商机</span>
</div> </div>
</div> </div>
...@@ -197,9 +212,11 @@ ...@@ -197,9 +212,11 @@
</div> </div>
<!-- 引入Vue.js --> <!-- 引入Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/lamejs@1.2.1/lame.min.js"></script>
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script> <script src="js/vue.min.js"></script>
<script src="js/util.js"></script> <script src="js/util.js"></script>
<script src="js/addressData.js"></script> <script src="js/addressData.js"></script>
<script src="js/addBusi.js"></script> <script src="js/addBusi.js?123211"></script>
</body> </body>
</html> </html>
\ No newline at end of file \ No newline at end of file
...@@ -27,52 +27,38 @@ body { ...@@ -27,52 +27,38 @@ body {
padding-bottom: 1.2rem; /* 为底部按钮预留空间 */ padding-bottom: 1.2rem; /* 为底部按钮预留空间 */
} }
/* 顶部标题栏 */ .loginOut{
.header {
background-color: white;
border-bottom: 1px solid #f1f1f1;
position: sticky;
top: 0;
z-index: 100;
height: 0.88rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 0 0.32rem; border-radius: .08rem;
background: #EBEDF0;
width: 1.8rem;
height: .6rem;
color: #666;
font-size: .28rem;
margin: .64rem auto;
}
.loginOut img{
width: .32rem;
height: .32rem;
margin-right: .08rem;
} }
.back-button { .topBut{
position: absolute;
left: 0.32rem;
top: 50%;
transform: translateY(-50%);
width: 0.96rem;
height: 0.96rem;
background: none;
border: none;
cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-end;
} margin-bottom: .2rem;
.back-icon {
width: 0.2rem;
height: 0.36rem;
}
.back-icon img {
width: 100%;
height: 100%;
object-fit: contain;
} }
.topBut div{
.header-title { border-radius: 4px;
font-family: 'Source Han Sans CN', sans-serif; background: #0068EE;
font-weight: bold; color: #fff;
font-size: 0.36rem; font-size: .26rem;
line-height: 0.36rem; font-weight: 500;
color: #333333; padding: .2rem .4rem;
margin-right: .1rem;
} }
/* 通用卡片样式 */ /* 通用卡片样式 */
...@@ -190,11 +176,6 @@ body { ...@@ -190,11 +176,6 @@ body {
user-select: none; user-select: none;
} }
.tag-button:hover {
border-color: #0068ee;
transform: translateY(-1px);
}
.tag-button.active { .tag-button.active {
background-color: #0068ee; background-color: #0068ee;
border-color: #0068ee; border-color: #0068ee;
......
...@@ -90,6 +90,7 @@ body { ...@@ -90,6 +90,7 @@ body {
width: 100%; width: 100%;
border: none; border: none;
display: block; display: block;
font-size: .29rem;
} }
.alertCon .ali textarea::placeholder{ .alertCon .ali textarea::placeholder{
color: #999; color: #999;
...@@ -106,6 +107,7 @@ body { ...@@ -106,6 +107,7 @@ body {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
position: relative;
} }
.alertCon .ali .imgList .addImg img.add{ .alertCon .ali .imgList .addImg img.add{
width: .56rem; width: .56rem;
......
...@@ -53,6 +53,29 @@ div{ ...@@ -53,6 +53,29 @@ div{
font-size: .32rem; font-size: .32rem;
} }
.tabList{
display: flex;
margin: .48rem;
color: #666;
font-size: .32rem;
background: #F1F4F9;
border-radius: .16rem;
height: .96rem;
align-items: center;
padding: .08rem;
}
.tabList div{
width: 33.33%;
text-align: center;
}
.tabList div.cho{
border-radius: .12rem;
background: #FFF;
color: #0068EE;
height: .8rem;
line-height: .8rem;
}
.logo { .logo {
width: .8rem; width: .8rem;
height: .8rem; height: .8rem;
......
...@@ -117,6 +117,7 @@ body { ...@@ -117,6 +117,7 @@ body {
.filter-tags { .filter-tags {
display: flex; display: flex;
padding: 0.32rem; padding: 0.32rem;
padding-bottom: 0;
} }
.filter-tag { .filter-tag {
...@@ -133,14 +134,33 @@ body { ...@@ -133,14 +134,33 @@ body {
color: #0068EE; color: #0068EE;
} }
.loginOut{
display: flex;
align-items: center;
justify-content: center;
border-radius: .08rem;
background: #EBEDF0;
width: 1.8rem;
height: .6rem;
color: #666;
font-size: .28rem;
margin: .64rem auto;
}
.loginOut img{
width: .32rem;
height: .32rem;
margin-right: .08rem;
}
/* 商机列表 */ /* 商机列表 */
.business-list { .business-list {
padding: 0 0.32rem; padding: 0 0.32rem;
height: calc(100vh - 3.8rem); height: calc(100vh - 2.8rem);
overflow: auto; overflow: auto;
margin-top: .32rem;
} }
.worker-con .business-list{ .worker-con .business-list{
height: calc(100vh - 5.2rem); height: calc(100vh - 3.8rem);
} }
.business-card { .business-card {
......
...@@ -3,16 +3,33 @@ const util = new window.publicMethod() ; ...@@ -3,16 +3,33 @@ const util = new window.publicMethod() ;
new Vue({ new Vue({
el: '#app', el: '#app',
data: { data: {
platform: 'yx',
loginForm: { loginForm: {
employeeId: '', employeeId: '23123456',
phoneNumber: '', phoneNumber: '13718590607',
verifyCode: '' verifyCode: '123456'
}, },
countdown: 0, countdown: 0,
countdownTimer: null, countdownTimer: null,
clickFlag: false clickFlag: false
}, },
methods: { methods: {
tabChang(type){
this.platform = type
localStorage.setItem('platform',type)
if(type == 'gw'){
this.loginForm.employeeId = '1235456'
this.loginForm.phoneNumber = '13718596969'
}else if(type == 'yx'){
this.loginForm.employeeId = '23123456'
this.loginForm.phoneNumber = '13718590607'
}else{
this.loginForm.employeeId = '15862709858'
this.loginForm.phoneNumber = '15862709858'
}
},
getVerifyCode() { getVerifyCode() {
let pa = this.loginForm let pa = this.loginForm
...@@ -37,10 +54,9 @@ new Vue({ ...@@ -37,10 +54,9 @@ new Vue({
this.clickFlag = true this.clickFlag = true
util.httpRequest({ util.httpRequest({
url: '/mobile/sendSms', url: '/send-sms',
middleUrl: '/zhijian-trial/api',
data: { data: {
campaignId: pa.employeeId, personnelCode: pa.employeeId,
phone: pa.phoneNumber, phone: pa.phoneNumber,
}, },
}).then(res=>{ }).then(res=>{
...@@ -59,7 +75,7 @@ new Vue({ ...@@ -59,7 +75,7 @@ new Vue({
}, 1000); }, 1000);
}else{ }else{
this.clickFlag = false this.clickFlag = false
util.toast(res.msg || '获取失败') util.toast(res.message || '获取失败')
} }
}).catch(()=>{ }).catch(()=>{
this.clickFlag = false this.clickFlag = false
...@@ -98,18 +114,24 @@ new Vue({ ...@@ -98,18 +114,24 @@ new Vue({
} }
util.httpRequest({ util.httpRequest({
url: '/mobile/login', url: '/phone-login',
middleUrl: '/zhijian-trial/api',
data: { data: {
campaignId: pa.employeeId, personnelCode: pa.employeeId,
phone: pa.phoneNumber, phone: pa.phoneNumber,
smsCode: pa.verifyCode smsCode: pa.verifyCode
}, },
}).then(res=>{ }).then(res=>{
if(res.code == 200){ if(res.code == 200){
localStorage.setItem('userInfo',JSON.stringify(res.data.personnel))
localStorage.setItem('tokenInfo',JSON.stringify(res.data.tokenInfo))
if(this.platform == 'gw'){
window.location.href = 'addBusi.html'
}else{
window.location.href = 'myBusi.html'
}
}else{ }else{
util.toast(res.msg || '登录失败') util.toast(res.message || '登录失败')
} }
}) })
} }
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
} }
}, },
methods: { methods: {
goAdd(){
location.href = 'addBusi.html?source=zhijian'
},
goBack(){ goBack(){
history.go(-1) history.go(-1)
} }
......
...@@ -72,8 +72,23 @@ ...@@ -72,8 +72,23 @@
* *
*/ */
httpRequest:function(param){ httpRequest:function(param){
let middle = param.middleUrl || '/zhijian-trial/ha' let middle = '/compass/api/'
let pa = localStorage.getItem('appLoginInfo')
if(param.middle){
middle += param.middle
}else{
if(localStorage.getItem('platform') == 'gw'){
middle += 'personnel'
}
if(localStorage.getItem('platform') == 'yx'){
middle += 'marketing'
}
if(localStorage.getItem('platform') == 'gov'){
middle += 'gov-marketing'
}
}
let pa = localStorage.getItem('tokenInfo')
if(pa){ if(pa){
pa = JSON.parse(pa) pa = JSON.parse(pa)
}else{ }else{
...@@ -88,7 +103,7 @@ ...@@ -88,7 +103,7 @@
data:param.data, data:param.data,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-access-token': pa.tokenValue 'Authorization': pa.token||''
} }
}).then((res) => { }).then((res) => {
resolve(res.data) resolve(res.data)
...@@ -97,6 +112,31 @@ ...@@ -97,6 +112,31 @@
}) })
}) })
}, },
detailTime: function(num,flag) {
if (num == null) {
return '';
} else {
num = Number(num);
let d = new Date(num);
let year = d.getFullYear();
let month = d.getMonth() + 1;
let date = d.getDate();
let hour = d.getHours();
let minute = d.getMinutes();
let second = d.getSeconds();
month < 10 ? month = '0' + month : month;
date < 10 ? date = '0' + date : date;
hour < 10 ? hour = '0' + hour : hour;
minute < 10 ? minute = '0' + minute : minute;
second < 10 ? second = '0' + second : second;
if(flag){
return year + "-" + month + "-" + date + " " + hour + ":" + minute
}
return year + "-" + month + "-" + date + " " + hour + ":" + minute + ":" + second;
}
},
} }
window.publicMethod = utils window.publicMethod = utils
})() })()
\ No newline at end of file \ No newline at end of file
...@@ -20,6 +20,12 @@ ...@@ -20,6 +20,12 @@
</div> </div>
</div> </div>
<div class="tabList">
<div :class="{cho: platform=='yx'}" @click="tabChang('yx')">C端支撑</div>
<div :class="{cho: platform=='gov'}" @click="tabChang('gov')">政企支撑</div>
<div :class="{cho: platform=='gw'}" @click="tabChang('gw')">装维师傅</div>
</div>
<div class="login-form"> <div class="login-form">
<div class="input-group"> <div class="input-group">
<img src="images/1.png" alt="工号图标" class="input-icon"> <img src="images/1.png" alt="工号图标" class="input-icon">
...@@ -58,7 +64,7 @@ ...@@ -58,7 +64,7 @@
<div @click="login" class="login-btn">登录</div> <div @click="login" class="login-btn">登录</div>
<div class="loginTs">登录即表示您同意<span>《用户协议》</span><span>《隐私协议》</span></div> <!-- <div class="loginTs">登录即表示您同意<span>《用户协议》</span>和<span>《隐私协议》</span></div> -->
</div> </div>
</div> </div>
</div> </div>
...@@ -66,6 +72,6 @@ ...@@ -66,6 +72,6 @@
<script src="js/axios.min.js"></script> <script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script> <script src="js/vue.min.js"></script>
<script src="js/util.js"></script> <script src="js/util.js"></script>
<script src="js/login.js?444"></script> <script src="js/login.js?441234"></script>
</body> </body>
</html> </html>
\ No newline at end of file \ No newline at end of file
...@@ -18,25 +18,25 @@ ...@@ -18,25 +18,25 @@
:class="{ active: activeTab === 'all' }" :class="{ active: activeTab === 'all' }"
@click="switchTab('all')" @click="switchTab('all')"
data-node-id="355:516" data-node-id="355:516"
>全部商机{{ totalCount }}</div> >全部商机{{ detail.totalCount }}</div>
<div <div
class="tab-text" class="tab-text"
:class="{ active: activeTab === 'pending' }" :class="{ active: activeTab === '1' }"
@click="switchTab('pending')" @click="switchTab('1')"
data-node-id="355:517" data-node-id="355:517"
>待跟进{{ pendingCount }}</div> >待跟进{{ detail.pendingCount }}</div>
<div <div
class="tab-text" class="tab-text"
:class="{ active: activeTab === 'follow-up' }" :class="{ active: activeTab === '2' }"
@click="switchTab('follow-up')" @click="switchTab('2')"
data-node-id="355:518" data-node-id="355:518"
>跟进中{{ followUpCount }}</div> >跟进中{{ detail.followingCount }}</div>
<div <div
class="tab-text" class="tab-text"
:class="{ active: activeTab === 'completed' }" :class="{ active: activeTab === '3,4,5' }"
@click="switchTab('completed')" @click="switchTab('3,4,5')"
data-node-id="355:519" data-node-id="355:519"
>已完结{{ completedCount }}</div> >已完结{{ detail.finishedCount }}</div>
</div> </div>
</div> </div>
...@@ -57,11 +57,11 @@ ...@@ -57,11 +57,11 @@
</div> </div>
<!-- 筛选标签 --> <!-- 筛选标签 -->
<div class="filter-tags" data-node-id="355:533"> <div class="filter-tags" data-node-id="355:533" v-if="activeTab == '3,4,5'">
<div <div
v-for="tag in filterTags" v-for="tag in filterTags"
:key="tag.id" :key="tag.id"
:class="['filter-tag', { active: tag.selected }]" :class="['filter-tag', { active: tag.id==tagId }]"
:data-node-id="tag.nodeId" :data-node-id="tag.nodeId"
@click="selectFilterTag(tag.id)" @click="selectFilterTag(tag.id)"
> >
...@@ -72,19 +72,18 @@ ...@@ -72,19 +72,18 @@
<!-- 商机列表 --> <!-- 商机列表 -->
<div class="business-list"> <div class="business-list">
<div <div
v-for="(business, index) in filteredBusinessList" v-for="(business, index) in detail.records"
:key="business.id" :key="business.id"
class="business-card" class="business-card"
:data-node-id="business.nodeId"
@click="viewBusinessDetail(business)"> @click="viewBusinessDetail(business)">
<div class="card-content"> <div class="card-content">
<!-- 顶部编号和状态 --> <!-- 顶部编号和状态 -->
<div class="card-header" data-node-id="355:432"> <div class="card-header" data-node-id="355:432">
<div class="business-number" data-node-id="355:433"> <div class="business-number" data-node-id="355:433">
<div class="number-text" data-node-id="355:434">#{{ business.orderNumber }}</div> <div class="number-text" data-node-id="355:434">{{ business.opportunityCode }}</div>
</div> </div>
<div :class="['status-badge', business.statusClass]" data-node-id="355:435"> <div :class="['status-badge', getStatusCalss(business.status)]" data-node-id="355:435">
<span>{{ business.statusText }}</span> <span>{{ business.statusName }}</span>
</div> </div>
</div> </div>
...@@ -94,7 +93,7 @@ ...@@ -94,7 +93,7 @@
<div class="detail-row" data-node-id="355:437"> <div class="detail-row" data-node-id="355:437">
<img class="detail-icon" src="images/location-icon.svg" alt="地址图标"> <img class="detail-icon" src="images/location-icon.svg" alt="地址图标">
<div class="detail-text" data-node-id="355:441"> <div class="detail-text" data-node-id="355:441">
<span>{{ business.address }}</span> <span>{{ addressShow(business.customerAddress) }}</span>
</div> </div>
</div> </div>
...@@ -102,7 +101,7 @@ ...@@ -102,7 +101,7 @@
<div class="detail-row contact-row" data-node-id="355:443"> <div class="detail-row contact-row" data-node-id="355:443">
<img class="detail-icon" src="images/user-icon.svg" alt="地址图标"> <img class="detail-icon" src="images/user-icon.svg" alt="地址图标">
<div class="detail-text" data-node-id="355:446"> <div class="detail-text" data-node-id="355:446">
<span>{{ business.contactPhone }}</span> <span>{{ business.customerPhone }}</span>
</div> </div>
</div> </div>
...@@ -111,33 +110,37 @@ ...@@ -111,33 +110,37 @@
<img class="detail-icon" src="images/tag-icon.svg" alt="地址图标"> <img class="detail-icon" src="images/tag-icon.svg" alt="地址图标">
<div class="business-tags" data-node-id="355:452"> <div class="business-tags" data-node-id="355:452">
<div <div
v-for="tag in business.tags" v-for="tag in business.tagNames"
:key="tag.id"
class="business-tag" class="business-tag"
:data-node-id="tag.nodeId"
> >
{{ tag.name }} {{ tag }}
</div> </div>
</div> </div>
</div> </div>
<!-- 处理人信息 --> <!-- 处理人信息 -->
<div class="processor-info" data-name="Container" data-node-id="355:457"> <div class="processor-info" data-name="Container" data-node-id="355:457">
<span>处理人:{{ business.processor }}</span> <span>处理人:{{ business.marketingStaffName }}</span>
</div> </div>
<!-- 时间信息 --> <!-- 时间信息 -->
<div class="time-info" data-name="Container" data-node-id="355:459"> <div class="time-info" data-name="Container" data-node-id="355:459">
<div class="submit-time" data-name="Container" data-node-id="355:460"> <div class="submit-time" data-name="Container" data-node-id="355:460">
<span>提交:{{ business.submitTime }}</span> <span>提交:{{ switchTime(business.createTime) }}</span>
</div> </div>
<div class="update-time"> <div class="update-time">
<span>更新:{{ business.updateTime }}</span> <span>更新:{{ switchTime(business.latestFollowTime)}}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="detail.records.length <= 0" style="text-align: center;font-size: .4rem;padding-top: 2rem;">暂无订单</div>
<div class="loginOut" @click="loginOut">
<img src="images/loginout.png" alt="">
<div>退出</div>
</div>
</div> </div>
<!-- 底部导航 --> <!-- 底部导航 -->
...@@ -154,7 +157,7 @@ ...@@ -154,7 +157,7 @@
class="nav-item all-business active" class="nav-item all-business active"
data-name="全部商机" data-name="全部商机"
data-node-id="355:529"> data-node-id="355:529">
<img class="nav-icon" src="images/business-icon.svg" alt="收集商机"> <img class="nav-icon" src="images/business-icon-active.svg" alt="收集商机">
<span class="nav-text" data-node-id="355:532">全部商机</span> <span class="nav-text" data-node-id="355:532">全部商机</span>
</div> </div>
</div> </div>
...@@ -162,6 +165,7 @@ ...@@ -162,6 +165,7 @@
</div> </div>
<!-- 引入Vue.js --> <!-- 引入Vue.js -->
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script> <script src="js/vue.min.js"></script>
<script src="js/util.js"></script> <script src="js/util.js"></script>
<script src="js/myBusi.js"></script> <script src="js/myBusi.js"></script>
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="botButt" >发现商机</div> <div class="botButt" @click="goAdd">发现商机</div>
<div class="botButt noBusi" @click="goBack">暂无商机</div> <div class="botButt noBusi" @click="goBack">暂无商机</div>
</div> </div>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!