Commit e3a7f5bd by chenxianqi

update code

parent 825ca73b
......@@ -601,6 +601,13 @@ func (c *PublicController) CreateWorkOrder() {
c.JSON(configs.ResponseFail, err.Message, nil)
}
}
// type is exist?
workOrderTypeRepository := services.GetWorkOrderTypeRepositoryInstance()
if _, err := workOrderTypeRepository.GetWorkOrderType(workOrder.CID); err != nil {
c.JSON(configs.ResponseFail, "创建失败,工单类型不存在~", err.Error())
}
workOrder.CreateAt = time.Now().Unix()
workOrder.UID = user.ID
workOrderRepository := services.GetWorkOrderRepositoryInstance()
......@@ -711,6 +718,20 @@ func (c *PublicController) GetWorkOrders() {
}
// GetWorkOrderTypes user get word order type all
func (c *PublicController) GetWorkOrderTypes() {
// get user
user := c.GetUserInfo()
if user == nil {
c.JSON(configs.ResponseFail, "查询失败!", nil)
}
workOrderTypeRepository := services.GetWorkOrderTypeRepositoryInstance()
workOrderTypes := workOrderTypeRepository.GetWorkOrderTypes()
c.JSON(configs.ResponseSucess, "查询成功!", workOrderTypes)
}
// GetWorkOrderComments get word order comments
func (c *PublicController) GetWorkOrderComments() {
......
......@@ -3,7 +3,7 @@
// @Description kefu server APIs.
// @Contact 361554012@qq.com
package routers
package routers
import (
"kefu_server/controllers"
......@@ -51,6 +51,7 @@ func init() {
beego.NSRouter("/workorder/create", &controllers.PublicController{}, "post:CreateWorkOrder"),
beego.NSRouter("/workorder/reply", &controllers.PublicController{}, "post:ReplyWorkOrder"),
beego.NSRouter("/workorders", &controllers.PublicController{}, "get:GetWorkOrders"),
beego.NSRouter("/workorder/types", &controllers.PublicController{}, "get:GetWorkOrderTypes"),
beego.NSRouter("/workorder/comments/:wid", &controllers.PublicController{}, "get:GetWorkOrderComments"),
beego.NSRouter("/workorder/:wid", &controllers.PublicController{}, "get:GetWorkOrder"),
beego.NSRouter("/workorder/:wid", &controllers.PublicController{}, "delete:DeleteWorkOrder"),
......
......@@ -18,6 +18,10 @@ Helps.install = function (Vue, options) {
}
return moment(parseInt(unix + '000')).format(format)
}
// 格式化日期(相对日期)
Vue.prototype.$formatDate = function (unix, format = "YYYY-MM-DD HH:mm:ss") {
return moment(parseInt(unix + '000')).format(format)
}
Vue.prototype.$robotNickname = function (id) {
var nickname
var robots = this.$store.getters.robots
......
......@@ -36,20 +36,22 @@ MimcPlugin.install = function (Vue, options) {
localStorage.setItem("user", JSON.stringify(response.data.data.user))
localStorage.setItem("Token", response.data.data.user.token)
console.log("MIMC初始化成功")
this.getRobot()
if(callback) callback(response.data.data.user)
this.getRobot(()=>{
if(callback) callback(response.data.data.user)
})
})
.catch((error)=>{
if(callback) callback(null)
console.log(error.response)
console.log(error)
})
},
// 获取机器人
getRobot(){
getRobot(callback){
axios.get('/public/robot/'+this.platform)
.then(response => {
this.robot = response.data.data
})
if(callback)callback()
})
.catch((error)=>{
console.log("mimc初始化失败,请刷新重试", error)
})
......
<template>
<div>
<router-view />
<div>
<div
class="mini-im-loading"
:class="{'pc-mini-im-loading': !isMobile}"
v-if="isShowPageLoading"
>
<mt-spinner type="triple-bounce" color="#26a2ff"></mt-spinner>
</div>
<router-view />
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "app",
data() {
return {
};
return {};
},
computed: {
...mapGetters([
"isShowPageLoading",
"userAccount",
"isArtificial",
"isMobile",
"artificialAccount",
"robotAccount",
"platform",
"userLocal",
"uid",
"uid",
])
},
mounted() {
this.handelUrl()
created() {
this.getLocal();
setTimeout(() => {
this.handelUrl()
this.runApp()
}, 500);
// 判断是否被踢出对话
this.onCheckIsOutSession();
},
methods: {
runApp() {
const user = this.$mimcInstance.getLocalCacheUser();
if (
user &&
this.userAccount != null &&
this.userAccount != user.id &&
this.userAccount != 0
) {
localStorage.clear();
}
this.$mimcInstance.init(
{
type: 0, // 默认0
address: this.userLocal,
uid: this.uid || 0, // 预留字段扩展自己平台业务
platform: this.platform, // 渠道(平台)
account_id: this.userAccount || 0 // 用户ID
// 初始化完成这里返回一个user
},
user => {
// 上报活动时间
this.upLastActivity();
// 获取公司信息
this.$store.dispatch("onGetCompanyInfo");
// 获取上传配置信息
this.$store.dispatch("onGetUploadSecret");
// 获取工单类型
this.$store.dispatch("onGetWorkorderTypes");
// 获取工单列表
this.$store.dispatch("onGetWorkorders");
// 重试
if (!user) {
setTimeout(() => this.runApp(), 1000);
return;
}
// user
this.$store.commit("updateState", {
userAccount: user.id,
userInfo: user
});
// robot
var robot = this.$mimcInstance.robot;
localStorage.setItem("robot_" + robot.id, JSON.stringify(robot));
this.$store.commit("updateState", {
robotAccount: robot.id,
robotInfo: robot
});
// 登录mimc
this.$mimcInstance.login();
// 发送一条握手消息给机器人
var sentHandshake =() =>{
if (this.$mimcInstance.user == null || !this.$mimcInstance.user.isLogin()) {
setTimeout(() => sentHandshake(), 200);
return
}
if (!this.artificialAccount) {
console.log("握手消息");
this.$mimcInstance.sendMessage(
"handshake",
this.robotAccount,
""
);
}
}
sentHandshake()
}
);
},
// Handelurl
handelUrl() {
// url query 介绍
......@@ -30,8 +133,15 @@ export default {
// u == userAccount 会话用户账号
// uid == userId 业务平台的ID
// c = 1 清除本地缓存
var isShowHeader,isMobile,userAccount,uid,isArtificial,artificialAccount,robotAccount,platform
var query = this.queryToJson(location.search);
var isShowHeader,
isMobile,
userAccount,
uid,
isArtificial,
artificialAccount,
robotAccount,
platform;
var query = this.$route.query;
if (query && query.c) localStorage.clear();
// 获取本地缓存
var urlQuery = this.queryToJson(localStorage.getItem("urlQuery"));
......@@ -48,19 +158,28 @@ export default {
if (query.p) platform = parseInt(query.p);
if (query.uid) uid = parseInt(query.uid);
if (query.r == "0") {
isArtificial = true
artificialAccount = parseInt(query.a)
isArtificial = true;
artificialAccount = parseInt(query.a);
} else {
robotAccount = parseInt(query.a)
robotAccount = parseInt(query.a);
}
}
var isArtificialString = localStorage.getItem("isArtificial");
var artificialAccountString = localStorage.getItem("artificialAccount");
if (isArtificialString == "true") {
isArtificial = true
artificialAccount = parseInt(artificialAccountString)
isArtificial = true;
artificialAccount = parseInt(artificialAccountString);
}
this.$store.commit("updateState", {isShowHeader,isMobile,userAccount,uid,isArtificial,artificialAccount,robotAccount, platform})
this.$store.commit("updateState", {
isShowHeader,
isMobile,
userAccount,
uid,
isArtificial,
artificialAccount,
robotAccount,
platform
});
},
// query 转json
queryToJson(str) {
......@@ -74,7 +193,33 @@ export default {
}
return mapData;
},
// 根据IP获取用户地理位置
getLocal() {
this.$store.dispatch("onGetLocal", this.$store.state.AmapAPPKey);
},
// 上报最后活动时间
upLastActivity() {
this.onCheckIsOutSession();
const user = this.$mimcInstance.getLocalCacheUser();
if (user) this.$store.dispatch("onUpdateLastActivity");
if (this.isArtificial) {
localStorage.setItem("artificialTime", Date.now());
}
setTimeout(() => this.upLastActivity(), 1000 * 60);
},
// 判断是否被踢出对话
onCheckIsOutSession() {
var artificialTime = localStorage.getItem("artificialTime");
if (artificialTime) {
artificialTime = parseInt(artificialTime);
if (Date.now() > artificialTime + 60 * 1000 * 10) {
this.$store.commit("updateState", {
isArtificial: false,
artificialAccount: null
});
}
}
},
}
};
</script>
......@@ -114,5 +259,26 @@ body {
font-size: 23px !important;
}
.mini-im-loading {
display: flex;
width: 100%;
position: fixed;
height: 100vh;
top: 0;
left: 0;
z-index: 9;
right: 0;
background-color: #fff !important;
margin: auto;
align-items: center;
justify-content: center;
&.pc-mini-im-loading {
width: 360px !important;
height: 360px !important;
top: -48px;
bottom: 0;
margin: auto !important;
}
}
</style>

391 Bytes | W: | H:

1.1 KB | W: | H:

ui/kefu_client/src/assets/workorder.png
ui/kefu_client/src/assets/workorder.png
ui/kefu_client/src/assets/workorder.png
ui/kefu_client/src/assets/workorder.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -25,7 +25,7 @@ const router = new Router({
component: () => import('./views/workorder_create.vue')
},
{
path: '/workorder/detail',
path: '/workorder/detail/:id',
name: 'workorder_detail',
component: () => import('./views/workorder_detail.vue')
},
......
......@@ -14,13 +14,15 @@ export default {
.then(response => {
let newMessage = [];
let messages = response.data.data.list || [];
if (messages.length < pageSize) {
if (messages.length < pageSize || messages.length == 0) {
context.commit('updateState', { isLoadMorEnd: true })
}
if (params.oldMsg.length == 0 && messages.length > 0) {
newMessage = response.data.data.list
} else if (messages.length > 0) {
newMessage = messages.concat(params.oldMsg);
}else{
newMessage = params.oldMsg
}
context.commit('updateState', { messages: newMessage })
if (params.callback) params.callback()
......@@ -71,5 +73,17 @@ export default {
axios.get("/public/secret").then(response => {
context.commit('updateState', { uploadToken: response.data.data })
});
},
// 获取工单类型
onGetWorkorderTypes(context){
axios.get("/public/workorder/types").then(response => {
context.commit('updateState', { workorderTypes: response.data.data })
});
},
// 获取工单列表
onGetWorkorders(context){
axios.get("/public/workorders").then(response => {
context.commit('updateState', { workorders: response.data.data })
});
}
}
\ No newline at end of file
......@@ -62,5 +62,14 @@ export default {
let limit = window.screen.height == window.screen.availHeight ? 1.8 : 1.65;
if (rate > limit) yes = true;
return yes;
},
isShowPageLoading(state){
return state.isShowPageLoading
},
workorders(state){
return state.workorders
},
workorderTypes(state){
return state.workorderTypes
}
}
\ No newline at end of file
export default {
platform: 5, // 平台(渠道)
isShowPageLoading: false, // page loading
isShowHeader: true, // 是否显示header
isMobile: true, // 是否是移动端
isArtificial: false, // 是否是人工服务
......@@ -16,4 +17,9 @@ export default {
userInfo: {}, // 用户信息
companyInfo: null, // 公司信息
uploadToken: null, // 上传token
// workorder
workorders: [], // 工单列表
workorderTypes: [], // 工单类型列表
}
\ No newline at end of file
<template>
<div class="container">
<mt-header v-if="isShowHeader" fixed title="工单">
<mt-header v-if="isShowHeader" fixed title="我的工单">
<div slot="left">
<mt-button @click="$router.go(-1)" icon="back"></mt-button>
</div>
......@@ -9,6 +9,26 @@
<span>创建工单</span>
</mt-button>
</mt-header>
<div class="list" :class="{'hide-header': !isShowHeader}">
<div class="no-data" v-if="workorders.lenght <= 0">
<img src="../assets/workorder.png" alt="">
<div>您还没有发布过工单~</div>
</div>
<ul v-else>
<template v-for="(item,index) in workorders">
<li :key="index" @click="$router.push('/workorder/detail/'+item.id)">
<div class="title">{{item.title}}</div>
<div>
<span class="type">{{getTypeName(item.tid)}}</span>
<span class="date">{{$formatDate(item.create_at)}}</span>
</div>
<i v-if="item.status == 1" style="color:#FF9800;">客服已回复</i>
<i v-if="item.status == 3" style="color:#ccc">工单已结束</i>
<i v-if="item.status == 0 || item.status == 2" style="color:green">待回复</i>
</li>
</template>
</ul>
</div>
</div>
</template>
......@@ -20,18 +40,89 @@ export default {
data() {
return {};
},
created() {
document.title = "我的工单"
},
computed: {
...mapGetters([
'isShowHeader'
'isShowHeader',
'workorders',
'workorderTypes',
])
},
mounted() {},
mounted() {
// 获取工单类型
this.$store.dispatch("onGetWorkorderTypes");
// 获取工单列表
this.$store.dispatch("onGetWorkorders");
},
methods: {
getTypeName(tid){
try{
return this.workorderTypes.filter((i)=>i.id == tid)[0].title
}catch(e){
console.log(e)
return ""
}
}
}
};
</script>
<style lang="stylus" scoped>
.no-data{
text-align center
padding-top 50px
img{
width 50px
height 50px
}
div{
color #666
font-size 12px
}
}
.list{
padding-top 50px
&.hide-header{
padding-top 0
}
li{
padding 10px 20px
background url('../assets/workorder.png') 10px center no-repeat
background-size 25px
padding-left 40px
padding-right 70px
border-bottom 1px solid #ddd
position relative
height 40px
.title{
font-size 14px
color #333
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.type{
font-size 12px
color #666
}
.date{
margin-left 10px
font-size 12px
color #999
}
i{
font-style normal
font-size 11px
position absolute
right 10px
top 0
height: 20px;
bottom 0
margin auto 0
}
}
}
</style>
<template>
<div class="container">
workorder_detail
<mt-header v-if="isShowHeader" fixed :title="workorder.title || '工单详情'">
<div slot="left">
<mt-button @click="$router.go(-1)" icon="back"></mt-button>
</div>
<mt-button slot="right">
<span>删除</span>
</mt-button>
</mt-header>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import axios from "axios";
export default {
name: "workorder_detail",
components: {},
data() {
return {};
return {
workorder: {},
};
},
mounted() {},
methods: {}
computed: {
...mapGetters([
'isShowHeader',
'workorders',
'workorderTypes',
])
},
created() {
document.title = "工单详情"
const id = this.$route.params.id
this.getWorkOrder(id)
},
methods: {
getWorkOrder(id){
axios.get("/public/workorder/"+id).then(response => {
this.workorder = response.data.data
console.log(this.workorder)
}).catch(error => {
console.log(error)
});
}
}
};
</script>
<style lang="stylus" scoped>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment