Merge branch 'main' of https://code.tiantongsl.com/senyao/travel
This commit is contained in:
commit
e937d047ce
|
@ -15,6 +15,12 @@
|
|||
"test:ci": "npm run lint && npm run test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullcalendar/core": "^6.1.15",
|
||||
"@fullcalendar/daygrid": "^6.1.15",
|
||||
"@fullcalendar/interaction": "^6.1.15",
|
||||
"@fullcalendar/list": "^6.1.15",
|
||||
"@fullcalendar/timegrid": "^6.1.15",
|
||||
"@fullcalendar/vue": "^6.1.15",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^1.0.2",
|
||||
"axios": "0.18.1",
|
||||
|
@ -31,6 +37,7 @@
|
|||
"jsonlint": "1.6.3",
|
||||
"jszip": "3.2.1",
|
||||
"left-pad": "^1.3.0",
|
||||
"moment": "^2.30.1",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import request from '@/utils/request'
|
||||
// 获取路线列表
|
||||
export function getProductsList() {
|
||||
return request({
|
||||
url: 'admin/products/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addProducts(data) {
|
||||
return request({
|
||||
url: '/admin/products/add',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
|
@ -7,6 +7,13 @@ export function orderBack(data) {
|
|||
data
|
||||
})
|
||||
}
|
||||
export function orderbackBatch(data) {
|
||||
return request({
|
||||
url: 'admin/order/backBatch',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 获取qa详情
|
||||
export function getQaDetail(city_id) {
|
||||
return request({
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
//直播间列表
|
||||
export function liveroom() {
|
||||
return request({
|
||||
url: '/admin/liveroom/index',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
// 排班列表
|
||||
export function roomWorks(live_room_id) {
|
||||
return request({
|
||||
url: '/admin/liveroom/roomWorks',
|
||||
method: 'get',
|
||||
params: { live_room_id }
|
||||
})
|
||||
}
|
||||
// 可排班主播列表
|
||||
export function availableZhubo(params) {
|
||||
return request({
|
||||
url: '/admin/liveroom/availableZhubo',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
// 编辑直播间
|
||||
export function saveProducts(data) {
|
||||
return request({
|
||||
url: '/admin/liveroom/saveProducts',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 保存排班信息
|
||||
export function saveRoomWorks(data) {
|
||||
return request({
|
||||
url: '/admin/liveroom/saveRoomWorks',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
<hamburger
|
||||
id="hamburger-container"
|
||||
:is-active="sidebar.opened"
|
||||
class="hamburger-container"
|
||||
@toggleClick="toggleSideBar"
|
||||
/>
|
||||
|
||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
|
||||
|
||||
<div class="right-menu">
|
||||
<template v-if="device!=='mobile'">
|
||||
<template v-if="device !== 'mobile'">
|
||||
<!-- <search id="header-search" class="right-menu-item" /> -->
|
||||
|
||||
<!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
|
@ -13,23 +18,54 @@
|
|||
<el-tooltip content="Global Size" effect="dark" placement="bottom">
|
||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
||||
</el-tooltip> -->
|
||||
|
||||
</template>
|
||||
<!-- <div class="right-menu-item hover-effect">
|
||||
<!-- <div class="right-menu-item hover-effect">
|
||||
<el-button @click="drawer = true">QA常见问题</el-button>
|
||||
</div>-->
|
||||
<div v-if="appointment_num" class="right-menu-item hover-effect">
|
||||
<el-button style="color: red" @click="handleAppointemnet()"
|
||||
>预约待处理({{ appointment_num }})</el-button
|
||||
>
|
||||
</div>
|
||||
<div v-if="$store.getters.is_anchor" class="right-menu-item hover-effect">
|
||||
<el-button @click="dialogWorks = true">排班{{ $store.getters.name }}</el-button>
|
||||
<el-button @click="dialogWorks = true"
|
||||
>排班{{ $store.getters.name }}</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="right-menu-item hover-effect">
|
||||
<el-button :style="{backgroundColor:!workstatus?'#409EFF':'#fff',color:workstatus?'#979797':'#fff'}" @click="startWorks">{{ workstatus?'上班':'上班中' }}</el-button>
|
||||
<el-button :style="{backgroundColor:workstatus?'#409EFF':'#fff',color:workstatus?'#fff':'#979797'}" @click="endWorks">{{ workstatus?'下班中':'下班' }}</el-button>
|
||||
<el-button
|
||||
:style="{
|
||||
backgroundColor: !workstatus ? '#409EFF' : '#fff',
|
||||
color: workstatus ? '#979797' : '#fff',
|
||||
}"
|
||||
@click="startWorks"
|
||||
>{{ workstatus ? "上班" : "上班中" }}</el-button
|
||||
>
|
||||
<el-button
|
||||
:style="{
|
||||
backgroundColor: workstatus ? '#409EFF' : '#fff',
|
||||
color: workstatus ? '#fff' : '#979797',
|
||||
}"
|
||||
@click="endWorks"
|
||||
>{{ workstatus ? "下班中" : "下班" }}</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
|
||||
<el-dropdown
|
||||
class="avatar-container right-menu-item hover-effect"
|
||||
trigger="click"
|
||||
>
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar" alt="">
|
||||
<i class="el-icon-camera" style="position: absolute;" @click.stop="showAvatar = true" />
|
||||
<img
|
||||
:src="avatar + '?imageView2/1/w/80/h/80'"
|
||||
class="user-avatar"
|
||||
alt=""
|
||||
/>
|
||||
<i
|
||||
class="el-icon-camera"
|
||||
style="position: absolute"
|
||||
@click.stop="showAvatar = true"
|
||||
/>
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
|
@ -43,18 +79,12 @@
|
|||
<el-dropdown-item>修改密码</el-dropdown-item>
|
||||
</div>
|
||||
<el-dropdown-item divided @click.native="logout">
|
||||
<span style="display:block;">退出登录</span>
|
||||
<span style="display: block">退出登录</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-dialog
|
||||
title="提示"
|
||||
:visible.sync="showAvatar"
|
||||
width="30%"
|
||||
center
|
||||
>
|
||||
|
||||
<el-dialog title="提示" :visible.sync="showAvatar" width="30%" center>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="/admin/index/avatar"
|
||||
|
@ -62,10 +92,9 @@
|
|||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
>
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" alt="">
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" alt="" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="修改密码" :visible.sync="dialogPWD">
|
||||
|
@ -85,7 +114,7 @@
|
|||
|
||||
<el-dialog title="排班" width="90%" :visible.sync="dialogWorks">
|
||||
<el-form :rules="rules">
|
||||
<el-row style="margin-bottom: 10px;">
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-col :span="24">
|
||||
<el-date-picker
|
||||
v-model="times[0]"
|
||||
|
@ -95,7 +124,7 @@
|
|||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="margin-bottom: 10px;">
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-col :span="24">
|
||||
<el-date-picker
|
||||
v-model="times[1]"
|
||||
|
@ -105,10 +134,15 @@
|
|||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="margin-bottom: 10px;">
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-col :span="24">
|
||||
<el-checkbox-group v-model="os">
|
||||
<el-checkbox v-for="(v,i,k) in $store.getters.oss" :key="k" :label="i">{{ v }}</el-checkbox>
|
||||
<el-checkbox
|
||||
v-for="(v, i, k) in $store.getters.oss"
|
||||
:key="k"
|
||||
:label="i"
|
||||
>{{ v }}</el-checkbox
|
||||
>
|
||||
</el-checkbox-group>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
@ -126,10 +160,21 @@
|
|||
:modal="false"
|
||||
>
|
||||
<div v-clickoutside="handleClose" class="drawer">
|
||||
<el-button v-if="QaShow" type="success" @click="drawer = false">关 闭</el-button>
|
||||
<el-button v-if="!QaShow" type="success" @click="QaShow = true">返 回</el-button>
|
||||
<el-button v-if="QaShow" type="success" @click="drawer = false"
|
||||
>关 闭</el-button
|
||||
>
|
||||
<el-button v-if="!QaShow" type="success" @click="QaShow = true"
|
||||
>返 回</el-button
|
||||
>
|
||||
<div v-if="QaShow" class="mod">
|
||||
<el-button v-for="item in getQaCityList" :key="item.city_id" style="width: 150px;" size="medium" type="primary" @click="clickQaList(item)">
|
||||
<el-button
|
||||
v-for="item in getQaCityList"
|
||||
:key="item.city_id"
|
||||
style="width: 150px"
|
||||
size="medium"
|
||||
type="primary"
|
||||
@click="clickQaList(item)"
|
||||
>
|
||||
{{ item.city_name }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
@ -145,17 +190,17 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import Screenfull from '@/components/Screenfull'
|
||||
import SizeSelect from '@/components/SizeSelect'
|
||||
import Search from '@/components/HeaderSearch'
|
||||
import { color } from 'echarts/lib/export'
|
||||
import sidebar from '@/layout/components/Sidebar/index.vue'
|
||||
import avatar from 'element-ui/packages/avatar'
|
||||
import {getQaCityList, getQaList} from '@/api/qa'
|
||||
import clickoutside from 'element-ui/src/utils/clickoutside'
|
||||
import { mapGetters } from "vuex";
|
||||
import Breadcrumb from "@/components/Breadcrumb";
|
||||
import Hamburger from "@/components/Hamburger";
|
||||
import Screenfull from "@/components/Screenfull";
|
||||
import SizeSelect from "@/components/SizeSelect";
|
||||
import Search from "@/components/HeaderSearch";
|
||||
import { color } from "echarts/lib/export";
|
||||
import sidebar from "@/layout/components/Sidebar/index.vue";
|
||||
import avatar from "element-ui/packages/avatar";
|
||||
import { getQaCityList, getQaList } from "@/api/qa";
|
||||
import clickoutside from "element-ui/src/utils/clickoutside";
|
||||
export default {
|
||||
directives: { clickoutside },
|
||||
components: {
|
||||
|
@ -164,20 +209,22 @@ export default {
|
|||
Screenfull,
|
||||
SizeSelect,
|
||||
// eslint-disable-next-line vue/no-unused-Wangeditor
|
||||
Search
|
||||
Search,
|
||||
},
|
||||
props: {
|
||||
appointment_num: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
avatar() {
|
||||
return avatar
|
||||
return avatar;
|
||||
},
|
||||
sidebar() {
|
||||
return sidebar
|
||||
return sidebar;
|
||||
},
|
||||
...mapGetters([
|
||||
'sidebar',
|
||||
'avatar',
|
||||
'device'
|
||||
])
|
||||
...mapGetters(["sidebar", "avatar", "device"]),
|
||||
},
|
||||
// eslint-disable-next-line vue/order-in-Wangeditor
|
||||
data() {
|
||||
|
@ -195,112 +242,143 @@ export default {
|
|||
getQaLists: [],
|
||||
times: [],
|
||||
form: {
|
||||
oldpwd: '',
|
||||
pwd: ''
|
||||
oldpwd: "",
|
||||
pwd: "",
|
||||
},
|
||||
QaInfo: {
|
||||
title: '',
|
||||
content: ''
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
rules: {
|
||||
oldpwd: [
|
||||
{ required: true, message: '请输入旧密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
|
||||
{ required: true, message: "请输入旧密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "长度在 6 到 20 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
pwd: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "长度在 6 到 20 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getworkstatus()
|
||||
getQaCityList().then(res => {
|
||||
this.getQaCityList = res.data
|
||||
})
|
||||
this.getworkstatus();
|
||||
getQaCityList().then((res) => {
|
||||
this.getQaCityList = res.data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
color,
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
this.$store.dispatch("app/toggleSideBar");
|
||||
},
|
||||
handleClose() {
|
||||
this.drawer = false
|
||||
this.QaShow = true
|
||||
this.drawer = false;
|
||||
this.QaShow = true;
|
||||
},
|
||||
clickQaList(data) {
|
||||
getQaList(data.city_id).then(res => {
|
||||
this.getQaLists = res.data
|
||||
})
|
||||
console.log(JSON.stringify(this.getQaLists))
|
||||
getQaList(data.city_id).then((res) => {
|
||||
this.getQaLists = res.data;
|
||||
});
|
||||
console.log(JSON.stringify(this.getQaLists));
|
||||
if (!this.getQaLists) {
|
||||
return this.$message({
|
||||
message: '暂无QA问题',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
})
|
||||
message: "暂无QA问题",
|
||||
type: "warning",
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
this.QaShow = false
|
||||
this.QaShow = false;
|
||||
},
|
||||
async logout() {
|
||||
await this.$store.dispatch('user/logout')
|
||||
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
|
||||
await this.$store.dispatch("user/logout");
|
||||
this.$router.push(`/login?redirect=${this.$route.fullPath}`);
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
this.imageUrl = URL.createObjectURL(file.raw)
|
||||
this.imageUrl = URL.createObjectURL(file.raw);
|
||||
},
|
||||
pwd() {
|
||||
this.$axios.post('/admin/admin/pwd', this.form).then(res => {
|
||||
this.dialogPWD = false
|
||||
this.form = {}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
this.$axios
|
||||
.post("/admin/admin/pwd", this.form)
|
||||
.then((res) => {
|
||||
this.dialogPWD = false;
|
||||
this.form = {};
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
saveWork() {
|
||||
this.$axios.post('/admin/work/save2', { times: this.times, os: this.os }).then(res => {
|
||||
console.log(res)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '添加成功'
|
||||
this.$axios
|
||||
.post("/admin/work/save2", { times: this.times, os: this.os })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "添加成功",
|
||||
});
|
||||
this.dialogWorks = false;
|
||||
})
|
||||
this.dialogWorks = false
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
startWorks() {
|
||||
this.$axios.post('/admin/admin/editInfo', { is_order: 1 }).then(res => {
|
||||
console.log(res)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '上班成功'
|
||||
this.$axios
|
||||
.post("/admin/admin/editInfo", { is_order: 1 })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "上班成功",
|
||||
});
|
||||
this.getworkstatus();
|
||||
})
|
||||
this.getworkstatus()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
endWorks() {
|
||||
this.$axios.post('/admin/admin/editInfo', { is_order: 0 }).then(res => {
|
||||
console.log(res)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '下班成功'
|
||||
this.$axios
|
||||
.post("/admin/admin/editInfo", { is_order: 0 })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "下班成功",
|
||||
});
|
||||
this.getworkstatus();
|
||||
})
|
||||
this.getworkstatus()
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
getworkstatus() {
|
||||
this.$axios.post('/admin/work/getworkstatus', { id: this.id }).then(res => {
|
||||
console.log(res)
|
||||
this.workstatus = res.data
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
this.$axios
|
||||
.post("/admin/work/getworkstatus", { id: this.id })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
this.workstatus = res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
handleAppointemnet() {
|
||||
this.$router.push({
|
||||
path: "/order/index/",
|
||||
query: { appointment_status: "1", refresh: Date.now() },
|
||||
});
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
/*const isJPG = file.type === 'image/jpeg'
|
||||
|
@ -313,29 +391,29 @@ export default {
|
|||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isJPG && isLt2M*/
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer{
|
||||
.drawer {
|
||||
padding: 20px 0 0 20px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
.mod{
|
||||
.mod {
|
||||
margin-top: 50px;
|
||||
}
|
||||
.ver{
|
||||
.ver {
|
||||
margin-top: 30px;
|
||||
color: #6c6f71;
|
||||
&_title{
|
||||
&_title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
&_content{
|
||||
&_content {
|
||||
line-height: 26px;
|
||||
font-size: 15px;
|
||||
padding-bottom: 10px;
|
||||
|
@ -348,18 +426,18 @@ export default {
|
|||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
-webkit-tap-highlight-color:transparent;
|
||||
transition: background 0.3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,10 +469,10 @@ export default {
|
|||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background .3s;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025)
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +511,7 @@ export default {
|
|||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
border-color: #409eff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
border: 1px solid #979797;
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
|
||||
<template
|
||||
v-if="
|
||||
hasOneShowingChild(item.children, item) &&
|
||||
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
|
||||
!item.alwaysShow
|
||||
"
|
||||
>
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
|
||||
<el-menu-item
|
||||
:index="resolvePath(onlyOneChild.path)"
|
||||
:class="{ 'submenu-title-noDropdown': !isNest }"
|
||||
>
|
||||
<item
|
||||
:icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"
|
||||
:title="onlyOneChild.meta.title"
|
||||
/>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
|
||||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
|
||||
<el-submenu
|
||||
v-else
|
||||
ref="subMenu"
|
||||
:index="resolvePath(item.path)"
|
||||
popper-append-to-body
|
||||
>
|
||||
<template slot="title">
|
||||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
|
||||
<item
|
||||
v-if="item.meta"
|
||||
:icon="item.meta && item.meta.icon"
|
||||
:title="item.meta.title"
|
||||
/>
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
|
@ -25,71 +46,72 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import path from 'path'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
import path from "path";
|
||||
import { isExternal } from "@/utils/validate";
|
||||
import Item from "./Item";
|
||||
import AppLink from "./Link";
|
||||
import FixiOSBug from "./FixiOSBug";
|
||||
|
||||
export default {
|
||||
name: 'SidebarItem',
|
||||
name: "SidebarItem",
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
// route object
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
|
||||
// TODO: refactor with render function
|
||||
this.onlyOneChild = null
|
||||
return {}
|
||||
this.onlyOneChild = null;
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
hasOneShowingChild(children = [], parent) {
|
||||
const showingChildren = children.filter(item => {
|
||||
const showingChildren = children.filter((item) => {
|
||||
if (item.hidden) {
|
||||
return false
|
||||
return false;
|
||||
} else {
|
||||
// Temp set(will be used if only has one showing child)
|
||||
this.onlyOneChild = item
|
||||
return true
|
||||
this.onlyOneChild = item;
|
||||
return true;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// When there is only one child router, the child router is displayed by default
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
if (showingChildren.length === 0) {
|
||||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
this.onlyOneChild = { ...parent, path: "", noShowingChildren: true };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false
|
||||
return false;
|
||||
},
|
||||
resolvePath(routePath) {
|
||||
routePath = routePath.replace(/\/:[a-zA-Z]+/g, "");
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
return routePath;
|
||||
}
|
||||
if (isExternal(this.basePath)) {
|
||||
return this.basePath
|
||||
return this.basePath;
|
||||
}
|
||||
return path.resolve(this.basePath, routePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return path.resolve(this.basePath, routePath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<template>
|
||||
<div :class="classObj" class="app-wrapper">
|
||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
|
||||
<div
|
||||
v-if="device === 'mobile' && sidebar.opened"
|
||||
class="drawer-bg"
|
||||
@click="handleClickOutside"
|
||||
/>
|
||||
<sidebar class="sidebar-container" />
|
||||
<div :class="{hasTagsView:needTagsView}" class="main-container">
|
||||
<div :class="{'fixed-header':fixedHeader}">
|
||||
<navbar />
|
||||
<div :class="{ hasTagsView: needTagsView }" class="main-container">
|
||||
<div :class="{ 'fixed-header': fixedHeader }">
|
||||
<navbar :appointment_num="appointment_num" />
|
||||
<tags-view v-if="needTagsView" />
|
||||
</div>
|
||||
<app-main />
|
||||
|
@ -16,127 +20,193 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import RightPanel from '@/components/RightPanel'
|
||||
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
|
||||
import ResizeMixin from './mixin/ResizeHandler'
|
||||
import { mapState } from 'vuex'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import RightPanel from "@/components/RightPanel";
|
||||
import { AppMain, Navbar, Settings, Sidebar, TagsView } from "./components";
|
||||
import ResizeMixin from "./mixin/ResizeHandler";
|
||||
import { mapState } from "vuex";
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
export default {
|
||||
name: 'Layout',
|
||||
name: "Layout",
|
||||
components: {
|
||||
AppMain,
|
||||
Navbar,
|
||||
RightPanel,
|
||||
Settings,
|
||||
Sidebar,
|
||||
TagsView
|
||||
TagsView,
|
||||
},
|
||||
mixins: [ResizeMixin],
|
||||
computed: {
|
||||
...mapState({
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
showSettings: state => state.settings.showSettings,
|
||||
needTagsView: state => state.settings.tagsView,
|
||||
fixedHeader: state => state.settings.fixedHeader
|
||||
sidebar: (state) => state.app.sidebar,
|
||||
device: (state) => state.app.device,
|
||||
showSettings: (state) => state.settings.showSettings,
|
||||
needTagsView: (state) => state.settings.tagsView,
|
||||
fixedHeader: (state) => state.settings.fixedHeader,
|
||||
}),
|
||||
classObj() {
|
||||
return {
|
||||
hideSidebar: !this.sidebar.opened,
|
||||
openSidebar: this.sidebar.opened,
|
||||
withoutAnimation: this.sidebar.withoutAnimation,
|
||||
mobile: this.device === 'mobile'
|
||||
}
|
||||
}
|
||||
mobile: this.device === "mobile",
|
||||
};
|
||||
},
|
||||
},
|
||||
data(){
|
||||
data() {
|
||||
return {
|
||||
iswork:null
|
||||
}
|
||||
iswork: null,
|
||||
appointment_num: 0,
|
||||
};
|
||||
},
|
||||
created(){
|
||||
this.iswork = setInterval(()=>{
|
||||
let toke = getToken()
|
||||
if(!toke || toke.length <= 0) return;
|
||||
this.$axios.get('/admin/index/iswork').then(res=>{
|
||||
if(res && res.data.new > 0) {
|
||||
this.$notify({
|
||||
title: '新的订单提醒',
|
||||
duration: 0,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>你有('+res.data.new+')个新的订单,需要处理</strong>'
|
||||
});
|
||||
}
|
||||
if(res && res.data.follow > 0) {
|
||||
this.$notify({
|
||||
title: '新的跟进提醒',
|
||||
duration: 10000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>你有('+res.data.follow+')个跟进订单,需要处理</strong>'
|
||||
});
|
||||
}
|
||||
if(res && res.data.back > 0) {
|
||||
this.$notify({
|
||||
title: '转单申请',
|
||||
duration: 10000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>你有('+res.data.back+')个转单订单,需要处理</strong>'
|
||||
});
|
||||
}
|
||||
}).catch(err=>{
|
||||
console.log(err)
|
||||
})
|
||||
},30000);
|
||||
created() {
|
||||
this.iswork = setInterval(() => {
|
||||
let toke = getToken();
|
||||
if (!toke || toke.length <= 0) return;
|
||||
this.$axios
|
||||
.get("/admin/index/iswork")
|
||||
.then((res) => {
|
||||
// console.log(res);
|
||||
|
||||
this.appointment_num = res.data.appointment_num;
|
||||
console.log(this.appointment_num);
|
||||
|
||||
if (res && res.data.new > 0) {
|
||||
this.$notify({
|
||||
title: "新的订单提醒",
|
||||
duration: 0,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message:
|
||||
"<strong>你有(" +
|
||||
res.data.new +
|
||||
")个新的订单,需要处理</strong>",
|
||||
});
|
||||
}
|
||||
if (res && res.data.follow > 0) {
|
||||
this.$notify({
|
||||
title: "新的跟进提醒",
|
||||
duration: 10000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message:
|
||||
"<strong>你有(" +
|
||||
res.data.follow +
|
||||
")个跟进订单,需要处理</strong>",
|
||||
});
|
||||
}
|
||||
if (res && res.data.back > 0) {
|
||||
this.$notify({
|
||||
title: "转单申请",
|
||||
duration: 10000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message:
|
||||
"<strong>你有(" +
|
||||
res.data.back +
|
||||
")个转单订单,需要处理</strong>",
|
||||
});
|
||||
}
|
||||
if (res && res.data.order_write_off > 0) {
|
||||
this.$notify({
|
||||
title: "订单核销",
|
||||
duration: 10000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message:
|
||||
"<strong>你有(" +
|
||||
res.data.order_write_off +
|
||||
")个核销订单</strong>",
|
||||
});
|
||||
}
|
||||
if (res && res.data.follow_message > 0) {
|
||||
this.$notify({
|
||||
// res.data.follow_order_id
|
||||
title: "跟进提醒",
|
||||
duration: 50000,
|
||||
dangerouslyUseHTMLString: true,
|
||||
message:
|
||||
"<strong>你有(" +
|
||||
res.data.follow_message +
|
||||
")个跟进提醒</strong>",
|
||||
onClick: () => {
|
||||
// console.log(res.data.follow_order_id);
|
||||
this.$router.push({
|
||||
path: "/order/index/",
|
||||
query: { id: res.data.follow_order_id, refresh: Date.now() },
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 30000);
|
||||
},
|
||||
methods: {
|
||||
handleClickOutside() {
|
||||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
|
||||
},
|
||||
followDetail(orderId) {
|
||||
console.log(orderId);
|
||||
// this.$router.push({ path: "/order/index/" + orderId });
|
||||
},
|
||||
onInfo(item) {
|
||||
this.value = null;
|
||||
this.next_follow = null;
|
||||
this.$set(item, "next_follow", null);
|
||||
this.item = item;
|
||||
this.active = "follow";
|
||||
this.$axios
|
||||
.get("/admin/order/info", { params: { id: item.id } })
|
||||
.then((res) => {
|
||||
this.item = res.data;
|
||||
this.dialogVisible = true;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/mixin.scss";
|
||||
@import "~@/styles/variables.scss";
|
||||
@import "~@/styles/mixin.scss";
|
||||
@import "~@/styles/variables.scss";
|
||||
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.app-wrapper {
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&.mobile.openSidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.fixed-header {
|
||||
&.mobile.openSidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: calc(100% - #{$sideBarWidth});
|
||||
transition: width 0.28s;
|
||||
}
|
||||
}
|
||||
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px)
|
||||
}
|
||||
.drawer-bg {
|
||||
background: #000;
|
||||
opacity: 0.3;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: calc(100% - #{$sideBarWidth});
|
||||
transition: width 0.28s;
|
||||
}
|
||||
|
||||
.hideSidebar .fixed-header {
|
||||
width: calc(100% - 54px);
|
||||
}
|
||||
|
||||
.mobile .fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,7 +3,7 @@ import Vue from 'vue'
|
|||
import Cookies from 'js-cookie'
|
||||
|
||||
import 'normalize.css/normalize.css' // a modern alternative to CSS resets
|
||||
|
||||
// import consts from '@/utils/consts'
|
||||
import Element from 'element-ui'
|
||||
import './styles/element-variables.scss'
|
||||
// import enLang from 'element-ui/lib/locale/lang/en'// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖
|
||||
|
@ -36,7 +36,7 @@ if (process.env.NODE_ENV === 'production') {
|
|||
const { mockXHR } = require('../mock')
|
||||
mockXHR()
|
||||
}
|
||||
|
||||
// Vue.prototype.$consts = consts
|
||||
Vue.use(Element, {
|
||||
size: Cookies.get('size') || 'medium' // set element-ui default size
|
||||
// locale: enLang // 如果使用中文,无需设置,请删除
|
||||
|
|
|
@ -103,6 +103,15 @@ export const asyncRoutes = [
|
|||
roles: ['admin']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'scheduling',
|
||||
component: () => import('@/views/scheduling/index'),
|
||||
name: 'scheduling',
|
||||
meta: {
|
||||
title: '直播排班',
|
||||
roles: ['admin']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'onlines',
|
||||
component: () => import('@/views/onlines/online.vue'),
|
||||
|
@ -189,6 +198,24 @@ export const asyncRoutes = [
|
|||
roles: ['order_back', 'editor']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'refunded',
|
||||
component: () => import('@/views/order/refunded'),
|
||||
name: 'OrderBack',
|
||||
meta: {
|
||||
title: '已退款订单',
|
||||
roles: ['order_back', 'editor']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'appointment',
|
||||
component: () => import('@/views/order/appointment'),
|
||||
name: 'appointment',
|
||||
meta: {
|
||||
title: '预约记录',
|
||||
roles: ['order_back', 'editor']
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import axios from 'axios'
|
||||
import { MessageBox, Message } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { getToken,removeToken } from '@/utils/auth'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
|
@ -65,6 +65,9 @@ service.interceptors.response.use(
|
|||
})
|
||||
})
|
||||
}
|
||||
if (res.code == 400) {
|
||||
removeToken()
|
||||
}
|
||||
return Promise.reject(new Error(res.message || 'Error'))
|
||||
} else {
|
||||
return res
|
||||
|
|
|
@ -1,93 +1,197 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<div class="filter-container">
|
||||
<el-input v-model="listQuery.username" placeholder="用户名" style="width: 200px; margin-right: 10px;" class="filter-item" />
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="getList">
|
||||
<el-input
|
||||
v-model="listQuery.username"
|
||||
placeholder="用户名"
|
||||
style="width: 200px; margin-right: 10px"
|
||||
class="filter-item"
|
||||
/>
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-circle-plus" @click="handleCreate({routes:[]})">
|
||||
<el-button
|
||||
class="filter-item"
|
||||
style="margin-left: 10px"
|
||||
type="primary"
|
||||
icon="el-icon-circle-plus"
|
||||
@click="handleCreate({ routes: [] })"
|
||||
>
|
||||
添加
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="list"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column align="center" label="操作" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" @click="handleCreate(scope.row)" size="small" icon="el-icon-edit">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleCreate(scope.row)"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
|
||||
<el-button type="primary" v-if="scope.row.status" @click="onWork(scope.row)" size="small" icon="el-icon-date">
|
||||
<el-button
|
||||
type="primary"
|
||||
v-if="scope.row.status"
|
||||
@click="onWork(scope.row)"
|
||||
size="small"
|
||||
icon="el-icon-date"
|
||||
>
|
||||
排班
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="ID" width="80" prop="id"></el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="ID"
|
||||
width="80"
|
||||
prop="id"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column align="center" label="用户名" width="160" prop="username"></el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="用户名"
|
||||
width="160"
|
||||
prop="username"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column align="center" label="姓名" width="160" prop="name"></el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="姓名"
|
||||
width="160"
|
||||
prop="name"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column align="center" label="手机" width="160" prop="mobile"></el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="手机"
|
||||
width="160"
|
||||
prop="mobile"
|
||||
></el-table-column>
|
||||
<!-- <el-table-column width="138px" align="center" label="路线">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.route_type === 10" type="border-card"
|
||||
>境内路线</el-tag
|
||||
>
|
||||
<el-tag v-if="scope.row.route_type === 20" type="success"
|
||||
>境外路线</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
|
||||
<!-- <el-table-column align="center" label="头像">
|
||||
<!-- <el-table-column align="center" label="头像">
|
||||
<template slot-scope="scope">
|
||||
<el-avatar :size="50" :src="scope.row.avatar"></el-avatar>
|
||||
</template>
|
||||
</el-table-column>-->
|
||||
|
||||
<el-table-column class-name="status-col" label="状态" width="180">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
@change="setStatus(row)"
|
||||
active-text="启用"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
inactive-text="禁用">
|
||||
inactive-text="禁用"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="180px" align="center" label="创建时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.create_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<span>{{
|
||||
scope.row.create_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="180px" align="center" label="修改时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.update_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<span>{{
|
||||
scope.row.update_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="listQuery.page"
|
||||
:limit.sync="listQuery.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
|
||||
<el-dialog title="修改管理员" :visible.sync="dialogVisible">
|
||||
<el-form label-width="120px" :model="item">
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="item.username" name="username" placeholder="管理员的用户名"></el-input>
|
||||
<el-input
|
||||
v-model="item.username"
|
||||
name="username"
|
||||
placeholder="管理员的用户名"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="item.name" name="name" placeholder="管理员的姓名"></el-input>
|
||||
<el-input
|
||||
v-model="item.name"
|
||||
name="name"
|
||||
placeholder="管理员的姓名"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机">
|
||||
<el-input v-model="item.mobile" name="name" placeholder="发送短时的时候会用到这个手机"></el-input>
|
||||
<el-input
|
||||
v-model="item.mobile"
|
||||
name="name"
|
||||
placeholder="发送短时的时候会用到这个手机"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="微信">
|
||||
<el-input
|
||||
v-model="item.wechat"
|
||||
name="wechat"
|
||||
placeholder="微信号"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="微信图片">
|
||||
<el-upload
|
||||
action = ""
|
||||
list-type="picture-card"
|
||||
multiple:false
|
||||
:show-file-list="false"
|
||||
:http-request="handlesAvatarSuccess"
|
||||
:on-success="
|
||||
(response, file, fileList) =>
|
||||
handleSuccess(response, file, fileList, 1)"
|
||||
>
|
||||
<img v-if="item.wechat_pic" :src="item.wechat_pic" style="width: 120px; height: 120px;margin-top: 14px;"/>
|
||||
<i slot="default" class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input v-model="item.password" type="password" name="password" placeholder="管理员的新密码"></el-input>
|
||||
<el-input
|
||||
v-model="item.password"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="管理员的新密码"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否分配">
|
||||
<el-switch
|
||||
|
@ -96,7 +200,7 @@
|
|||
:active-value="1"
|
||||
inactive-text="不分配"
|
||||
:inactive-value="0"
|
||||
>
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否主播">
|
||||
|
@ -106,7 +210,7 @@
|
|||
:active-value="1"
|
||||
inactive-text=""
|
||||
:inactive-value="0"
|
||||
>
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否加盟商">
|
||||
|
@ -116,23 +220,42 @@
|
|||
:active-value="1"
|
||||
inactive-text=""
|
||||
:inactive-value="0"
|
||||
>
|
||||
>
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="产品ID">
|
||||
<!-- <el-form-item label="产品ID">
|
||||
<el-input v-model="item.product_ids" type="textarea" />
|
||||
<span style="color: red;font-size: 11px;">多个用英文逗号隔开,例如: 384731,2328</span>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="路线">
|
||||
<el-checkbox-group v-model="item.routes">
|
||||
<el-checkbox label="复选框 A">111</el-checkbox>
|
||||
<el-checkbox label="复选框 B">2222</el-checkbox>
|
||||
<el-checkbox label="复选框 C">3333</el-checkbox>
|
||||
<el-checkbox label="禁用" disabled></el-checkbox>
|
||||
<el-checkbox label="选中且禁用" disabled></el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<span style="color: red; font-size: 11px"
|
||||
>多个用英文逗号隔开,例如: 384731,2328</span
|
||||
>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="线路">
|
||||
<el-select
|
||||
filterable
|
||||
v-model="item.product_ids"
|
||||
multiple
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.id"
|
||||
:label="item.product_name"
|
||||
:value="item.id"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div class="addRoutes">
|
||||
<el-button
|
||||
class="filter-item"
|
||||
style="margin-left: 10px"
|
||||
type="primary"
|
||||
icon="el-icon-circle-plus"
|
||||
@click="handleAddRoutes"
|
||||
>添加线路</el-button
|
||||
>
|
||||
</div>
|
||||
<!-- <el-form-item label="路线">
|
||||
<el-select multiple v-model="item.routes" filterable placeholder="请选择">
|
||||
<el-option
|
||||
|
@ -143,12 +266,12 @@
|
|||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="路线">
|
||||
<!-- <el-form-item label="路线">
|
||||
<el-radio-group v-model="item.route_type">
|
||||
<el-radio :label="10">境内跟团</el-radio>
|
||||
<el-radio :label="20">境外跟团</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="onSave(item)">保 存</el-button>
|
||||
|
@ -157,13 +280,13 @@
|
|||
|
||||
<el-dialog title="添加排班" :visible.sync="dialogWork">
|
||||
<el-form label-width="120px" :model="from">
|
||||
|
||||
<el-form-item label="上班日期">
|
||||
<el-date-picker
|
||||
style="margin-right: 10px;"
|
||||
style="margin-right: 10px"
|
||||
type="dates"
|
||||
v-model="from.dates"
|
||||
placeholder="选择一个或多个日期">
|
||||
placeholder="选择一个或多个日期"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
|
@ -180,127 +303,272 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item label="渠道">
|
||||
<el-checkbox-group v-model="from.oss" >
|
||||
<el-checkbox v-for="(v,i,k) in oss" :label="i" :key="k">{{v}}</el-checkbox>
|
||||
<el-checkbox-group v-model="from.oss">
|
||||
<el-checkbox v-for="(v, i, k) in oss" :label="i" :key="k">{{
|
||||
v
|
||||
}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="onWork()">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="添加线路" :visible.sync="isAddRouters" width="30%">
|
||||
<el-form
|
||||
:rules="addRoutes"
|
||||
ref="AddRoutersForm"
|
||||
:model="AddRoutersForm"
|
||||
label-width="80px"
|
||||
>
|
||||
<el-form-item label="平台" prop="os">
|
||||
<el-select v-model="AddRoutersForm.os" placeholder="请选择平台">
|
||||
<el-option
|
||||
v-for="item in platformList"
|
||||
:label="item.os"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="线路名称" prop="product_name">
|
||||
<el-input
|
||||
placeholder="请输入线路名称"
|
||||
v-model="AddRoutersForm.product_name"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="线路id" prop="third_product_id">
|
||||
<el-input
|
||||
placeholder="请输入线路id"
|
||||
v-model="AddRoutersForm.third_product_id"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="isAddRouters = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleAddRouters">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
|
||||
|
||||
import Pagination from "@/components/Pagination"; // Secondary package based on el-pagination
|
||||
import { getProductsList, addProducts } from "@/api/admin";
|
||||
import { getToken } from "@/utils/auth";
|
||||
export default {
|
||||
name: 'Adminlist',
|
||||
name: "Adminlist",
|
||||
components: { Pagination },
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
ids: "",
|
||||
oss: [],
|
||||
from: {oss:[]},
|
||||
platformList: [],
|
||||
isAddRouters: false,
|
||||
AddRoutersForm: {
|
||||
third_product_id: "",
|
||||
product_name: "",
|
||||
os: "",
|
||||
},
|
||||
from: { oss: [] },
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20
|
||||
limit: 20,
|
||||
},
|
||||
dialogVisible: false,
|
||||
dialogWork: false,
|
||||
item: {
|
||||
btn:[]
|
||||
btn: [],
|
||||
product_ids: [],
|
||||
},
|
||||
route_type: '',
|
||||
// options: [{
|
||||
// value: '1',
|
||||
// label: '路线1'
|
||||
// }, {
|
||||
// value: '2',
|
||||
// label: '路线2'
|
||||
// }, {
|
||||
// value: '3',
|
||||
// label: '路线3'
|
||||
// }, {
|
||||
// value: '4',
|
||||
// label: '路线4'
|
||||
// }, {
|
||||
// value: '5',
|
||||
// label: '路线5'
|
||||
// }],
|
||||
}
|
||||
route_type: "",
|
||||
options: [],
|
||||
addRoutes: {
|
||||
third_product_id: [
|
||||
{ required: true, message: "请输入线路id", trigger: "blur" },
|
||||
],
|
||||
os: [{ required: true, message: "请选择平台", trigger: "change" }],
|
||||
product_name: [
|
||||
{ required: true, message: "请输入线路名称", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.$axios.get('/admin/admin/index', { params: this.listQuery }).then(response => {
|
||||
this.list = response.data.data
|
||||
this.total = response.data.total
|
||||
this.oss = response.ext.oss
|
||||
// for(let k in response.ext.oss){
|
||||
// this.oss.push({id:k,val:response.ext.oss[k]})
|
||||
// }
|
||||
console.log(this.oss)
|
||||
this.listLoading = false
|
||||
}).catch(err=>{
|
||||
})
|
||||
this.$axios
|
||||
.get("/admin/admin/index", { params: this.listQuery })
|
||||
.then((response) => {
|
||||
this.list = response.data.data;
|
||||
this.total = response.data.total;
|
||||
this.oss = response.ext.oss;
|
||||
// for(let k in response.ext.oss){
|
||||
// this.oss.push({id:k,val:response.ext.oss[k]})
|
||||
// }
|
||||
console.log(this.oss);
|
||||
this.listLoading = false;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
checkIfUrlContainsImage(url = "") {
|
||||
const imageExtensions = [
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".png",
|
||||
".gif",
|
||||
".bmp",
|
||||
".svg",
|
||||
".webp",
|
||||
];
|
||||
return imageExtensions.some((extension) =>
|
||||
url.toLowerCase().endsWith(extension)
|
||||
);
|
||||
},
|
||||
handleAddRoutes() {
|
||||
this.isAddRouters = true;
|
||||
},
|
||||
async handlesAvatarSuccess(file) {
|
||||
try {
|
||||
var formdata = new FormData();
|
||||
formdata.append("file", file.file);
|
||||
|
||||
this.upLoading = true;
|
||||
const _this = this;
|
||||
const res = await this.$axios.post("/admin/upload/index", formdata, {
|
||||
headers: {
|
||||
"Content-type": "multipart/form-data",
|
||||
"X-Token": getToken(),
|
||||
},
|
||||
});
|
||||
this.item.wechat_pic = `${window.location.protocol}//${window.location.host}${res.data}`;
|
||||
file.onSuccess(res);
|
||||
} catch (error) {
|
||||
console.error('error:', error);
|
||||
}
|
||||
},
|
||||
handleSuccess(res, file, fileList) {
|
||||
console.log(res, file, fileList);
|
||||
if (!res.data) return;
|
||||
this.item.wechat_pic = `${window.location.protocol}//${window.location.host}${res.data}`;
|
||||
},
|
||||
handleAddRouters() {
|
||||
this.$refs["AddRoutersForm"].validate(async (valid) => {
|
||||
if (valid) {
|
||||
let add = await addProducts(this.AddRoutersForm);
|
||||
this.isAddRouters = false;
|
||||
if (add.msg == "ok") {
|
||||
this.$message({
|
||||
message: "线路添加成功",
|
||||
type: "success",
|
||||
});
|
||||
let res = await getProductsList();
|
||||
this.options = res.data.data;
|
||||
this.platformList = res.ext.oss;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
setStatus(item) {
|
||||
console.log(item)
|
||||
this.$axios.post('/admin/admin/disabled',item).then(res=>{
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '修改成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
}).catch(err=>{
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '修改失败',
|
||||
type: 'error',
|
||||
duration: 2000
|
||||
console.log(item);
|
||||
this.$axios
|
||||
.post("/admin/admin/disabled", item)
|
||||
.then((res) => {
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "修改成功",
|
||||
type: "success",
|
||||
duration: 2000,
|
||||
});
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "修改失败",
|
||||
type: "error",
|
||||
duration: 2000,
|
||||
});
|
||||
});
|
||||
},
|
||||
handleCreate(item) {
|
||||
async handleCreate(item) {
|
||||
this.dialogVisible = true;
|
||||
this.item = item
|
||||
let res = await getProductsList();
|
||||
// console.log(res.data.data);
|
||||
this.options = res.data.data;
|
||||
this.platformList = res.ext.oss;
|
||||
this.item = { ...item };
|
||||
this.item.product_ids = item.product_ids.split(",").map((item) => {
|
||||
return Number(item);
|
||||
});
|
||||
},
|
||||
onSave(from) {
|
||||
this.$axios.post('/admin/admin/save', from).then(response => {
|
||||
this.item = {}
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
}).catch(err=>{
|
||||
})
|
||||
this.$axios
|
||||
.post("/admin/admin/save", {
|
||||
...from,
|
||||
product_ids: from.product_ids.join(),
|
||||
})
|
||||
.then((response) => {
|
||||
this.$message({
|
||||
message: "成功",
|
||||
type: "success",
|
||||
});
|
||||
this.item = {};
|
||||
this.dialogVisible = false;
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onWork(item) {
|
||||
if(item) {
|
||||
this.item = item
|
||||
this.from = {oss:[]}
|
||||
this.dialogWork = true
|
||||
return
|
||||
if (item) {
|
||||
this.item = item;
|
||||
this.from = { oss: [] };
|
||||
this.dialogWork = true;
|
||||
return;
|
||||
}
|
||||
this.from.admin_id = this.item.id;
|
||||
this.$axios.post('/admin/work/saves', this.from).then(response => {
|
||||
this.item = {}
|
||||
this.dialogWork = false
|
||||
}).catch(err=>{
|
||||
|
||||
})
|
||||
this.$axios
|
||||
.post("/admin/work/saves", this.from)
|
||||
.then((response) => {
|
||||
this.item = {};
|
||||
this.dialogWork = false;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
setTime(val) {
|
||||
console.log(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(val);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
.addRoutes {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
// .el-input__suffix .el-input__suffix-inner {
|
||||
// // 解决聚焦的时候会有闪现一下滚动条
|
||||
// .el-input__icon {
|
||||
// transform: rotateZ(0deg);
|
||||
// // transition: transform 20s;
|
||||
// // background: pink;
|
||||
// &::before {
|
||||
// display: inline-block;
|
||||
// transition: transform 0.3s;
|
||||
// transform: rotateZ(180deg);
|
||||
// }
|
||||
// &.is-reverse::before {
|
||||
// transform: rotateZ(0deg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
</style>
|
||||
|
|
|
@ -1,226 +1,309 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<div class="filter-container">
|
||||
<el-input v-model="listQuery.username" placeholder="用户名" style="width: 200px; margin-right: 10px;"
|
||||
class="filter-item" />
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="getList">
|
||||
<el-input
|
||||
v-model="listQuery.mobile"
|
||||
placeholder="手机号"
|
||||
style="width: 200px; margin-right: 10px"
|
||||
class="filter-item"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-model="listQuery.times"
|
||||
class="filter-item"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-circle-plus" @click="onAdd">
|
||||
添加主播排班
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-circle-plus"
|
||||
@click="onAdd"
|
||||
>
|
||||
添加主播
|
||||
</el-button>
|
||||
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="list"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column align="center" fixed label="操作" width="220">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" @click="onDel(scope.row)" size="small" icon="el-icon-delete-solid">
|
||||
<!-- <el-button
|
||||
type="danger"
|
||||
@click="onDel(scope.row)"
|
||||
size="small"
|
||||
icon="el-icon-delete-solid"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</el-button> -->
|
||||
|
||||
<el-button type="primary" @click="onSave(scope.row)" size="small" icon="el-icon-edit">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="onAdd(scope.row)"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="ID" width="80">
|
||||
<!-- <el-table-column align="center" label="ID" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column> -->
|
||||
|
||||
<el-table-column align="center" label="用户名" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.admin.username }}</span>
|
||||
<span>{{ scope.row.username }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="姓名" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.admin.name }}</span>
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- <el-table-column align="center" width="100px" label="头像">
|
||||
<el-table-column align="center" label="手机号" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-avatar :size="50" :src="scope.row.admin.avatar"></el-avatar>
|
||||
</template>
|
||||
</el-table-column>-->
|
||||
|
||||
<el-table-column align="center" label="排班时间">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.start| parseTime('{y}-{m}-{d} {h}:{i}') }} - {{ scope.row.end| parseTime('{y}-{m}-{d} {h}:{i}') }}
|
||||
<span>{{ scope.row.mobile }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="岗位" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.type == 2 ? "主播" : "中控" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column align="center" label="排班时间">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.start | parseTime("{y}-{m}-{d} {h}:{i}") }} -
|
||||
{{ scope.row.end | parseTime("{y}-{m}-{d} {h}:{i}") }}
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
|
||||
<el-table-column align="center" label="平台">
|
||||
<!-- <el-table-column align="center" label="平台">
|
||||
<template slot-scope="scope">
|
||||
<template v-for="i in scope.row.os">
|
||||
{{ oss[i] }}
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
|
||||
<el-table-column align="center" label="订单数">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.orders }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="直播时长(小时)">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.work_time }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="订单金额">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.total/100 }}
|
||||
{{ scope.row.total }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="140px" align="center" label="创建时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.create_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<span>{{
|
||||
scope.row.create_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="140px" align="center" label="修改时间">
|
||||
<!-- <el-table-column width="140px" align="center" label="修改时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.update_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<span>{{
|
||||
scope.row.update_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="listQuery.page"
|
||||
:limit.sync="listQuery.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<!--
|
||||
<el-dialog title="修改排班" :visible.sync="dialogWork">
|
||||
<el-form label-width="120px" :model="item">
|
||||
|
||||
<el-form-item label="上班时间">
|
||||
<el-date-picker
|
||||
v-model="item.date"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期">
|
||||
end-placeholder="结束日期"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="渠道">
|
||||
<el-checkbox-group v-model="item.oss">
|
||||
<el-checkbox v-for="(v,i,k) in oss" :label="i" :key="k">{{v}}</el-checkbox>
|
||||
<el-checkbox v-for="(v, i, k) in oss" :label="i" :key="k">{{
|
||||
v
|
||||
}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="onSave()">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-dialog> -->
|
||||
|
||||
<el-dialog title="主播排班表" :visible.sync="dialogCreate">
|
||||
<el-form label-width="120px">
|
||||
<el-row v-for="an in anchors" :key="an.id" style="margin-bottom: 10px;">
|
||||
<el-col :span="2">{{ an.name }}</el-col>
|
||||
<el-col :span="14">
|
||||
<el-date-picker
|
||||
v-model="an.times"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
:default-time="['07:00:00', '23:59:59']"
|
||||
style="width:90%"
|
||||
end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-checkbox-group v-model="an.os">
|
||||
<el-checkbox v-for="(v,i,k) in oss" :label="i" :key="k">{{v}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog :title="title" :visible.sync="dialogCreate">
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input placeholder="用户名" v-model="form.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input placeholder="姓名" v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="mobile">
|
||||
<el-input placeholder="请输入手机号" v-model="form.mobile"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="岗位" prop="type">
|
||||
<el-radio-group v-model="form.type">
|
||||
<el-radio :label="2">主播</el-radio>
|
||||
<el-radio :label="3">中控</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" v-loading="loading" @click="onSaves()">保 存</el-button>
|
||||
<el-button type="primary" v-loading="loading" @click="onSaves(form)"
|
||||
>保 存</el-button
|
||||
>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
|
||||
import Pagination from "@/components/Pagination"; // Secondary package based on el-pagination
|
||||
|
||||
export default {
|
||||
name: 'Works',
|
||||
name: "Works",
|
||||
components: { Pagination },
|
||||
data() {
|
||||
return {
|
||||
oss: {},
|
||||
list: null,
|
||||
title: "",
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
loading: false,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20
|
||||
limit: 20,
|
||||
},
|
||||
form: {
|
||||
username: "",
|
||||
name: "",
|
||||
mobile: "",
|
||||
type: 2,
|
||||
},
|
||||
dialogWork: false,
|
||||
dialogCreate: false,
|
||||
item: {},
|
||||
anchors: []
|
||||
}
|
||||
anchors: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.$axios.get('/admin/work/index', { params: this.listQuery }).then(response => {
|
||||
this.list = response.data.data
|
||||
this.total = response.data.total
|
||||
this.oss = response.ext.oss
|
||||
this.listLoading = false
|
||||
}).catch(err => {
|
||||
})
|
||||
this.$axios
|
||||
.get("/admin/liveroom/zhuboStatistics", { params: this.listQuery })
|
||||
.then((response) => {
|
||||
this.list = response.data.data;
|
||||
this.total = response.data.total;
|
||||
this.listLoading = false;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onDel(item) {
|
||||
this.$axios.post('/admin/work/del', {id: item.id}).then(res => {
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
}).catch(err => {
|
||||
|
||||
})
|
||||
this.$axios
|
||||
.post("/admin/work/del", { id: item.id })
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onSave(from) {
|
||||
if(from) {
|
||||
this.$set(from,'date',[new Date(from.start), new Date(from.end)]);
|
||||
this.item = from;
|
||||
this.item.os = from.os+'';
|
||||
this.dialogWork = true;
|
||||
return
|
||||
}
|
||||
this.$axios.post('/admin/work/save', this.item).then(response => {
|
||||
this.dialogWork = false
|
||||
this.getList()
|
||||
}).catch(err => {
|
||||
})
|
||||
},
|
||||
onAdd() {
|
||||
this.$axios.get('/admin/work/anchor').then((res) => {
|
||||
this.anchors = res.data || []
|
||||
this.dialogCreate = true
|
||||
}).catch(err=>{
|
||||
|
||||
})
|
||||
// onSave(from) {
|
||||
// if (from) {
|
||||
// this.$set(from, "date", [new Date(from.start), new Date(from.end)]);
|
||||
// this.item = from;
|
||||
// this.item.os = from.os + "";
|
||||
// this.dialogWork = true;
|
||||
// return;
|
||||
// }
|
||||
// this.$axios
|
||||
// .post("/admin/work/save", this.item)
|
||||
// .then((response) => {
|
||||
// this.dialogWork = false;
|
||||
// this.getList();
|
||||
// })
|
||||
// .catch((err) => {});
|
||||
// },
|
||||
onAdd(item) {
|
||||
// this.anchors = res.data || [];
|
||||
this.dialogCreate = true;
|
||||
this.$nextTick((res) => {
|
||||
this.$refs["form"].resetFields();
|
||||
this.title = item.id ? "编辑" : "添加";
|
||||
this.form = item.id
|
||||
? { ...item }
|
||||
: {
|
||||
username: "",
|
||||
name: "",
|
||||
mobile: "",
|
||||
type: 2,
|
||||
};
|
||||
});
|
||||
},
|
||||
onSaves() {
|
||||
if(this.loading) return
|
||||
this.loading = true
|
||||
this.$axios.post('/admin/work/save2', this.anchors).then(res => {
|
||||
this.dialogCreate = false
|
||||
this.loading = false
|
||||
}).catch(err=> {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$axios
|
||||
.post("/admin/admin/save", this.form)
|
||||
.then((response) => {
|
||||
this.$message({
|
||||
message: "成功",
|
||||
type: "success",
|
||||
});
|
||||
this.dialogCreate = false;
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="getList">
|
||||
搜索
|
||||
</el-button>
|
||||
<!-- <el-button
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList(1)"
|
||||
>
|
||||
导出
|
||||
</el-button> -->
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
|
@ -77,6 +77,17 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="当月核销率(按订单)" width="160">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.month_write_rate }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="180" label="当月核销率(按销售额)">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.month_write_rate_price }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
<span>{{ scope.row.last_work_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="138px" align="center" label="路线">
|
||||
<!-- <el-table-column width="138px" align="center" label="线路">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.last_work_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<el-tag type="border-card">{{ scope.row.routes }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column> -->
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -578,7 +578,7 @@ export default {
|
|||
flowObj: "",
|
||||
os: null, // 初始值,你可以根据需要设置为 1、2 或 3
|
||||
},
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音" },
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音(甄选)", 4:"全平台", 5:"抖音(新国旅)" },
|
||||
adminList: [],
|
||||
form: {},
|
||||
rules: {
|
||||
|
@ -628,12 +628,14 @@ export default {
|
|||
this.$axios
|
||||
.get("/admin/order/index", { params: this.listQuery })
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
this.list = response.data.data;
|
||||
this.total = response.data.total;
|
||||
|
||||
(this.timetype_arr = response.ext.timetype),
|
||||
(this.oss = response.ext.oss);
|
||||
this.listLoading = false;
|
||||
});
|
||||
})
|
||||
},
|
||||
objectToQuery(obj) {
|
||||
return Object.keys(obj)
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<div class="filter-container">
|
||||
<el-input v-model="listQuery.sn" placeholder="订单号" style="width: 300px;" class="filter-item" />
|
||||
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="getList">
|
||||
搜索
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="listLoading" :data="list" border fit highlight-current-row style="width: 100%">
|
||||
|
||||
<el-table-column align="center" fixed width="220" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button v-if="scope.row.self ==0 && scope.row.status == 0" type="primary" size="small" icon="el-icon-check" @click="onPass(scope.row)">
|
||||
确认
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="订单号" width="80" prop="orderInfo.sn" />
|
||||
<el-table-column align="center" label="出游日期" width="80" prop="travel_date" />
|
||||
<el-table-column align="center" label="出游人数" width="80" prop="num" />
|
||||
<el-table-column align="center" label="出行人名称" width="220" prop="name" />
|
||||
<el-table-column align="center" label="联系电话" prop="mobile" />
|
||||
<el-table-column align="center" label="券码图片" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-image
|
||||
style="width: 100px; height: 100px"
|
||||
:src="scope.row.code_pic"
|
||||
:preview-src-list="[scope.row.code_pic]">
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="备注" prop="note" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="listQuery.page"
|
||||
:limit.sync="listQuery.limit"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import Pagination from '@/Wangeditor/Pagination'
|
||||
import Pagination from '@/components/PaginationFixed'
|
||||
|
||||
export default {
|
||||
name: 'Orderlist',
|
||||
components: { Pagination },
|
||||
filters: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 10
|
||||
},
|
||||
oss: {},
|
||||
item: {},
|
||||
dialogVisible: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.$axios.get('/admin/orderbooks/list', { params: this.listQuery }).then(response => {
|
||||
this.list = response.data.data
|
||||
this.total = response.data.total
|
||||
this.oss = response.ext
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
onBack() {
|
||||
this.$axios.post('/admin/order/back', this.item).then(res => {
|
||||
this.dialogVisible = false
|
||||
this.item = {}
|
||||
this.getList()
|
||||
}).catch(err => {
|
||||
|
||||
})
|
||||
},
|
||||
onPass(item) {
|
||||
this.$axios.post('/admin/order/backpass', { id: item.id }).then(res => {
|
||||
this.dialogVisible = false
|
||||
this.item = {}
|
||||
this.getList()
|
||||
}).catch(err => {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.app-container {
|
||||
position: relative;
|
||||
padding-bottom: 60px; /* 分页条的高度 */
|
||||
}
|
||||
|
||||
.filter-container,
|
||||
.el-table {
|
||||
padding-bottom: 52px; /* 分页条的高度,以避免内容重叠 */
|
||||
}
|
||||
</style>
|
|
@ -39,6 +39,8 @@
|
|||
v-model="listQuery.os_status"
|
||||
placeholder="平台状态"
|
||||
:options="oss"
|
||||
clearable
|
||||
:props="{ checkStrictly: true }"
|
||||
class="filter-item"
|
||||
@change="handleChange"
|
||||
/>
|
||||
|
@ -87,13 +89,14 @@
|
|||
<el-select
|
||||
v-model="listQuery.appointment_status"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="预约状态"
|
||||
class="filter-item"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option key="" label="请选择" value="" />
|
||||
<el-option key="1" label="已预约" value="1" />
|
||||
<el-option key="0" label="未预约" value="0" />
|
||||
<el-option key="1" label="已预约(未处理)" value="1" />
|
||||
<el-option key="2" label="已预约(已处理)" value="2" />
|
||||
</el-select>
|
||||
|
||||
<el-button
|
||||
|
@ -122,6 +125,15 @@
|
|||
>
|
||||
核单
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="multipleSelection.length == 0"
|
||||
class="filter-item"
|
||||
icon="el-icon-refresh"
|
||||
@click="onCirculationAll()"
|
||||
>
|
||||
批量流转
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
|
@ -132,7 +144,9 @@
|
|||
highlight-current-row
|
||||
style="width: 100%"
|
||||
:height="tableMaxHeight"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55"> </el-table-column>
|
||||
<el-table-column align="center" fixed width="200" label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button-group>
|
||||
|
@ -167,6 +181,15 @@
|
|||
>
|
||||
同步
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="scope.row.appointment_status == 1"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="onOneClickYyHandle(scope.row)"
|
||||
>
|
||||
预约处理
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -181,7 +204,11 @@
|
|||
<el-table-column align="center" fixed label="电话" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.mobile }}</span>
|
||||
<span style="display:block;font-size: 12px;">{{ scope.row.mobileInfo.area }}-{{ scope.row.mobileInfo.originalIsp }}</span>
|
||||
<span style="display: block; font-size: 12px"
|
||||
>{{ scope.row.mobileInfo.area }}-{{
|
||||
scope.row.mobileInfo.originalIsp
|
||||
}}</span
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
@ -234,7 +261,13 @@
|
|||
}"
|
||||
type="primary"
|
||||
>
|
||||
{{ scope.row.appointment_status == 1 ? '已预约' : '未预约' }}
|
||||
{{
|
||||
scope.row.appointment_status == 1
|
||||
? "已预约(未处理)"
|
||||
: scope.row.appointment_status == 2
|
||||
? "已预约(已处理)"
|
||||
: "未预约"
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -424,7 +457,7 @@
|
|||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="出游日期">
|
||||
<el-form-item required pros="travel_date" label="出游日期">
|
||||
<el-date-picker
|
||||
v-model="item.travel_date"
|
||||
type="date"
|
||||
|
@ -440,7 +473,12 @@
|
|||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="下次跟进时间" v-if="item.status !== 2">
|
||||
<el-form-item
|
||||
required
|
||||
pros="next_follow"
|
||||
label="下次跟进时间"
|
||||
v-if="item.status !== 2"
|
||||
>
|
||||
<el-date-picker
|
||||
v-model="next_follow"
|
||||
type="datetime"
|
||||
|
@ -470,7 +508,7 @@
|
|||
</el-select>
|
||||
</el-form-item>-->
|
||||
|
||||
<el-form-item label="跟进说明">
|
||||
<el-form-item required pros="desc" label="跟进说明">
|
||||
<el-input v-model="item.desc" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@ -538,10 +576,10 @@
|
|||
|
||||
<el-dialog title="申请转出订单" :visible.sync="applyVisible">
|
||||
<el-form label-width="160px" :model="item3" :rules="rules" ref="ruleForm">
|
||||
<el-form-item label="标题:">
|
||||
<el-form-item label="标题:" v-if="!isAll">
|
||||
<el-input v-model="item3.product_name" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号:">
|
||||
<el-form-item label="订单号:" v-if="!isAll">
|
||||
<el-input v-model="item3.sn" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="流转对象:" style="width: 600px" prop="flowObj">
|
||||
|
@ -590,7 +628,7 @@
|
|||
<script>
|
||||
// import Pagination from '@/Wangeditor/Pagination'
|
||||
import Pagination from "@/components/PaginationFixed";
|
||||
import { orderBack } from "@/api/order";
|
||||
import { orderBack, orderbackBatch } from "@/api/order";
|
||||
export default {
|
||||
name: "Orderlist",
|
||||
components: { Pagination },
|
||||
|
@ -642,8 +680,9 @@ export default {
|
|||
admin: null,
|
||||
zhubo: null,
|
||||
os_status: [],
|
||||
appointment_status: "",
|
||||
},
|
||||
item: { next_follow: "", personnel: {} },
|
||||
item: { next_follow: "", personnel: { adult: "" } },
|
||||
follow: [],
|
||||
|
||||
dialogVisible: false,
|
||||
|
@ -657,9 +696,12 @@ export default {
|
|||
flowObj: "",
|
||||
os: null, // 初始值,你可以根据需要设置为 1、2 或 3
|
||||
},
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音" },
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音(甄选)", 5: "抖音(新国旅)" },
|
||||
multipleSelection: [],
|
||||
sn: [],
|
||||
adminList: [],
|
||||
form: {},
|
||||
isAll: false,
|
||||
rules: {
|
||||
flowObj: [
|
||||
{ required: true, message: "请选择流转对象", trigger: "change" },
|
||||
|
@ -673,21 +715,47 @@ export default {
|
|||
if (this.$route.query.start && this.$route.query.end) {
|
||||
this.listQuery.times = [this.$route.query.start, this.$route.query.end];
|
||||
}
|
||||
// console.log(typeof this.$route.params.id);
|
||||
this.setQuery("status");
|
||||
this.setQuery("os_status");
|
||||
this.setQuery("times");
|
||||
await this.getList();
|
||||
await this.setOneClickRepair();
|
||||
await this.getList();
|
||||
this.setQuery("appointment_status");
|
||||
// await this.getList();
|
||||
// if (!this.$route.query.id) {
|
||||
// await this.setOneClickRepair();
|
||||
// await this.getList();
|
||||
// }
|
||||
this.getShortcutContent();
|
||||
this.getAdminList();
|
||||
},
|
||||
computed: {
|
||||
tableMaxHeight() {
|
||||
return window.innerHeight - 320 + 'px';
|
||||
mounted() {
|
||||
console.log(this.$route.query);
|
||||
this.setMode();
|
||||
if (this.$route.query.id) {
|
||||
this.onInfo({ id: this.$route.query.id });
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableMaxHeight() {
|
||||
return window.innerHeight - 320 + "px";
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.onInfo({ id: this.$route.query.id });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(val) {
|
||||
// console.log(val);
|
||||
|
||||
this.multipleSelection = val;
|
||||
const data = [];
|
||||
this.multipleSelection.map((item) => {
|
||||
data.push(item.sn);
|
||||
});
|
||||
this.sn = data;
|
||||
},
|
||||
setQuery(key) {
|
||||
if (this.$route.query.hasOwnProperty(key)) {
|
||||
this.listQuery[key] = this.$route.query[key];
|
||||
|
@ -746,7 +814,7 @@ export default {
|
|||
this.value = null;
|
||||
this.next_follow = null;
|
||||
this.$set(item, "next_follow", null);
|
||||
this.item = item;
|
||||
// this.item = item;
|
||||
this.active = "follow";
|
||||
this.$axios
|
||||
.get("/admin/order/info", { params: { id: item.id } })
|
||||
|
@ -759,10 +827,10 @@ export default {
|
|||
resetForm(formName) {
|
||||
this.$refs[formName].resetFields();
|
||||
},
|
||||
getAdminList(typeDesc = '') {
|
||||
getAdminList(typeDesc = "") {
|
||||
this.$axios
|
||||
.get("/admin/admin/index", {
|
||||
params: { limit: 100, status: 1, is_order: 1, type_desc:typeDesc },
|
||||
params: { limit: 100, status: 1, is_order: 1, type_desc: typeDesc },
|
||||
})
|
||||
.then((response) => {
|
||||
this.adminList = response.data.data;
|
||||
|
@ -773,6 +841,7 @@ export default {
|
|||
onCirculation(item) {
|
||||
this.getAdminList(item.category_desc);
|
||||
this.applyVisible = true;
|
||||
this.isAll = false;
|
||||
this.item3 = { ...item, os: Number(item.os) };
|
||||
console.log(this.item3);
|
||||
if (this.item3.backs && this.item3.backs.admin_id) {
|
||||
|
@ -781,18 +850,52 @@ export default {
|
|||
this.resetForm("ruleForm");
|
||||
}
|
||||
},
|
||||
// 批量设置
|
||||
onCirculationAll() {
|
||||
this.applyVisible = true;
|
||||
this.isAll = true;
|
||||
},
|
||||
//确定
|
||||
onCirculationSave(to_admin_id) {
|
||||
this.$refs.ruleForm.validate((valid) => {
|
||||
this.$refs.ruleForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
orderBack({
|
||||
sn: this.item3.sn,
|
||||
os: this.item3.os,
|
||||
to_admin_id: to_admin_id,
|
||||
}).then((res) => {
|
||||
this.applyVisible = false;
|
||||
this.getList();
|
||||
});
|
||||
let res;
|
||||
if (this.isAll) {
|
||||
this.$confirm("是否批量流转订单", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
res = await orderbackBatch({
|
||||
sn: this.sn,
|
||||
to_admin_id: to_admin_id,
|
||||
});
|
||||
if (res.data) {
|
||||
this.$message({
|
||||
message: "批量流转订单成功",
|
||||
type: "success",
|
||||
});
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res = await orderBack({
|
||||
sn: this.item3.sn,
|
||||
os: this.item3.os,
|
||||
to_admin_id: to_admin_id,
|
||||
});
|
||||
if (res.data) {
|
||||
this.$message({
|
||||
message: "流转订单成功",
|
||||
type: "success",
|
||||
});
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -806,6 +909,7 @@ export default {
|
|||
.post("/admin/order/backcancel", { id: this.item3.id })
|
||||
.then((res) => {
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
|
@ -827,8 +931,6 @@ export default {
|
|||
.catch((err) => {});
|
||||
},
|
||||
onSave(item) {
|
||||
console.log(this.next_follow);
|
||||
|
||||
this.$axios
|
||||
.post("/admin/order/save", {
|
||||
id: item.id,
|
||||
|
@ -843,7 +945,10 @@ export default {
|
|||
})
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.item = { next_follow: "", personnel: {} };
|
||||
this.item = { next_follow: "", personnel: { adult: "" } };
|
||||
this.$router.push({
|
||||
path: "/order/index",
|
||||
});
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
|
@ -890,7 +995,6 @@ export default {
|
|||
this.$axios
|
||||
.post("/admin/order/oneClickRepair", { id: item.id })
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "同步完成",
|
||||
|
@ -898,6 +1002,25 @@ export default {
|
|||
});
|
||||
// this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify.error({
|
||||
title: "同步失败",
|
||||
message: err,
|
||||
});
|
||||
});
|
||||
},
|
||||
onOneClickYyHandle(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/changeAppointmentStatus", { id: item.id })
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "已处理",
|
||||
type: "success",
|
||||
});
|
||||
// this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify.error({
|
||||
title: "错误",
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
搜索
|
||||
</el-button>
|
||||
|
||||
<!-- <el-button
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList(1)"
|
||||
>
|
||||
导出
|
||||
</el-button> -->
|
||||
</el-button>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
|||
<el-tag type="warning" v-if="scope.row.os === 1">美团</el-tag>
|
||||
<el-tag type="success" v-if="scope.row.os === 2">快手</el-tag>
|
||||
<el-tag type="primary" v-if="scope.row.os === 3">抖音</el-tag>
|
||||
<el-tag type="primary" v-if="scope.row.os === 5">抖音(新国旅)</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
@ -144,6 +145,9 @@ export default {
|
|||
}, {
|
||||
value: '3',
|
||||
label: '抖音'
|
||||
}, {
|
||||
value: '5',
|
||||
label: '抖音(新国旅)'
|
||||
}],
|
||||
form: {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,992 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div class="filter-container">
|
||||
<el-input
|
||||
v-model="listQuery.sn"
|
||||
placeholder="订单号"
|
||||
style="width: 200px"
|
||||
class="filter-item"
|
||||
/>
|
||||
<el-input
|
||||
v-model="listQuery.product_name"
|
||||
placeholder="标题"
|
||||
style="width: 200px"
|
||||
class="filter-item"
|
||||
/>
|
||||
|
||||
<el-input
|
||||
v-model="listQuery.mobile"
|
||||
placeholder="手机号"
|
||||
style="width: 200px"
|
||||
class="filter-item"
|
||||
/>
|
||||
|
||||
<el-input
|
||||
v-model="listQuery.zhubo"
|
||||
placeholder="主播"
|
||||
style="width: 100px"
|
||||
class="filter-item"
|
||||
/>
|
||||
|
||||
<el-input
|
||||
v-model="listQuery.admin"
|
||||
placeholder="客服"
|
||||
style="width: 100px"
|
||||
class="filter-item"
|
||||
/>
|
||||
|
||||
<!-- <el-cascader
|
||||
v-model="listQuery.os_status"
|
||||
placeholder="平台状态"
|
||||
:options="oss"
|
||||
clearable
|
||||
:props="{ checkStrictly: true }"
|
||||
class="filter-item"
|
||||
@change="handleChange"
|
||||
/> -->
|
||||
|
||||
<el-select
|
||||
v-model="listQuery.status"
|
||||
filterable
|
||||
placeholder="跟进状态"
|
||||
class="filter-item"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option key="" label="请选择" value="" />
|
||||
<el-option
|
||||
v-for="(v, k) in status_arr"
|
||||
:key="k"
|
||||
:label="v"
|
||||
:value="k"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-select
|
||||
v-model="listQuery.timetype"
|
||||
filterable
|
||||
placeholder="时间"
|
||||
class="filter-item"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option key="" label="请选择" value="" />
|
||||
<el-option
|
||||
v-for="(v, k) in timetype_arr"
|
||||
:key="k"
|
||||
:label="v"
|
||||
:value="k"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-date-picker
|
||||
v-model="listQuery.times"
|
||||
class="filter-item"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
end-placeholder="结束日期"
|
||||
/>
|
||||
<el-select
|
||||
v-model="listQuery.appointment_status"
|
||||
filterable
|
||||
clearable
|
||||
placeholder="预约状态"
|
||||
class="filter-item"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option key="0" label="未预约" value="0" />
|
||||
<el-option key="1" label="已预约(未处理)" value="1" />
|
||||
<el-option key="2" label="已预约(已处理)" value="2" />
|
||||
</el-select>
|
||||
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="getList(1)"
|
||||
>
|
||||
导出
|
||||
</el-button>
|
||||
|
||||
<!-- <el-button
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
@click="dialog2Visible = true"
|
||||
>
|
||||
核单
|
||||
</el-button> -->
|
||||
<!-- <el-button
|
||||
type="primary"
|
||||
:disabled="multipleSelection.length == 0"
|
||||
class="filter-item"
|
||||
icon="el-icon-refresh"
|
||||
@click="onCirculationAll()"
|
||||
>
|
||||
批量流转
|
||||
</el-button> -->
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="listLoading"
|
||||
:data="list"
|
||||
border
|
||||
fit
|
||||
highlight-current-row
|
||||
style="width: 100%"
|
||||
:height="tableMaxHeight"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55"> </el-table-column>
|
||||
<el-table-column align="center" fixed label="电话" width="140">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.mobile }}</span>
|
||||
<span style="display: block; font-size: 12px"
|
||||
>{{ scope.row.mobileInfo.area }}-{{
|
||||
scope.row.mobileInfo.originalIsp
|
||||
}}</span
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
fixed
|
||||
label="平台"
|
||||
width="80"
|
||||
prop="os_name"
|
||||
/>
|
||||
|
||||
<el-table-column align="center" fixed label="直播" width="60">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.is_zhibo">是</el-tag>
|
||||
<el-tag v-else type="info">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
fixed
|
||||
label="客服"
|
||||
width="80"
|
||||
prop="admin.username"
|
||||
/>
|
||||
|
||||
<el-table-column align="center" label="订单号" width="180" prop="sn" />
|
||||
|
||||
<el-table-column width="138px" align="center" label="下单时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.create_at | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="160px" align="center" label="派单时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.give_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="预约状态(抖音)" width="80">
|
||||
<template slot-scope="scope">
|
||||
<div
|
||||
style="padding: 1px 5px; border-radius: 3px"
|
||||
:style="{
|
||||
color: order_status[scope.row.appointment_status],
|
||||
border: `1px solid ${order_status[scope.row.appointment_status]}`,
|
||||
}"
|
||||
type="primary"
|
||||
>
|
||||
{{
|
||||
scope.row.appointment_status == 1
|
||||
? "已预约(未处理)"
|
||||
: scope.row.appointment_status == 2
|
||||
? "已预约(已处理)"
|
||||
: "未预约"
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<div
|
||||
style="padding: 1px 5px; border-radius: 3px"
|
||||
:style="{
|
||||
color: order_status[scope.row.order_status],
|
||||
border: `1px solid ${order_status[scope.row.order_status]}`,
|
||||
}"
|
||||
type="primary"
|
||||
>
|
||||
{{ scope.row.order_status_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="跟进状态" width="90">
|
||||
<template slot-scope="scope">
|
||||
<div
|
||||
style="padding: 1px 5px; border-radius: 3px"
|
||||
:style="{
|
||||
color: follow_status[scope.row.status],
|
||||
border: `1px solid ${follow_status[scope.row.status]}`,
|
||||
}"
|
||||
type="primary"
|
||||
>
|
||||
{{ scope.row.status_name }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
width="500px"
|
||||
label="标题"
|
||||
prop="product_name"
|
||||
/>
|
||||
<el-table-column
|
||||
width="500px"
|
||||
align="center"
|
||||
label="跟进备注"
|
||||
prop="remark"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="联系人"
|
||||
width="120"
|
||||
prop="contact"
|
||||
/>
|
||||
|
||||
<!-- <el-table-column align="center" label="微信" width="80">
|
||||
<template slot-scope="scope">
|
||||
<i v-if="scope.row.is_wechat>0" class="el-icon-circle-check"></i>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
|
||||
<el-table-column width="138px" align="center" label="出行时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.travel_date | parseTime("{y}-{m}-{d}") }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column width="138px" align="center" label="最后跟进时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.last_follow | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="核单" width="80">
|
||||
<template slot-scope="scope">
|
||||
<i v-if="scope.row.is_check == 1" class="el-icon-check" />
|
||||
<i v-if="scope.row.is_check == 2" class="el-icon-close" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="center"
|
||||
width="138px"
|
||||
label="分类"
|
||||
prop="category_desc"
|
||||
/>
|
||||
|
||||
<el-table-column align="center" label="总金额" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.total_price / 100 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
align="center"
|
||||
width="80px"
|
||||
label="人数"
|
||||
prop="quantity"
|
||||
/>
|
||||
<el-table-column
|
||||
align="center"
|
||||
label="主播"
|
||||
width="80"
|
||||
prop="anchor.username"
|
||||
/>
|
||||
<el-table-column width="138px" align="center" label="修改时间">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.update_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="listQuery.page"
|
||||
:limit.sync="listQuery.limit"
|
||||
@pagination="setMode"
|
||||
/>
|
||||
|
||||
<el-dialog title="订单跟进" :visible.sync="dialogVisible">
|
||||
<el-form label-width="130px" :model="item">
|
||||
<el-form-item label="产品名称">
|
||||
{{ item.product_name }}
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品状态">
|
||||
{{ item.order_status_name }}
|
||||
</el-form-item>
|
||||
<el-form-item label="数量">
|
||||
{{ item.quantity }}
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
{{ item.contact }}
|
||||
</el-form-item>
|
||||
<el-form-item label="手机">
|
||||
{{ item.mobile }}
|
||||
</el-form-item>
|
||||
<el-form-item label="下单时间">
|
||||
{{ item.create_at | parseTime("{y}-{m}-{d} {h}:{i}") }}
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="人员">
|
||||
<el-row>
|
||||
<el-col :span="3">大人</el-col>
|
||||
<el-col :span="5"
|
||||
><el-input
|
||||
v-model="item.personnel.adult"
|
||||
name="adult"
|
||||
placeholder="大人"
|
||||
/></el-col>
|
||||
<el-col :span="3">老人</el-col>
|
||||
<el-col :span="5"
|
||||
><el-input
|
||||
v-model="item.personnel.old"
|
||||
name="old"
|
||||
placeholder="老人"
|
||||
/></el-col>
|
||||
<el-col :span="3">小孩</el-col>
|
||||
<el-col :span="5"
|
||||
><el-input
|
||||
v-model="item.personnel.child"
|
||||
name="child"
|
||||
placeholder="小孩"
|
||||
/></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="item.status !== 1" label="核销码">
|
||||
<el-input
|
||||
v-model="item.check_sn"
|
||||
name="check_sn"
|
||||
placeholder="请输入平台核销码"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="加微信" v-if="item.status !== 2">
|
||||
<el-checkbox
|
||||
v-model="item.is_wechat"
|
||||
:true-label="1"
|
||||
:false-label="0"
|
||||
>已加微信</el-checkbox
|
||||
>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item required pros="travel_date" label="出游日期">
|
||||
<el-date-picker
|
||||
v-model="item.travel_date"
|
||||
type="date"
|
||||
placeholder="选择日期时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="item.status !== 1" label="返回日期">
|
||||
<el-date-picker
|
||||
v-model="item.travel_end"
|
||||
type="date"
|
||||
placeholder="选择日期时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
required
|
||||
pros="next_follow"
|
||||
label="下次跟进时间"
|
||||
v-if="item.status !== 2"
|
||||
>
|
||||
<el-date-picker
|
||||
v-model="next_follow"
|
||||
type="datetime"
|
||||
placeholder="选择日期时间"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="跟进状态">
|
||||
<template v-for="(v, k) in status_arr">
|
||||
<el-radio v-if="k > 0" v-model="item.status" :label="k" border>{{
|
||||
v
|
||||
}}</el-radio>
|
||||
</template>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="快捷跟进" style="width: 600px;">
|
||||
<el-select v-model="value" placeholder="请选择" @change="onChange">
|
||||
<el-form-item style="display: inline-flex;text-align: left;width: 770px;">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
style="width: 250px;display: inline-flex;word-break: break-all;"
|
||||
:label="item.label"
|
||||
:value="item.label"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-select>
|
||||
</el-form-item>-->
|
||||
|
||||
<el-form-item required pros="desc" label="跟进说明">
|
||||
<el-input v-model="item.desc" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="onSave(item)">保 存</el-button>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="active" type="border-card">
|
||||
<el-tab-pane name="follow" label="跟进记录">
|
||||
<el-table :data="item.follow" style="width: 100%">
|
||||
<el-table-column label="日期" width="138">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.create_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="跟进人" width="110" prop="name" />
|
||||
<el-table-column label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ status_arr[scope.row.status] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="desc" label="跟进说明" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="finance" label="财务记录">
|
||||
<el-table :data="item.finance" style="width: 100%">
|
||||
<el-table-column label="日期">
|
||||
<template slot-scope="scope">
|
||||
<span>{{
|
||||
scope.row.create_time | parseTime("{y}-{m}-{d} {h}:{i}")
|
||||
}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" width="110">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ type_arr[scope.row.type] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.total / 100 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="纯核销" :visible.sync="dialog2Visible">
|
||||
<el-form label-width="160px" :model="form">
|
||||
<el-form-item label="平台">
|
||||
<el-radio v-model="form.os" label="1">美团</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item label="核销码">
|
||||
<el-input v-model="form.check_sn" placeholder="请输入平台核销码" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="onPass(form)">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="申请转出订单" :visible.sync="applyVisible">
|
||||
<el-form label-width="160px" :model="item3" :rules="rules" ref="ruleForm">
|
||||
<el-form-item label="标题:" v-if="!isAll">
|
||||
<el-input v-model="item3.product_name" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单号:" v-if="!isAll">
|
||||
<el-input v-model="item3.sn" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="流转对象:" style="width: 600px" prop="flowObj">
|
||||
<el-select
|
||||
v-model="item3.flowObj"
|
||||
placeholder="请选择"
|
||||
@change="onChange2"
|
||||
>
|
||||
<el-form-item
|
||||
style="display: inline-flex; text-align: left; width: 770px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in adminList"
|
||||
:key="item.value"
|
||||
style="
|
||||
width: 250px;
|
||||
display: inline-flex;
|
||||
word-break: break-all;
|
||||
"
|
||||
:label="item.username"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<!-- scope.row.backs&&scope.row.backs.status==2? -->
|
||||
<el-button
|
||||
v-if="item3.backs && item3.backs.status == 0"
|
||||
type="primary"
|
||||
@click="onCancel(item3.flowObj)"
|
||||
>取 消</el-button
|
||||
>
|
||||
<el-button
|
||||
v-else
|
||||
type="primary"
|
||||
@click="onCirculationSave(item3.flowObj)"
|
||||
>确 认</el-button
|
||||
>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import Pagination from '@/Wangeditor/Pagination'
|
||||
import Pagination from "@/components/PaginationFixed";
|
||||
import { orderBack, orderbackBatch } from "@/api/order";
|
||||
export default {
|
||||
name: "Orderlist",
|
||||
components: { Pagination },
|
||||
data() {
|
||||
return {
|
||||
active: "follow",
|
||||
types: {
|
||||
0: "",
|
||||
1: "",
|
||||
2: "",
|
||||
3: "primary",
|
||||
4: "success",
|
||||
5: "warning",
|
||||
6: "danger",
|
||||
7: "info",
|
||||
},
|
||||
types2: { 1: "primary", 2: "success", 3: "warning" },
|
||||
status_arr: ["待跟进", "跟进中", "已核销", "核销失败", "放弃跟单"],
|
||||
type_arr: ["-", "收益", "支出"],
|
||||
timetype_arr: {},
|
||||
order_status: [
|
||||
"#9e9f9c",
|
||||
"#04bcd9",
|
||||
"#fc9904",
|
||||
"#1193f4",
|
||||
"#48b14b",
|
||||
"#eb1662",
|
||||
"#9d1cb5",
|
||||
],
|
||||
follow_status: [
|
||||
"#9e9f9c",
|
||||
"#04bcd9",
|
||||
"#fc9904",
|
||||
"#1193f4",
|
||||
"#48b14b",
|
||||
"#eb1662",
|
||||
],
|
||||
options: [],
|
||||
value: null,
|
||||
next_follow: null,
|
||||
list: [],
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
times: [],
|
||||
status: null,
|
||||
admin: null,
|
||||
zhubo: null,
|
||||
os_status: [],
|
||||
appointment_status: "",
|
||||
},
|
||||
item: { next_follow: "", personnel: { adult: "" } },
|
||||
follow: [],
|
||||
|
||||
dialogVisible: false,
|
||||
dialog2Visible: false,
|
||||
applyVisible: false,
|
||||
oss: [],
|
||||
isSynchronization: false,
|
||||
item3: {
|
||||
sn: null,
|
||||
backs: null,
|
||||
flowObj: "",
|
||||
os: null, // 初始值,你可以根据需要设置为 1、2 或 3
|
||||
},
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音(甄选)", 5: "抖音(新国旅)" },
|
||||
multipleSelection: [],
|
||||
sn: [],
|
||||
adminList: [],
|
||||
form: {},
|
||||
isAll: false,
|
||||
rules: {
|
||||
flowObj: [
|
||||
{ required: true, message: "请选择流转对象", trigger: "change" },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
// this.listQuery.status = this.$route.query.status || null
|
||||
this.listQuery.zhubo = this.$route.query.zhubo || null;
|
||||
if (this.$route.query.start && this.$route.query.end) {
|
||||
this.listQuery.times = [this.$route.query.start, this.$route.query.end];
|
||||
}
|
||||
// console.log(typeof this.$route.params.id);
|
||||
this.setQuery("status");
|
||||
this.setQuery("os_status");
|
||||
this.setQuery("times");
|
||||
this.setQuery("appointment_status");
|
||||
// await this.getList();
|
||||
// if (!this.$route.query.id) {
|
||||
// await this.setOneClickRepair();
|
||||
// await this.getList();
|
||||
// }
|
||||
this.getShortcutContent();
|
||||
this.getAdminList();
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.$route.query);
|
||||
this.setMode();
|
||||
if (this.$route.query.id) {
|
||||
this.onInfo({ id: this.$route.query.id });
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableMaxHeight() {
|
||||
return window.innerHeight - 320 + "px";
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.onInfo({ id: this.$route.query.id });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSelectionChange(val) {
|
||||
// console.log(val);
|
||||
|
||||
this.multipleSelection = val;
|
||||
const data = [];
|
||||
this.multipleSelection.map((item) => {
|
||||
data.push(item.sn);
|
||||
});
|
||||
this.sn = data;
|
||||
},
|
||||
setQuery(key) {
|
||||
if (this.$route.query.hasOwnProperty(key)) {
|
||||
this.listQuery[key] = this.$route.query[key];
|
||||
} else {
|
||||
this.listQuery[key] = "";
|
||||
}
|
||||
},
|
||||
async setMode() {
|
||||
await this.getList();
|
||||
// await this.setOneClickRepair();
|
||||
// await this.getList();
|
||||
},
|
||||
async setOneClickRepair() {
|
||||
let arr = this.list.map((res) => {
|
||||
return res.id;
|
||||
});
|
||||
await this.onOneClickRepair({ id: arr.join() });
|
||||
},
|
||||
async getList($is_excel) {
|
||||
this.listQuery.excel = null;
|
||||
this.listQuery.is_refunded = 1;
|
||||
if ($is_excel == 1) {
|
||||
this.listQuery.excel = 1;
|
||||
const isdate = this.listQuery.times[0] instanceof Date;
|
||||
const params = {
|
||||
...this.listQuery,
|
||||
times: [
|
||||
isdate ? this.listQuery.times[0].toISOString() : "",
|
||||
isdate ? this.listQuery.times[1].toISOString() : "",
|
||||
],
|
||||
};
|
||||
window.open("/admin/order/index?" + this.objectToQuery(params));
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$axios
|
||||
.get("/admin/order/index", { params: this.listQuery })
|
||||
.then((response) => {
|
||||
this.list = response.data.data;
|
||||
this.total = response.data.total;
|
||||
(this.timetype_arr = response.ext.timetype),
|
||||
(this.oss = response.ext.oss);
|
||||
this.listLoading = false;
|
||||
this.isSynchronization = true;
|
||||
});
|
||||
},
|
||||
objectToQuery(obj) {
|
||||
return Object.keys(obj)
|
||||
.map((key) => {
|
||||
const value = obj[key];
|
||||
if (value == undefined || value == null) return "";
|
||||
return encodeURIComponent(key) + "=" + encodeURIComponent(value);
|
||||
})
|
||||
.join("&");
|
||||
},
|
||||
onInfo(item) {
|
||||
this.value = null;
|
||||
this.next_follow = null;
|
||||
this.$set(item, "next_follow", null);
|
||||
// this.item = item;
|
||||
this.active = "follow";
|
||||
this.$axios
|
||||
.get("/admin/order/info", { params: { id: item.id } })
|
||||
.then((res) => {
|
||||
this.item = res.data;
|
||||
this.dialogVisible = true;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
resetForm(formName) {
|
||||
this.$refs[formName].resetFields();
|
||||
},
|
||||
getAdminList(typeDesc = "") {
|
||||
this.$axios
|
||||
.get("/admin/admin/index", {
|
||||
params: { limit: 100, status: 1, is_order: 1, type_desc: typeDesc },
|
||||
})
|
||||
.then((response) => {
|
||||
this.adminList = response.data.data;
|
||||
this.listLoading = false;
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onCirculation(item) {
|
||||
this.getAdminList(item.category_desc);
|
||||
this.applyVisible = true;
|
||||
this.isAll = false;
|
||||
this.item3 = { ...item, os: Number(item.os) };
|
||||
console.log(this.item3);
|
||||
if (this.item3.backs && this.item3.backs.admin_id) {
|
||||
this.item3.flowObj = this.item3.backs.admin_id;
|
||||
} else {
|
||||
this.resetForm("ruleForm");
|
||||
}
|
||||
},
|
||||
// 批量设置
|
||||
onCirculationAll() {
|
||||
this.applyVisible = true;
|
||||
this.isAll = true;
|
||||
},
|
||||
//确定
|
||||
onCirculationSave(to_admin_id) {
|
||||
this.$refs.ruleForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
let res;
|
||||
if (this.isAll) {
|
||||
this.$confirm("是否批量流转订单", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(async () => {
|
||||
res = await orderbackBatch({
|
||||
sn: this.sn,
|
||||
to_admin_id: to_admin_id,
|
||||
});
|
||||
if (res.data) {
|
||||
this.$message({
|
||||
message: "批量流转订单成功",
|
||||
type: "success",
|
||||
});
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res = await orderBack({
|
||||
sn: this.item3.sn,
|
||||
os: this.item3.os,
|
||||
to_admin_id: to_admin_id,
|
||||
});
|
||||
if (res.data) {
|
||||
this.$message({
|
||||
message: "流转订单成功",
|
||||
type: "success",
|
||||
});
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 取消
|
||||
onCancel() {
|
||||
this.$refs.ruleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$axios
|
||||
.post("/admin/order/backcancel", { id: this.item3.id })
|
||||
.then((res) => {
|
||||
this.applyVisible = false;
|
||||
this.isAll = false;
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
onBack() {
|
||||
this.$axios
|
||||
.post("/admin/order/back", this.item)
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.item = {};
|
||||
this.getList();
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onSave(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/save", {
|
||||
id: item.id,
|
||||
check_sn: item.check_sn,
|
||||
is_wechat: item.is_wechat,
|
||||
travel_end: item.travel_end,
|
||||
travel_date: item.travel_date,
|
||||
desc: item.desc,
|
||||
status: item.status,
|
||||
next_follow: this.next_follow,
|
||||
personnel: this.item.personnel,
|
||||
})
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.item = { next_follow: "", personnel: { adult: "" } };
|
||||
this.$router.push({
|
||||
path: "/order/index",
|
||||
});
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onPass(form) {
|
||||
this.$axios
|
||||
.post("/admin/order/pass", { check_sn: form.check_sn })
|
||||
.then((res) => {
|
||||
this.dialog2Visible = false;
|
||||
this.form = {};
|
||||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
onChange(from) {
|
||||
this.$set(
|
||||
this.item,
|
||||
"desc",
|
||||
from + (this.item.desc != undefined ? this.item.desc : "")
|
||||
);
|
||||
},
|
||||
onChange2(from) {
|
||||
this.$set(
|
||||
this.item,
|
||||
"to_admin_id",
|
||||
from + (this.item.admin_id != undefined ? this.item.admin_id : "")
|
||||
);
|
||||
},
|
||||
handleChange(os) {
|
||||
console.log(os);
|
||||
},
|
||||
getShortcutContent() {
|
||||
this.listLoading = true;
|
||||
this.$axios
|
||||
.get("/admin/shortcutContent/list", {
|
||||
params: { page: 1, limit: 50, status: 1 },
|
||||
})
|
||||
.then((response) => {
|
||||
for (const r of response.data.data) {
|
||||
this.options.push({ value: r.id, label: r.content });
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
onOneClickRepair(item) {
|
||||
// this.$axios
|
||||
// .post("/admin/order/oneClickRepair", { id: item.id })
|
||||
// .then((res) => {
|
||||
// this.$notify({
|
||||
// title: "成功",
|
||||
// message: "同步完成",
|
||||
// type: "success",
|
||||
// });
|
||||
// // this.getList();
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// this.$notify.error({
|
||||
// title: "同步失败",
|
||||
// message: err,
|
||||
// });
|
||||
// });
|
||||
},
|
||||
onOneClickYyHandle(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/changeAppointmentStatus", { id: item.id })
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "已处理",
|
||||
type: "success",
|
||||
});
|
||||
// this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify.error({
|
||||
title: "错误",
|
||||
message: err,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
position: relative;
|
||||
padding-bottom: 60px; /* 分页条的高度 */
|
||||
}
|
||||
|
||||
.filter-container,
|
||||
.el-table {
|
||||
padding-bottom: 5px; /* 分页条的高度,以避免内容重叠 */
|
||||
}
|
||||
</style>
|
|
@ -578,7 +578,7 @@ export default {
|
|||
flowObj: "",
|
||||
os: null, // 初始值,你可以根据需要设置为 1、2 或 3
|
||||
},
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音" },
|
||||
os_arr: { 1: "美团", 2: "快手", 3: "抖音(甄选)", 5:"抖音(新国旅)"},
|
||||
adminList: [],
|
||||
form: {},
|
||||
rules: {
|
||||
|
|
|
@ -3,9 +3,19 @@
|
|||
<el-row>
|
||||
<el-col :span="24">
|
||||
<div class="problem_form">
|
||||
<el-form :inline="true" ref="form" :model="dataForm" label-width="60px">
|
||||
<el-form
|
||||
:inline="true"
|
||||
ref="form"
|
||||
:model="dataForm"
|
||||
label-width="60px"
|
||||
>
|
||||
<el-form-item label="关键字:">
|
||||
<el-input v-model="dataForm.keyword" placeholder="请输入搜索关键字" style="width: 400px;" class="filter-item" />
|
||||
<el-input
|
||||
v-model="dataForm.keyword"
|
||||
placeholder="请输入搜索关键字"
|
||||
style="width: 400px"
|
||||
class="filter-item"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="onSubmit">查询</el-button>
|
||||
|
@ -15,26 +25,58 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
<div class="problem_container">
|
||||
<div class="problem_left" v-infinite-scroll="load" :infinite-scroll-immediate="false" style="overflow:auto;padding: 10px;">
|
||||
<div @click="handleQacityl(item.city_id)" class="btn" v-for="item in getQaCityList">{{ item.city_name }}</div>
|
||||
<div
|
||||
class="problem_left"
|
||||
v-infinite-scroll="load"
|
||||
:infinite-scroll-immediate="false"
|
||||
style="overflow: auto; padding: 10px"
|
||||
>
|
||||
<div
|
||||
@click="handleQacityl(item.city_id)"
|
||||
class="btn"
|
||||
v-for="item in getQaCityList"
|
||||
>
|
||||
{{ item.city_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="problem_right">
|
||||
<ul class="infinite-list" v-infinite-scroll="load" :infinite-scroll-immediate="false" style="overflow:auto">
|
||||
<ul
|
||||
class="infinite-list"
|
||||
v-infinite-scroll="load"
|
||||
:infinite-scroll-immediate="false"
|
||||
style="overflow: auto"
|
||||
>
|
||||
<li class="problem_right_container" v-for="item in getQaLists">
|
||||
<div class="title">
|
||||
<span v-html="handleprant(item.title)"></span>
|
||||
<!-- <el-button @click="handleZip(item.img_zip)" type="primary">下载图片</el-button>
|
||||
<el-button @click="handleZip(item.trip_zip)" type="primary">下载行程</el-button> -->
|
||||
<el-button @click="showImgDialog(item.img_zip)" type="primary">下载图片</el-button>
|
||||
<el-button @click="showFileList(item.trip_zip)" type="primary" style="margin-left: 10px;">下载行程</el-button>
|
||||
<el-button @click="showImgDialog(item.img_zip)" type="primary"
|
||||
>下载图片</el-button
|
||||
>
|
||||
<el-button
|
||||
@click="showFileList(item.trip_zip)"
|
||||
type="primary"
|
||||
style="margin-left: 10px"
|
||||
>下载行程</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="desc_container" v-for="list in item.qaQuestions">
|
||||
<span style="font-weight: 700;color: #46a6ff;" class="desc" v-html="handleprant(list.title)">
|
||||
<span
|
||||
style="font-weight: 700; color: #46a6ff"
|
||||
class="desc"
|
||||
v-html="handleprant(list.title)"
|
||||
>
|
||||
</span>
|
||||
<el-button @click="copyToClipboard(list.content)" type="primary" size="mini" style="margin-left: 10px;">复制</el-button>
|
||||
<el-button
|
||||
@click="copyToClipboard(list.content)"
|
||||
type="primary"
|
||||
size="mini"
|
||||
style="margin-left: 10px"
|
||||
>复制</el-button
|
||||
>
|
||||
|
||||
<div class="desc" v-html="handleprantHtml(list.content)">
|
||||
</div>
|
||||
<div class="desc" v-html="handleprantHtml(list.content)"></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -50,10 +92,18 @@
|
|||
class="image-card"
|
||||
:body-style="{ padding: '10px' }"
|
||||
>
|
||||
<img :src="image.url" class="image-preview" />
|
||||
<div style="text-align: center">{{ image.desc }}</div>
|
||||
<img :src="image.file" class="image-preview" />
|
||||
<div class="image-footer">
|
||||
<el-button @click="handlePreview(image.url)" size="mini">查看</el-button>
|
||||
<el-button @click="handleDownload(image.url)" type="success" size="mini">下载</el-button>
|
||||
<el-button @click="handlePreview(image.file)" size="mini"
|
||||
>查看</el-button
|
||||
>
|
||||
<el-button
|
||||
@click="handleDownload(image.file)"
|
||||
type="success"
|
||||
size="mini"
|
||||
>下载</el-button
|
||||
>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
@ -72,14 +122,22 @@
|
|||
class="file-card"
|
||||
:body-style="{ padding: '10px' }"
|
||||
>
|
||||
<div class="file-info">
|
||||
<div class="file-info">
|
||||
<el-icon class="file-icon">
|
||||
<i :class="getFileIcon(file.url)"></i>
|
||||
<i :class="getFileIcon(file.file)"></i>
|
||||
</el-icon>
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
<span class="file-name" style="display: block;">{{ getFileName(file.file) }}</span>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<span class="file-name">{{ file.desc }}</span>
|
||||
</div>
|
||||
<div class="file-footer">
|
||||
<el-button @click="handleDownload(file.url)" type="success" size="mini">下载</el-button>
|
||||
<el-button
|
||||
@click="handleDownload(file.file)"
|
||||
type="success"
|
||||
size="mini"
|
||||
>下载</el-button
|
||||
>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
@ -99,7 +157,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getQaCityList, getQaList } from '@/api/qa'
|
||||
import { getQaCityList, getQaList } from "@/api/qa";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
@ -107,110 +165,119 @@ export default {
|
|||
getQaCityList: [],
|
||||
getQaLists: [],
|
||||
dataForm: {
|
||||
keyword: '',
|
||||
city_id: ''
|
||||
keyword: "",
|
||||
city_id: "",
|
||||
},
|
||||
dialogImage: false, // 控制图片列表对话框的显示
|
||||
previewVisible: false, // 控制图片预览对话框的显示
|
||||
previewImageUrl: '', // 预览图片的 URL
|
||||
previewTitle: '', // 预览图片的标题
|
||||
imageList: [ // 示例图片列表
|
||||
previewImageUrl: "", // 预览图片的 URL
|
||||
previewTitle: "", // 预览图片的标题
|
||||
imageList: [
|
||||
// 示例图片列表
|
||||
],
|
||||
fileList: [ // 示例图片列表
|
||||
fileList: [
|
||||
// 示例图片列表
|
||||
],
|
||||
dialogFile: false,
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
getQaCityList().then(res => {
|
||||
this.getQaCityList = res.data
|
||||
})
|
||||
getQaCityList().then((res) => {
|
||||
this.getQaCityList = res.data;
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
'dataForm.keyword': function (newVal) {
|
||||
"dataForm.keyword": function (newVal) {
|
||||
if (newVal) {
|
||||
this.onSubmit();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 显示文件列表对话框
|
||||
showFileList(fileUrl) {
|
||||
this.fileList = [];
|
||||
if (fileUrl) {
|
||||
this.fileList = fileUrl.split(',').map(url => ({ url, name: url.split('/').pop() }));
|
||||
if (fileUrl.length) {
|
||||
this.fileList = fileUrl;
|
||||
}
|
||||
this.dialogFile = true;
|
||||
},
|
||||
// 根据文件 URL 获取文件图标
|
||||
getFileIcon(url) {
|
||||
const ext = url.split('.').pop().toLowerCase();
|
||||
const ext = url.split(".").pop().toLowerCase();
|
||||
console.log('ext:' + ext);
|
||||
switch (ext) {
|
||||
case 'pdf':
|
||||
return 'el-icon-file-pdf';
|
||||
case 'docx':
|
||||
return 'el-icon-file-word';
|
||||
case 'pptx':
|
||||
return 'el-icon-file-ppt';
|
||||
case 'xlsx':
|
||||
return 'el-icon-file-excel';
|
||||
case "pdf":
|
||||
return "el-icon-file-pdf";
|
||||
case "docx":
|
||||
return "el-icon-file-word";
|
||||
case "pptx":
|
||||
return "el-icon-file-ppt";
|
||||
case "xlsx":
|
||||
return "el-icon-file-excel";
|
||||
default:
|
||||
return 'el-icon-file';
|
||||
return "el-icon-file";
|
||||
}
|
||||
},
|
||||
// 根据文件 URL 获取文件图标
|
||||
getFileName(url) {
|
||||
return url.substring(url.lastIndexOf("/") + 1);
|
||||
},
|
||||
handleQacityl(val) {
|
||||
getQaList({ city_id: val }).then(res => {
|
||||
this.getQaLists = res.data.data
|
||||
})
|
||||
getQaList({ city_id: val }).then((res) => {
|
||||
this.getQaLists = res.data.data;
|
||||
});
|
||||
},
|
||||
handleZip(url) {
|
||||
if (url) {
|
||||
// window.open(url)
|
||||
fetch(url)
|
||||
.then(response => response.blob())
|
||||
.then(blob => {
|
||||
const link = document.createElement('a');
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const link = document.createElement("a");
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
link.href = objectUrl;
|
||||
link.download = url.split('/').pop(); // Extract filename from URL
|
||||
link.download = url.split("/").pop(); // Extract filename from URL
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '下载失败',
|
||||
type: 'error'
|
||||
message: "下载失败",
|
||||
type: "error",
|
||||
});
|
||||
console.error('Download error:', error);
|
||||
console.error("Download error:", error);
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '暂无下载链接',
|
||||
type: 'warning'
|
||||
message: "暂无下载链接",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
},
|
||||
load() {
|
||||
console.log('load')
|
||||
console.log("load");
|
||||
},
|
||||
handleprant(val) {
|
||||
if (!val) return ''; // 处理空值情况,避免返回 undefined 或其他非字符串值
|
||||
if (!val) return ""; // 处理空值情况,避免返回 undefined 或其他非字符串值
|
||||
|
||||
let replaceReg = new RegExp(this.dataForm.keyword, "ig");
|
||||
let replaceString = `<span style="color: #fff;background-color: #FC0421FF;">${this.dataForm.keyword}</span>`;
|
||||
return val.replace(replaceReg, replaceString);
|
||||
},
|
||||
handleprantHtml(val) {
|
||||
if (!val) return '';
|
||||
if (!val) return "";
|
||||
|
||||
let p = this.dataForm.keyword;
|
||||
let regexp = new RegExp(p, "g");
|
||||
let replacedHtml = val.replace(/(?<=>)[^>]+(?=<[/]?\w+.*>)/g, (v) => {
|
||||
return v.replace(regexp, `<span style='color: #fff;background-color: #FC0421FF;'>${p}</span>`);
|
||||
return v.replace(
|
||||
regexp,
|
||||
`<span style='color: #fff;background-color: #FC0421FF;'>${p}</span>`
|
||||
);
|
||||
});
|
||||
// 检查是否有替换发生
|
||||
if (replacedHtml === val) {
|
||||
|
@ -220,32 +287,31 @@ export default {
|
|||
return replacedHtml;
|
||||
},
|
||||
onSubmit() {
|
||||
getQaList(this.dataForm).then(res => {
|
||||
this.getQaLists = res.data.data
|
||||
})
|
||||
getQaList(this.dataForm).then((res) => {
|
||||
this.getQaLists = res.data.data;
|
||||
});
|
||||
},
|
||||
copyToClipboard(html) {
|
||||
const text = this.stripHtml(html);
|
||||
const input = document.createElement('textarea');
|
||||
const input = document.createElement("textarea");
|
||||
input.value = text;
|
||||
document.body.appendChild(input);
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(input);
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '内容已复制'
|
||||
message: "内容已复制",
|
||||
});
|
||||
},
|
||||
stripHtml(html) {
|
||||
const div = document.createElement('div');
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = html;
|
||||
return div.textContent || div.innerText || '';
|
||||
return div.textContent || div.innerText || "";
|
||||
},
|
||||
showImgDialog(imagesUrls) {
|
||||
this.imageList = []
|
||||
if (imagesUrls) {
|
||||
this.imageList = imagesUrls.split(',').map(url => ({ url }));
|
||||
if (imagesUrls.length) {
|
||||
this.imageList = imagesUrls;
|
||||
}
|
||||
|
||||
this.dialogImage = true;
|
||||
|
@ -253,7 +319,7 @@ export default {
|
|||
// 处理图片预览
|
||||
handlePreview(url) {
|
||||
this.previewImageUrl = url;
|
||||
this.previewTitle = '图片预览';
|
||||
this.previewTitle = "图片预览";
|
||||
this.previewVisible = true;
|
||||
},
|
||||
// 处理图片删除
|
||||
|
@ -265,35 +331,35 @@ export default {
|
|||
if (url) {
|
||||
// window.open(url)
|
||||
fetch(url)
|
||||
.then(response => response.blob())
|
||||
.then(blob => {
|
||||
const link = document.createElement('a');
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const link = document.createElement("a");
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
link.href = objectUrl;
|
||||
link.download = url.split('/').pop(); // Extract filename from URL
|
||||
link.download = url.split("/").pop(); // Extract filename from URL
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
})
|
||||
.catch(error => {
|
||||
.catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '下载失败',
|
||||
type: 'error'
|
||||
message: "下载失败",
|
||||
type: "error",
|
||||
});
|
||||
console.error('Download error:', error);
|
||||
console.error("Download error:", error);
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '暂无下载链接',
|
||||
type: 'warning'
|
||||
message: "暂无下载链接",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -365,7 +431,7 @@ body {
|
|||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
color: #46a6ff;
|
||||
&>:nth-child(1) {
|
||||
& > :nth-child(1) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
type="primary"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="onEdit(scope.row)"
|
||||
@click="onAdd(scope.row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
|
@ -96,264 +96,185 @@
|
|||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<el-dialog title="添加QA" :visible.sync="dialogCreate">
|
||||
<el-form label-width="120px" :model="anchors">
|
||||
<el-form-item label="城市">
|
||||
<el-select v-model="anchors.city_id" placeholder="请选择">
|
||||
<el-form-item
|
||||
style="display: inline-flex; text-align: left; width: 770px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in getQaCitys"
|
||||
:key="item.city_id"
|
||||
style="display: inline-flex; word-break: break-all"
|
||||
:label="item.city_name"
|
||||
:value="item.city_id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="旅游路线">
|
||||
<el-input
|
||||
v-model="anchors.title"
|
||||
type="text"
|
||||
placeholder="请输入旅游路线"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="QA内容">
|
||||
<div
|
||||
class="mistake-content"
|
||||
v-for="(item, index) in anchors.qaQuestions"
|
||||
>
|
||||
<div class="mistake-left">
|
||||
<div>副标题</div>
|
||||
<div class="qa-desc">
|
||||
<el-input
|
||||
style="width: 100px; margin-right: 10px"
|
||||
v-model="item.sort"
|
||||
type="text"
|
||||
placeholder="序号"
|
||||
/>
|
||||
<el-input
|
||||
v-model="item.title"
|
||||
type="text"
|
||||
placeholder="请输入副标题"
|
||||
/>
|
||||
</div>
|
||||
<div>内容</div>
|
||||
<div style="border: 1px solid #ccc">
|
||||
<myEditor v-model="item.content" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mistake-right">
|
||||
<el-button @click="handleDel(index)" type="danger"
|
||||
>删除</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mistake-btn">
|
||||
<el-button type="primary" @click="handleAdd">添加</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch
|
||||
v-model="anchors.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传图片">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="admin/upload/index"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
>
|
||||
<div v-for="(item, index) in anchors.img_zip" class="img-box">
|
||||
<i
|
||||
@click.stop="handleClose('img_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<i v-if="!checkIfUrlContainsImage(item)" class="el-icon-folder" />
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item) }}</div>
|
||||
</div>
|
||||
<i class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<div style="color: red">(请上传.jpg, png的图片)</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传行程">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="admin/upload/index"
|
||||
:show-file-list="false"
|
||||
:on-success="handleSuccess"
|
||||
>
|
||||
<div v-for="(item, index) in anchors.trip_zip" class="img-box">
|
||||
<i
|
||||
@click.stop="handleClose('trip_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<i v-if="!checkIfUrlContainsImage(item)" class="el-icon-folder" />
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item) }}</div>
|
||||
</div>
|
||||
<i class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<span style="color: red">(本行程请上传,ppt,word,pdf格式的文件)</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-dialog
|
||||
v-if="dialogCreate"
|
||||
ref="dialog"
|
||||
:title="title"
|
||||
:visible.sync="dialogCreate"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: flex-end; margin-bottom: 10px"
|
||||
>
|
||||
<el-button v-loading="loading" type="primary" @click="onSave"
|
||||
>保 存</el-button
|
||||
>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="编辑内容" :visible.sync="dialogEdit">
|
||||
<el-form label-width="120px" :model="anchors">
|
||||
<el-form-item label="城市">
|
||||
<el-select v-model="anchors.city_id" placeholder="请选择">
|
||||
<el-form-item
|
||||
style="display: inline-flex; text-align: left; width: 770px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in getQaCitys"
|
||||
:key="item.city_id"
|
||||
style="
|
||||
width: 250px;
|
||||
display: inline-flex;
|
||||
word-break: break-all;
|
||||
"
|
||||
:label="item.city_name"
|
||||
:value="item.city_id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="旅游路线">
|
||||
<el-input
|
||||
v-model="anchors.title"
|
||||
type="text"
|
||||
placeholder="请输入旅游路线"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="QA内容">
|
||||
<div
|
||||
class="mistake-content"
|
||||
v-for="(item, index) in anchors.qaQuestions"
|
||||
>
|
||||
<div class="mistake-left">
|
||||
<div>副标题</div>
|
||||
<div class="qa-desc">
|
||||
<el-input
|
||||
style="width: 100px; margin-right: 10px"
|
||||
v-model="item.sort"
|
||||
type="text"
|
||||
placeholder="序号"
|
||||
/>
|
||||
<el-input
|
||||
v-model="item.title"
|
||||
type="text"
|
||||
placeholder="请输入副标题"
|
||||
/>
|
||||
</div>
|
||||
<div>内容</div>
|
||||
<div style="border: 1px solid #ccc">
|
||||
<myEditor v-model="item.content" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mistake-right">
|
||||
<el-button @click="handleDel(index)" type="danger"
|
||||
>删除</el-button
|
||||
<el-scrollbar ref="scrollbar" class="scrollable-container">
|
||||
<el-form ref="addForm" label-width="120px" :model="anchors">
|
||||
<el-form-item label="城市" prop="city_id">
|
||||
<el-select v-model="anchors.city_id" placeholder="请选择">
|
||||
<el-form-item
|
||||
style="display: inline-flex; text-align: left; width: 770px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in getQaCitys"
|
||||
:key="item.city_id"
|
||||
style="display: inline-flex; word-break: break-all"
|
||||
:label="item.city_name"
|
||||
:value="item.city_id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="旅游路线" prop="title">
|
||||
<el-input
|
||||
v-model="anchors.title"
|
||||
type="text"
|
||||
placeholder="请输入旅游路线"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="QA内容">
|
||||
<div
|
||||
class="mistake-content"
|
||||
v-for="(item, index) in anchors.qaQuestions"
|
||||
>
|
||||
<div class="mistake-left">
|
||||
<div>副标题</div>
|
||||
<div class="qa-desc">
|
||||
<el-input
|
||||
style="width: 100px; margin-right: 10px"
|
||||
v-model="item.sort"
|
||||
type="text"
|
||||
placeholder="序号"
|
||||
/>
|
||||
<el-input
|
||||
v-model="item.title"
|
||||
type="text"
|
||||
placeholder="请输入副标题"
|
||||
/>
|
||||
</div>
|
||||
<div>内容</div>
|
||||
<div style="border: 1px solid #ccc">
|
||||
<myEditor v-model="item.content" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mistake-right">
|
||||
<el-button @click="handleDel(index)" type="danger"
|
||||
>删除</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mistake-btn">
|
||||
<el-button type="primary" @click="handleAdd">添加</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch
|
||||
v-model="anchors.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传图片">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="admin/upload/index"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
<div class="mistake-btn">
|
||||
<el-button type="primary" @click="handleAdd">添加</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch
|
||||
v-model="anchors.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 10px;
|
||||
"
|
||||
>
|
||||
<div v-for="(item, index) in anchors.img_zip" class="img-box">
|
||||
<i
|
||||
@click.stop="handleClose('img_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<i v-if="!checkIfUrlContainsImage(item)" class="el-icon-folder" />
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item) }}</div>
|
||||
<el-button type="primary" @click="onAddImg()">添加图片</el-button>
|
||||
</div>
|
||||
<el-form-item label="上传图片">
|
||||
<div class="upload-list">
|
||||
<div class="wu-yu" v-for="(item, index) in anchors.img_zip">
|
||||
<i
|
||||
@click.stop="handleClose('img_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action=""
|
||||
:show-file-list="false"
|
||||
:http-request="handlesAvatarSuccess"
|
||||
:on-success="
|
||||
(response, file, fileList) =>
|
||||
handleAvatarSuccess(response, file, fileList, index)
|
||||
"
|
||||
>
|
||||
<div v-if="!!item.file" class="img-box">
|
||||
<i
|
||||
v-if="!checkIfUrlContainsImage(item.file)"
|
||||
class="el-icon-folder"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item.file"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item.file) }}</div>
|
||||
</div>
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<el-input v-model="item.desc" placeholder="图片说明"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<i class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<div style="color: red">(请上传.jpg, png的图片)</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传行程">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="admin/upload/index"
|
||||
:show-file-list="false"
|
||||
:on-success="handleSuccess"
|
||||
<div style="color: red">(请上传.jpg, png的图片)</div>
|
||||
</el-form-item>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 10px;
|
||||
"
|
||||
>
|
||||
<div v-for="(item, index) in anchors.trip_zip" class="img-box">
|
||||
<i
|
||||
@click.stop="handleClose('trip_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<i v-if="!checkIfUrlContainsImage(item)" class="el-icon-folder" />
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item) }}</div>
|
||||
<el-button type="primary" @click="onAddtrip()">添加行程</el-button>
|
||||
</div>
|
||||
<el-form-item label="上传行程">
|
||||
<div class="upload-list">
|
||||
<div class="wu-yu" v-for="(item, index) in anchors.trip_zip">
|
||||
<i
|
||||
@click.stop="handleClose('trip_zip', index)"
|
||||
class="close el-icon-close"
|
||||
/>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action=""
|
||||
:http-request="handlesAvatarSuccess"
|
||||
:show-file-list="false"
|
||||
:on-success="
|
||||
(response, file, fileList) =>
|
||||
handleSuccess(response, file, fileList, index)
|
||||
"
|
||||
>
|
||||
<div v-if="!!item.file" class="img-box">
|
||||
<i
|
||||
v-if="!checkIfUrlContainsImage(item.file)"
|
||||
class="el-icon-folder"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
style="width: 100px; height: 100px"
|
||||
:src="item.file"
|
||||
class="avatar"
|
||||
alt=""
|
||||
/>
|
||||
<div class="desc">{{ handleRegex(item.file) }}</div>
|
||||
</div>
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<el-input v-model="item.desc" placeholder="行程说明"></el-input>
|
||||
</div>
|
||||
</div>
|
||||
<i class="el-icon-plus avatar-uploader-icon" />
|
||||
</el-upload>
|
||||
<span style="color: red">(本行程请上传,ppt,word,pdf格式的文件)</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button v-loading="loading" type="primary" @click="onSave"
|
||||
>保 存</el-button
|
||||
>
|
||||
</div>
|
||||
<span style="color: red"
|
||||
>(本行程请上传,ppt,word,pdf格式的文件)</span
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -361,13 +282,14 @@
|
|||
<script>
|
||||
import Pagination from "@/components/PaginationFixed";
|
||||
import myEditor from "@/components/Wangeditor/index.vue";
|
||||
|
||||
import { getToken } from "@/utils/auth";
|
||||
export default {
|
||||
name: "getQa",
|
||||
components: { Pagination, myEditor },
|
||||
data() {
|
||||
return {
|
||||
statusArr: { 0: "禁用", 1: "启用" },
|
||||
title: "",
|
||||
list: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
|
@ -387,8 +309,8 @@ export default {
|
|||
item: {},
|
||||
anchors: {
|
||||
qaQuestions: [],
|
||||
img_zip: [],
|
||||
trip_zip: [],
|
||||
img_zip: [{ desc: "", file: "" }],
|
||||
trip_zip: [{ desc: "", file: "" }],
|
||||
},
|
||||
getQaCitys: {},
|
||||
};
|
||||
|
@ -411,19 +333,42 @@ export default {
|
|||
".svg",
|
||||
".webp",
|
||||
];
|
||||
console.log(url);
|
||||
console.log(
|
||||
"========fffff====" +
|
||||
imageExtensions.some((extension) =>
|
||||
url.toLowerCase().endsWith(extension)
|
||||
)
|
||||
);
|
||||
console.log(url);
|
||||
return imageExtensions.some((extension) =>
|
||||
url.toLowerCase().endsWith(extension)
|
||||
);
|
||||
},
|
||||
|
||||
async handlesAvatarSuccess(file) {
|
||||
try {
|
||||
var formdata = new FormData();
|
||||
formdata.append("file", file.file);
|
||||
|
||||
this.upLoading = true;
|
||||
const _this = this;
|
||||
const res = await this.$axios.post("/admin/upload/index", formdata, {
|
||||
headers: {
|
||||
"Content-type": "multipart/form-data",
|
||||
"X-Token": getToken(),
|
||||
},
|
||||
});
|
||||
// if (![200].includes(res.data.code)) {
|
||||
// this.$message.error("上传失败");
|
||||
// return;
|
||||
// }
|
||||
// 主动回调success方法
|
||||
file.onSuccess(res);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
handleClose(val, i) {
|
||||
if (this.anchors[val].length == 1) {
|
||||
this.$message({
|
||||
message: "至少保留一条",
|
||||
type: "warning",
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log("i===", i);
|
||||
this.anchors[val].splice(i, 1);
|
||||
},
|
||||
|
@ -461,19 +406,27 @@ export default {
|
|||
this.listLoading = false;
|
||||
});
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
console.log("====1111===" + res);
|
||||
this.anchors.img_zip.push(
|
||||
`${window.location.protocol}//${window.location.host}${res.data}`
|
||||
);
|
||||
console.log("====111122222===" + this.anchors.img_zip);
|
||||
onAddImg() {
|
||||
this.anchors.img_zip.push({ desc: "", file: "" });
|
||||
},
|
||||
handleSuccess(res, file) {
|
||||
console.log("====222222===" + res);
|
||||
this.anchors.trip_zip.push(
|
||||
`${window.location.protocol}//${window.location.host}${res.data}`
|
||||
);
|
||||
console.log("====111122222===" + this.anchors.trip_zip);
|
||||
onAddtrip() {
|
||||
this.anchors.trip_zip.push({ desc: "", file: "" });
|
||||
},
|
||||
handleAvatarSuccess(res, file, fileList, index) {
|
||||
if (!res.data) return;
|
||||
this.anchors.img_zip[
|
||||
index
|
||||
].file = `${window.location.protocol}//${window.location.host}${res.data}`;
|
||||
// this.anchors.img_zip.push(
|
||||
// `${window.location.protocol}//${window.location.host}${res.data}`
|
||||
// );
|
||||
},
|
||||
handleSuccess(res, file, fileList, index) {
|
||||
console.log(res, file, fileList);
|
||||
if (!res.data) return;
|
||||
this.anchors.trip_zip[
|
||||
index
|
||||
].file = `${window.location.protocol}//${window.location.host}${res.data}`;
|
||||
},
|
||||
handleRegex(val) {
|
||||
const regex = /\/([^\/]+)$/;
|
||||
|
@ -484,51 +437,54 @@ export default {
|
|||
this.listQuery.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
onAdd() {
|
||||
this.anchors.qaQuestions = [
|
||||
{
|
||||
sort: 1,
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
];
|
||||
// 初始化时默认排序值为0
|
||||
this.anchors.img_zip = [];
|
||||
this.anchors.trip_zip = [];
|
||||
onAdd(item) {
|
||||
this.dialogCreate = true;
|
||||
},
|
||||
onEdit(item) {
|
||||
if (!item.qaQuestions.length) {
|
||||
this.anchors = {
|
||||
...item,
|
||||
qaQuestions: [
|
||||
{
|
||||
sort: 1,
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
],
|
||||
};
|
||||
if (!item.id) {
|
||||
this.title = "添加QA";
|
||||
this.anchors.qaQuestions = [
|
||||
{
|
||||
sort: 1,
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
];
|
||||
// 初始化时默认排序值为0
|
||||
this.anchors.img_zip = [{ desc: "", file: "" }];
|
||||
this.anchors.trip_zip = [{ desc: "", file: "" }];
|
||||
} else {
|
||||
this.anchors = { ...item };
|
||||
this.title = "编辑QA";
|
||||
if (!item.qaQuestions.length) {
|
||||
this.anchors = {
|
||||
...item,
|
||||
qaQuestions: [
|
||||
{
|
||||
sort: 1,
|
||||
title: "",
|
||||
content: "",
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
this.anchors = { ...item };
|
||||
}
|
||||
this.anchors.img_zip = item.img_zip
|
||||
? item.img_zip
|
||||
: [{ desc: "", file: "" }];
|
||||
this.anchors.trip_zip = item.trip_zip
|
||||
? item.trip_zip
|
||||
: [{ desc: "", file: "" }];
|
||||
}
|
||||
this.anchors.img_zip = item.img_zip;
|
||||
this.anchors.trip_zip = item.trip_zip;
|
||||
// this.anchors.img_zip =
|
||||
// typeof item.img_zip == "string" ? [item.img_zip] : item.img_zip;
|
||||
// this.anchors.trip_zip =
|
||||
// typeof item.trip_zip == "string" ? [item.trip_zip] : item.trip_zip;
|
||||
this.dialogEdit = true;
|
||||
},
|
||||
onSave() {
|
||||
if (this.loading) return;
|
||||
this.loading = true;
|
||||
const api = this.dialogCreate ? "/admin/qa/addQa" : "/admin/qa/editQa";
|
||||
const api =
|
||||
this.title == "添加QA" ? "/admin/qa/addQa" : "/admin/qa/editQa";
|
||||
this.$axios
|
||||
.post(api, this.anchors)
|
||||
.then(() => {
|
||||
this.dialogCreate = false;
|
||||
this.dialogEdit = false;
|
||||
// this.dialogEdit = false;
|
||||
this.loading = false;
|
||||
this.getList();
|
||||
})
|
||||
|
@ -585,11 +541,45 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scrollable-container {
|
||||
// position: relative;
|
||||
height: 500px; /* 可以根据实际情况调整高度 */
|
||||
// overflow-y: auto;
|
||||
}
|
||||
::v-deep.el-scrollbar .el-scrollbar__wrap {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.upload-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.wu-yu {
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 110px;
|
||||
flex-wrap: wrap;
|
||||
align-content: space-between;
|
||||
& + .wu-yu {
|
||||
margin-left: 5px;
|
||||
}
|
||||
::v-deep.el-input {
|
||||
width: 100px;
|
||||
margin: 10px 0 10px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.filter-items {
|
||||
position: fixed;
|
||||
// right: 0;
|
||||
left: 70%;
|
||||
z-index: 66;
|
||||
}
|
||||
.img-box {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 10px;
|
||||
& + .img-box {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
@ -615,7 +605,7 @@ export default {
|
|||
.close {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -8px;
|
||||
right: -15px;
|
||||
font-size: 18px;
|
||||
color: #409eff;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div class="scheduling_head">
|
||||
<div class="head_lable">产品编号:</div>
|
||||
<div
|
||||
class="scheduling_tab"
|
||||
@click="handleClick(index)"
|
||||
:key="index"
|
||||
:class="activeName == item.id ? 'active' : ''"
|
||||
v-for="(item, index) in liveroomList"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<el-button type="primary" style="margin-left: 210px" @click="handleEdit"
|
||||
>编辑</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="scheduling_tab_pana">
|
||||
<div class="table-list" v-for="item in roomWorksList">
|
||||
<div class="table-list_item">
|
||||
<div class="tit">
|
||||
{{ item.date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-list_item">
|
||||
<div class="tit">
|
||||
{{ item.date_name
|
||||
}}<i
|
||||
@click="handleAdds('', item.date)"
|
||||
class="el-icon-circle-plus"
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-list-box" v-for="it in item.work">
|
||||
<div class="border" @dblclick="handleAdds(it, item.date)">
|
||||
<div style="margin-bottom: 10px">
|
||||
AM {{ extractTime(it.start) }}~{{ extractTime(it.end) }}
|
||||
</div>
|
||||
<div>主播:{{ it.zhubo.name }}</div>
|
||||
<div>中控:{{ it.zhongkong.name }}</div>
|
||||
<div>路线:{{ it.route ? it.route : "无" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<liveroom-update
|
||||
v-if="addOrUpdateVisible"
|
||||
ref="addOrUpdate"
|
||||
@update="saveProducts"
|
||||
></liveroom-update>
|
||||
<roomWorksUpdate
|
||||
v-if="roomVisible"
|
||||
ref="roomUpdate"
|
||||
:title="title"
|
||||
@update="saveRoomWorks"
|
||||
></roomWorksUpdate>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
liveroom,
|
||||
roomWorks,
|
||||
availableZhubo,
|
||||
saveProducts,
|
||||
saveRoomWorks,
|
||||
} from "@/api/scheduling";
|
||||
import liveroomUpdate from "./liveroom-update.vue";
|
||||
import roomWorksUpdate from "./room-works";
|
||||
export default {
|
||||
name: "Scheduling",
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
activeName: "",
|
||||
listLoading: true,
|
||||
title: "添加排班",
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
title: "",
|
||||
status: "",
|
||||
},
|
||||
total: 0,
|
||||
dialogVisible: false,
|
||||
dialogType: "new",
|
||||
liveroomList: [],
|
||||
roomWorksList: [],
|
||||
product_ids: "",
|
||||
live_room_id: "",
|
||||
addOrUpdateVisible: false,
|
||||
roomVisible: false,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
liveroomUpdate,
|
||||
roomWorksUpdate,
|
||||
},
|
||||
async mounted() {
|
||||
await this.liveroom();
|
||||
this.roomWorks();
|
||||
},
|
||||
methods: {
|
||||
extractTime(dateTimeStr) {
|
||||
// 定义正则表达式来匹配时间部分
|
||||
const regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
|
||||
const match = dateTimeStr.match(regex);
|
||||
|
||||
if (!match) {
|
||||
throw new Error("不匹配");
|
||||
}
|
||||
|
||||
// 提取时间部分
|
||||
return `${match[4]}:${match[5]}:${match[6]}`;
|
||||
},
|
||||
isCurrentTimeAfter(startTimeStr) {
|
||||
// 将开始时间字符串转换为Date对象
|
||||
const startTime = new Date(startTimeStr);
|
||||
|
||||
// 获取当前时间
|
||||
const currentTime = new Date();
|
||||
|
||||
// 比较当前时间和开始时间
|
||||
return currentTime >= startTime;
|
||||
},
|
||||
// 直播间列表
|
||||
async liveroom() {
|
||||
try {
|
||||
let { data } = await liveroom();
|
||||
this.liveroomList = data;
|
||||
this.activeName = this.liveroomList[0].id + "";
|
||||
this.live_room_id = this.liveroomList[0].id;
|
||||
this.product_ids = this.liveroomList[0].product_ids;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
// 排班列表
|
||||
async roomWorks() {
|
||||
try {
|
||||
let { data } = await roomWorks(this.live_room_id);
|
||||
this.roomWorksList = data;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
// tab切换
|
||||
handleClick(i) {
|
||||
let { id, product_ids } = this.liveroomList[i];
|
||||
this.live_room_id = id;
|
||||
this.product_ids = product_ids;
|
||||
this.activeName = id + "";
|
||||
this.roomWorks();
|
||||
},
|
||||
// 编辑直播间
|
||||
handleEdit() {
|
||||
this.addOrUpdateVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs["addOrUpdate"].init(this.live_room_id, this.product_ids);
|
||||
});
|
||||
},
|
||||
// 添加排班
|
||||
handleAdds(form, date) {
|
||||
console.log(form);
|
||||
|
||||
this.title = form.id ? "编辑排班" : "添加排班";
|
||||
if (form.id && this.isCurrentTimeAfter(form.start)) {
|
||||
return this.$message.error("当前时间无法编辑");
|
||||
}
|
||||
this.roomVisible = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs["roomUpdate"].init(this.live_room_id, { ...form }, date);
|
||||
});
|
||||
},
|
||||
saveProducts(form) {
|
||||
this.liveroom();
|
||||
saveProducts(form).then((res) => {
|
||||
this.$message({
|
||||
message: "直播间编辑成功",
|
||||
type: "success",
|
||||
});
|
||||
});
|
||||
},
|
||||
saveRoomWorks(form) {
|
||||
saveRoomWorks(form).then((res) => {
|
||||
this.roomWorks();
|
||||
this.$message({
|
||||
message: "添加排班成功",
|
||||
type: "success",
|
||||
});
|
||||
});
|
||||
},
|
||||
handleAdd() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-container {
|
||||
position: relative;
|
||||
padding-bottom: 60px; /* 分页条的高度 */
|
||||
}
|
||||
::v-deep .el-tabs__nav-wrap::after {
|
||||
display: none;
|
||||
}
|
||||
.filter-container,
|
||||
.el-table {
|
||||
padding-bottom: 5px; /* 分页条的高度,以避免内容重叠 */
|
||||
}
|
||||
::v-deep .el-row {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
}
|
||||
.head_lable {
|
||||
font-size: 14px;
|
||||
color: #3d3d3d;
|
||||
font-weight: 700;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.scheduling_head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.scheduling_tab {
|
||||
display: inline-block;
|
||||
padding: 12px 28px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
& + .scheduling_tab {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
border-color: #1269ff;
|
||||
}
|
||||
.el-icon-circle-plus {
|
||||
color: #367af0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.scheduling_tab_pana {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// align-items: center;
|
||||
.table-list {
|
||||
flex-basis: 14.3%;
|
||||
.table-list_item {
|
||||
height: 56px;
|
||||
background: #e4ecff;
|
||||
display: flex;
|
||||
// justify-content: center;
|
||||
align-items: center;
|
||||
border: 1px solid #d7ddeb;
|
||||
margin-right: -1px;
|
||||
margin-bottom: -1px;
|
||||
.tit {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
}
|
||||
.table-list-box {
|
||||
padding: 15px;
|
||||
font-size: 14px;
|
||||
color: #ffffff;
|
||||
border: 1px solid #d7ddeb;
|
||||
margin-right: -1px;
|
||||
margin-bottom: -1px;
|
||||
.border {
|
||||
padding: 13px;
|
||||
background: #367af0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
title="编辑直播间"
|
||||
:visible.sync="dialogVisible"
|
||||
width="30%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-form ref="form" :model="form" label-width="80px">
|
||||
<el-form-item label="直播间id" prop="product_ids">
|
||||
<el-input v-model="form.product_ids"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleEdit">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
form: {
|
||||
product_ids: "",
|
||||
live_room_id: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init(live_room_id, product_ids) {
|
||||
this.dialogVisible = true;
|
||||
this.form.product_ids = product_ids;
|
||||
this.form.live_room_id = live_room_id;
|
||||
console.log(this.form);
|
||||
},
|
||||
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleEdit() {
|
||||
this.dialogVisible = false;
|
||||
this.$emit("update", this.form);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="title"
|
||||
:visible.sync="dialogVisible"
|
||||
width="30%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-form :rules="rules" ref="form" :model="form" label-width="80px">
|
||||
<el-form-item label="直播间" prop="live_room_id">
|
||||
<el-select v-model="form.live_room_id" placeholder="请选择直播间">
|
||||
<el-option
|
||||
v-for="item in liveroomList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="开始时间" prop="start">
|
||||
<el-date-picker
|
||||
@change="handleDate"
|
||||
v-model="form.start"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetime"
|
||||
placeholder="选择日期时间"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间" prop="end">
|
||||
<el-date-picker
|
||||
v-model="form.end"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetime"
|
||||
@change="handleDate"
|
||||
placeholder="选择日期时间"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="时间">
|
||||
<el-time-select
|
||||
placeholder="起始时间"
|
||||
v-model="startTime"
|
||||
:picker-options="{
|
||||
start: '08:00',
|
||||
step: '00:15',
|
||||
end: '24:00',
|
||||
}"
|
||||
>
|
||||
</el-time-select>
|
||||
<el-time-select
|
||||
placeholder="结束时间"
|
||||
@change="handleDate"
|
||||
v-model="endTime"
|
||||
:picker-options="{
|
||||
start: '08:00',
|
||||
step: '00:15',
|
||||
end: '24:00',
|
||||
minTime: startTime,
|
||||
}"
|
||||
>
|
||||
</el-time-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="主播" prop="zhubo_id">
|
||||
<el-select v-model="form.zhubo_id" placeholder="请选择主播">
|
||||
<el-option
|
||||
v-for="item in zhuboList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:disabled="item.disabled"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="中控" prop="zhongkong_id">
|
||||
<el-select v-model="form.zhongkong_id" placeholder="请选择中控">
|
||||
<el-option
|
||||
v-for="item in zhongkongList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:disabled="item.disabled"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="路线">
|
||||
<el-input v-model="form.route"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleEdit">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { availableZhubo, liveroom } from "@/api/scheduling";
|
||||
export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: "添加排班",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
startTime: "",
|
||||
endTime: "",
|
||||
form: {
|
||||
live_room_id: "",
|
||||
start: "",
|
||||
end: "",
|
||||
zhubo_id: "",
|
||||
zhongkong_id: "",
|
||||
route: "",
|
||||
},
|
||||
zhuboList: [],
|
||||
zhongkongList: [],
|
||||
liveroomList: [],
|
||||
dayDate: "",
|
||||
rules: {
|
||||
live_room_id: [
|
||||
{ required: true, message: "请选择直播间", trigger: "change" },
|
||||
],
|
||||
zhongkong_id: [
|
||||
{ required: true, message: "请选择中控", trigger: "change" },
|
||||
],
|
||||
zhubo_id: [
|
||||
{ required: true, message: "请选择主播", trigger: "change" },
|
||||
],
|
||||
// date: [{ required: true, message: "请选择时间", trigger: "change" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
form: function () {
|
||||
this.handleDate();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
extractTime(dateTimeStr) {
|
||||
// 定义正则表达式来匹配时间部分
|
||||
const regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
|
||||
const match = dateTimeStr.match(regex);
|
||||
|
||||
if (!match) {
|
||||
throw new Error("不匹配");
|
||||
}
|
||||
|
||||
// 提取时间部分
|
||||
return `${match[4]}:${match[5]}`;
|
||||
},
|
||||
init(live_room_id, form, date) {
|
||||
this.dialogVisible = true;
|
||||
this.$nextTick((res) => {
|
||||
this.$refs["form"].resetFields();
|
||||
this.dayDate = date;
|
||||
this.form = !!form.id
|
||||
? form
|
||||
: {
|
||||
live_room_id: "",
|
||||
start: "",
|
||||
end: "",
|
||||
zhubo_id: "",
|
||||
zhongkong_id: "",
|
||||
};
|
||||
this.form.live_room_id = live_room_id;
|
||||
this.startTime = form.id ? this.extractTime(this.form.start) : "";
|
||||
this.endTime = form.id ? this.extractTime(this.form.end) : "";
|
||||
console.log(this.startTime);
|
||||
console.log(this.endTime);
|
||||
});
|
||||
this.liveroom();
|
||||
},
|
||||
// 直播间列表
|
||||
async liveroom() {
|
||||
try {
|
||||
let { data } = await liveroom();
|
||||
this.liveroomList = data;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
},
|
||||
handleDate() {
|
||||
this.form.end = `${this.dayDate} ${this.endTime}:00`;
|
||||
this.form.start = `${this.dayDate} ${this.startTime}:00`;
|
||||
if (this.form.end && this.form.start) {
|
||||
availableZhubo({ ...this.form, type: 2 }).then((res) => {
|
||||
this.zhuboList = res.data;
|
||||
});
|
||||
availableZhubo({ ...this.form, type: 3 }).then((res) => {
|
||||
this.zhongkongList = res.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
handleEdit() {
|
||||
// this.form.end = `${this.dayDate} ${this.startTime}:00`;
|
||||
// this.form.start = `${this.dayDate} ${this.endTime}:00`;
|
||||
this.dialogVisible = false;
|
||||
this.$emit("update", this.form);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -40,7 +40,7 @@ module.exports = {
|
|||
"/dev-api": {
|
||||
// 接口地址 以 api开头的都走下面的配置
|
||||
// target: 'https://www.szjinao.cn', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
target: "http://192.168.0.100:8787", // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
target: 'http://192.168.0.100:8787', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
ws: true, // 是否支持 websocket 请求 支持
|
||||
changeOrigin: true, // 是否启用跨域
|
||||
pathRewrite: {
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace app\admin\controller;
|
|||
use app\model\Admins;
|
||||
use app\model\Onlines;
|
||||
use app\model\Orders;
|
||||
use app\model\Products;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\Redis;
|
||||
|
@ -26,8 +27,8 @@ class AdminController extends base
|
|||
}
|
||||
|
||||
if($typeDesc = $request->get('type_desc')) {
|
||||
$routeType = self::ROUTE_LISTS[mb_substr($typeDesc, 0, 2)] ?? 10;
|
||||
$query->where('route_type', $routeType);
|
||||
//$routeType = self::ROUTE_LISTS[mb_substr($typeDesc, 0, 2)] ?? 10;
|
||||
//$query->where('route_type', $routeType);
|
||||
}
|
||||
|
||||
$list = $query->paginate($request->get('limit',10));
|
||||
|
@ -72,6 +73,11 @@ class AdminController extends base
|
|||
$is_franchisee = $request->post('is_franchisee',0);
|
||||
$product_ids = $request->post('product_ids','');
|
||||
$routeType = $request->post('route_type','10');
|
||||
$type = $request->post('type','0');
|
||||
|
||||
if (in_array($type, [2, 3])) { // 主播/中控默认密码:123456
|
||||
$password = '123456';
|
||||
}
|
||||
|
||||
if($id) {
|
||||
$item = (new Admins())->find($id);
|
||||
|
@ -112,6 +118,7 @@ class AdminController extends base
|
|||
$item->is_franchisee = $is_franchisee;
|
||||
$item->product_ids = $product_ids;
|
||||
$item->route_type = $routeType;
|
||||
$item->type = $type;
|
||||
Log::info('logs:' . json_encode($item));
|
||||
$back = $item->save();
|
||||
if($back)
|
||||
|
@ -177,6 +184,11 @@ class AdminController extends base
|
|||
$list[$adminId]['order_num'] = $user->order_num;
|
||||
$list[$adminId]['id'] = $adminId;
|
||||
$list[$adminId]['username'] = $user->username;
|
||||
$list[$adminId]['route_type'] = $user->route_type;
|
||||
$list[$adminId]['routes'] = [];
|
||||
if ($user->product_ids) {
|
||||
$list[$adminId]['routes'] = Products::query()->field(['product_name'])->whereIn('id', explode(',', $user->product_ids))->select();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success(array_values($list));
|
||||
|
|
|
@ -11,10 +11,16 @@ use support\Request;
|
|||
|
||||
class DataController extends base
|
||||
{
|
||||
public function index(Request $request) {
|
||||
$times = $request->get('times');
|
||||
$os = $request->get('os');
|
||||
|
||||
/**
|
||||
* 获取订单统计数据
|
||||
* @param $times
|
||||
* @param $os
|
||||
* @return Orders[]|array|\think\Collection|\think\db\Query[]|\think\model\Collection
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
private function orderStatics($times, $os) {
|
||||
$query = Orders::alias('o')->with('admin')
|
||||
->leftJoin('admins a','a.id = o.admin_id')
|
||||
->order('o.admin_id','desc')
|
||||
|
@ -23,19 +29,19 @@ class DataController extends base
|
|||
count(o.id) as orders,
|
||||
SUM(o.total_price) as total_price,
|
||||
SUM(CASE
|
||||
WHEN (o.os = 1 AND o.order_status = 4) OR (o.os = 3 AND o.order_status = 2) OR (o.os = 2 AND o.order_status = 5) THEN 1
|
||||
WHEN (o.os in (1,7) AND o.order_status = 4) OR (o.os in(3,5) AND o.order_status = 2) OR (o.os = 2 AND o.order_status = 5) THEN 1
|
||||
ELSE 0
|
||||
END) as assets,
|
||||
SUM(CASE
|
||||
WHEN (o.os = 1 AND o.order_status = 4) OR (o.os = 3 AND o.order_status = 2) OR (o.os = 2 AND o.order_status = 5) THEN asset_price
|
||||
WHEN (o.os in (1,7) AND o.order_status = 4) OR (o.os in(3,5) AND o.order_status = 2) OR (o.os = 2 AND o.order_status = 5) THEN asset_price
|
||||
ELSE 0
|
||||
END) as asset_price,
|
||||
SUM(CASE
|
||||
WHEN (o.os = 1 AND o.order_status = 5) OR (o.os = 3 AND o.order_status = 4) OR (o.os = 2 AND o.order_status = 1) THEN 1
|
||||
WHEN (o.os in (1,7) AND o.order_status = 5) OR (o.os in(3,5) AND o.order_status = 4) OR (o.os = 2 AND o.order_status = 1) THEN 1
|
||||
ELSE 0
|
||||
END) AS nopays,
|
||||
SUM(CASE
|
||||
WHEN (o.os = 1 AND o.order_status = 5) OR (o.os = 3 AND o.order_status = 4) OR (o.os = 2 AND o.order_status = 1) THEN actual_price
|
||||
WHEN (o.os in (1,7) AND o.order_status = 5) OR (o.os in(3,5) AND o.order_status = 4) OR (o.os = 2 AND o.order_status = 1) THEN actual_price
|
||||
ELSE 0
|
||||
END) AS nopay_price,
|
||||
o.admin_id,a.name');
|
||||
|
@ -50,8 +56,12 @@ class DataController extends base
|
|||
$query->where('o.os', $os);
|
||||
}
|
||||
|
||||
$list = $query->select();
|
||||
|
||||
return $query->select();
|
||||
}
|
||||
public function index(Request $request) {
|
||||
$times = $request->get('times');
|
||||
$os = $request->get('os');
|
||||
$list = $this->orderStatics($times, $os);
|
||||
//统计每一列
|
||||
$totalArr[1] = [
|
||||
'write_rate' => 0,
|
||||
|
@ -63,6 +73,10 @@ class DataController extends base
|
|||
'nopays' => 0,
|
||||
'nopay_price' => 0,
|
||||
'admin_id' => 0,
|
||||
'm_orders' => 0,
|
||||
'm_total_price' => 0,
|
||||
'm_assets' => 0,
|
||||
'm_asset_price' => 0,
|
||||
'name' => '合计',
|
||||
'admin' => [
|
||||
'username' => '合计',
|
||||
|
@ -70,9 +84,29 @@ class DataController extends base
|
|||
'avatar' => '',
|
||||
]
|
||||
];
|
||||
|
||||
// 当月数据统计
|
||||
$currentList = $this->orderStatics([date('Y-m-01'), date('Y-m-d H:i:s')], $os);
|
||||
$currentList = array_column($currentList->toArray(), null, 'admin_id');
|
||||
foreach ($list as $k => $v) {
|
||||
$list[$k]['write_rate'] = number_format(($v['assets']/$v['orders'])*100,2);
|
||||
$list[$k]['write_rate_price'] = number_format(($v['asset_price']/$v['total_price'])*100,2);
|
||||
|
||||
// 当月核销率(按订单)
|
||||
$list[$k]['month_write_rate'] = 0;
|
||||
// 当月核销率(按销售额)
|
||||
$list[$k]['month_write_rate_price'] = 0;
|
||||
if (isset($currentList[$v['admin_id']])) {
|
||||
$currentAdmin = $currentList[$v['admin_id']];
|
||||
$list[$k]['month_write_rate'] = number_format(($currentAdmin['assets']/$currentAdmin['orders'])*100,2);
|
||||
$list[$k]['month_write_rate_price'] = number_format(($currentAdmin['asset_price']/$currentAdmin['total_price'])*100,2);
|
||||
|
||||
$totalArr[1]['m_orders'] += $currentAdmin['orders'];
|
||||
$totalArr[1]['m_total_price'] += $currentAdmin['total_price'];
|
||||
$totalArr[1]['m_assets'] += $currentAdmin['assets'];
|
||||
$totalArr[1]['m_asset_price'] += $currentAdmin['asset_price'];
|
||||
}
|
||||
|
||||
$totalArr[1]['orders'] += $list[$k]['orders'];
|
||||
$totalArr[1]['total_price'] += $list[$k]['total_price'];
|
||||
$totalArr[1]['assets'] += $list[$k]['assets'];
|
||||
|
@ -82,6 +116,8 @@ class DataController extends base
|
|||
}
|
||||
$totalArr[1]['write_rate'] = (float)number_format(($totalArr[1]['assets']/$totalArr[1]['orders'])*100,2);
|
||||
$totalArr[1]['write_rate_price'] = (float)number_format(($totalArr[1]['asset_price']/$totalArr[1]['total_price'])*100,2);
|
||||
$totalArr[1]['month_write_rate'] = (float)number_format(($totalArr[1]['m_assets']/$totalArr[1]['m_orders'])*100,2);
|
||||
$totalArr[1]['month_write_rate_price'] = (float)number_format(($totalArr[1]['m_asset_price']/$totalArr[1]['m_total_price'])*100,2);
|
||||
$list = array_merge($list->toArray(), $totalArr);
|
||||
|
||||
$excel = $request->get('excel');
|
||||
|
|
|
@ -64,7 +64,34 @@ class IndexController extends base
|
|||
$backs = Backs::where('admin', $request->admin->id)->where('status', 0)->count();
|
||||
}
|
||||
|
||||
return $this->success(['new' => $new ?? 0, 'follow' => $follow, 'back' => $backs]);
|
||||
// 核销提醒
|
||||
$orderWriteOff = Redis::get('CRM:USER:WRITE:OFF:' . $request->admin->id);
|
||||
Redis::del('CRM:USER:WRITE:OFF:' . $request->admin->id);
|
||||
|
||||
// 跟进提醒
|
||||
$followMessage = 0;
|
||||
$followOrderId = '';
|
||||
$appointmentNum = 0;
|
||||
if ($request->admin->id > 1) {
|
||||
$start = strtotime(date('Y-m-d')) * 1000;
|
||||
$end = strtotime(date('Y-m-d', strtotime('+1 days'))) * 1000 - 1;
|
||||
$followMessageList = Orders::where(['admin_id' => $request->admin->id])
|
||||
->whereBetween('next_follow', [$start, $end])
|
||||
->where('status', 1)
|
||||
->field(['id'])
|
||||
->select();
|
||||
$followMessage = count($followMessageList);
|
||||
if ($followMessage) {
|
||||
$followOrderId = $followMessageList[0]['id'];
|
||||
}
|
||||
|
||||
// 预约未处理数量
|
||||
$appointmentNum = Orders::where(['admin_id' => $request->admin->id])
|
||||
->where('appointment_status', 1)
|
||||
->count();
|
||||
}
|
||||
|
||||
return $this->success(['new' => $new ?? 0, 'follow' => $follow, 'back' => $backs, 'order_write_off' => $orderWriteOff, 'follow_message' => $followMessage, 'follow_order_id' => $followOrderId, 'appointment_num' => $appointmentNum]);
|
||||
}
|
||||
|
||||
public function line()
|
||||
|
@ -120,51 +147,51 @@ class IndexController extends base
|
|||
SUM(total_price) as total,
|
||||
COUNT(id) as `all`,
|
||||
SUM(CASE
|
||||
WHEN (os = 1 AND order_status = 3) OR (os = 2 AND order_status = 4) OR (os = 3 AND order_status = 1) THEN 1
|
||||
WHEN (os in(1,7) AND order_status = 3) OR (os = 2 AND order_status = 4) OR (os in (3,5) AND order_status = 1) THEN 1
|
||||
ELSE 0
|
||||
END) as tobeused,
|
||||
SUM(CASE
|
||||
WHEN (os = 1 AND order_status = 3) OR (os = 2 AND order_status = 4) OR (os = 3 AND order_status = 1) THEN total_price
|
||||
WHEN (os in(1,7) AND order_status = 3) OR (os = 2 AND order_status = 4) OR (os in (3,5) AND order_status = 1) THEN total_price
|
||||
ELSE 0
|
||||
END) as tobeused_price,
|
||||
SUM(CASE
|
||||
WHEN (os = 1 AND order_status = 4) OR (os = 3 AND order_status = 2) OR (os = 2 AND order_status = 5) THEN 1
|
||||
WHEN (os in(1,7) AND order_status = 4) OR (os in (3,5) AND order_status = 2) OR (os = 2 AND order_status = 5) THEN 1
|
||||
ELSE 0
|
||||
END) as asset,
|
||||
SUM(CASE
|
||||
WHEN (os = 1 AND order_status = 4) OR (os = 3 AND order_status = 2) OR (os = 2 AND order_status = 5) THEN asset_price
|
||||
WHEN (os in(1,7) AND order_status = 4) OR (os in (3,5) AND order_status = 2) OR (os = 2 AND order_status = 5) THEN asset_price
|
||||
ELSE 0
|
||||
END) as asset_price,
|
||||
SUM(CASE
|
||||
WHEN ((os = 1 AND status = 5) OR (os = 3 AND status = 4) OR (os = 2 AND status = 1)) THEN 1
|
||||
WHEN ((os in(1,7) AND status = 5) OR (os in (3,5) AND status = 4) OR (os = 2 AND status = 1)) THEN 1
|
||||
ELSE 0
|
||||
END) AS refund,
|
||||
SUM(CASE
|
||||
WHEN ((os = 1 AND status = 5) OR (os = 3 AND status = 4) OR (os = 2 AND status = 1)) THEN actual_price
|
||||
WHEN ((os in(1,7) AND status = 5) OR (os in (3,5) AND status = 4) OR (os = 2 AND status = 1)) THEN actual_price
|
||||
ELSE 0
|
||||
END) AS refund_price,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfThirtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfThirtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
ELSE 0
|
||||
END) AS tobeused_30,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfThirtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfThirtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
ELSE 0
|
||||
END) AS tobeused_price_30,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfSixtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfSixtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
ELSE 0
|
||||
END) AS tobeused_60,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfSixtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfSixtyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
ELSE 0
|
||||
END) AS tobeused_price_60,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfEightyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfEightyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN 1
|
||||
ELSE 0
|
||||
END) AS tobeused_80,
|
||||
SUM(CASE
|
||||
WHEN ((os=1 AND order_status=3) OR (os=2 AND order_status=4) OR (os=3 AND order_status=1)) AND create_at >= ' . $startOfEightyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
WHEN ((os in(1,7) AND order_status=3) OR (os=2 AND order_status=4) OR (os in (3,5) AND order_status=1)) AND create_at >= ' . $startOfEightyDaysAgoTimestamp . ' AND create_at <= ' . $endOfDayTimestamp . ' THEN total_price
|
||||
ELSE 0
|
||||
END) AS tobeused_price_80
|
||||
');
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\model\Admins;
|
||||
use app\model\LiveRoom;
|
||||
use app\model\LiveRoomWorks;
|
||||
use app\model\Orders;
|
||||
use app\model\Works;
|
||||
use support\Request;
|
||||
|
||||
class LiveRoomController extends base {
|
||||
/**
|
||||
* 直播间列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function index(Request $request) {
|
||||
$all = LiveRoom::select();
|
||||
return $this->success($all);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新直播产品
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function saveProducts(Request $request) {
|
||||
$roomId = $request->post('live_room_id', '');
|
||||
if (empty($roomId)) {
|
||||
$this->error('请选择直播间');
|
||||
}
|
||||
$products = $request->post('product_ids', '');
|
||||
$productIds = explode(',', $products);
|
||||
foreach ($productIds as $productId) {
|
||||
if (empty($productId)) {
|
||||
continue;
|
||||
}
|
||||
$liveRoom = LiveRoom::whereRaw(sprintf('find_in_set(%s, `product_ids`)', $productId))->where('id', '!=', $roomId)->find();
|
||||
if (!empty($liveRoom)) {
|
||||
return $this->error(sprintf('产品ID:%s已经在%s存在', $productId, $liveRoom['name']));
|
||||
}
|
||||
}
|
||||
LiveRoom::where(['id' => $roomId])->update(['product_ids' => $products]);
|
||||
return $this->success([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 排班列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function roomWorks(Request $request)
|
||||
{
|
||||
$roomId = $request->get('live_room_id', '');
|
||||
if (!$roomId) {
|
||||
return $this->error('请选择直播间');
|
||||
}
|
||||
$weekDays = get_week_days();
|
||||
foreach ($weekDays as &$day) {
|
||||
$day['work'] = LiveRoomWorks::getDayWork($day['date'], $roomId);
|
||||
}
|
||||
|
||||
return $this->success($weekDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* 排班
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function saveRoomWorks(Request $request)
|
||||
{
|
||||
$id = $request->post('id', '0');
|
||||
$roomId = $request->post('live_room_id', '');
|
||||
$zhuboId = $request->post('zhubo_id', 0);
|
||||
$zhongkongId = $request->post('zhongkong_id', 0);
|
||||
$route = $request->post('route', '');
|
||||
$start = $request->post('start');
|
||||
$end = $request->post('end');
|
||||
$month = date('Ym', strtotime($start));
|
||||
$day = date('Ymd', strtotime($start));
|
||||
|
||||
if (strtotime($start) < time()) {
|
||||
return $this->error(6000, '当前时间不可排班');
|
||||
}
|
||||
|
||||
if (strtotime($start) >= strtotime($end)) {
|
||||
return $this->error(6000, '开始时间不可大于结束时间');
|
||||
}
|
||||
|
||||
// 检测当前日期是否已有排班
|
||||
if (LiveRoomWorks::dayWorkIsExists($id, $roomId, $start, $end)) {
|
||||
return $this->error(6001, '当前时间段已有排班');
|
||||
}
|
||||
// 检测当前主播当天是否已排班
|
||||
if (LiveRoomWorks::zhuboWorkIsExists($id, $zhuboId, $day)) {
|
||||
return $this->error(6002, '当前主播已排班');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'live_room_id' => $roomId,
|
||||
'zhubo_id' => $zhuboId,
|
||||
'zhongkong_id' => $zhongkongId,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'month' => $month,
|
||||
'day' => $day,
|
||||
'route' => $route,
|
||||
];
|
||||
if ($id) {
|
||||
$result = LiveRoomWorks::where('id', $id)->update($data);
|
||||
} else {
|
||||
$result = LiveRoomWorks::create($data);
|
||||
}
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 可排班主播列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function availableZhubo(Request $request) {
|
||||
$type = $request->get('type', 2);
|
||||
$id = $request->get('id', 0);
|
||||
$start = $request->get('start');
|
||||
if (empty($start)) {
|
||||
return $this->error('请选择时间');
|
||||
}
|
||||
$end = $request->get('end');
|
||||
$day = date('Ymd', strtotime($start));
|
||||
|
||||
$query = Admins::where('status', 1)->where('type', $type);
|
||||
$list = $query->field(['id', 'name', 'mobile'])->select();
|
||||
|
||||
// 获取已排班主播
|
||||
$adminIds = LiveRoomWorks::inWorkAdmin($day)->column('zhubo_id');
|
||||
foreach ($list as $val) {
|
||||
$val->disabled = false;
|
||||
if ($type == 2 && in_array($val->id, $adminIds)) {
|
||||
$val->disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 主播业绩查询
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function zhuboStatistics(Request $request)
|
||||
{
|
||||
$start = $request->get('start', date('Y-m-01'));
|
||||
$end = $request->get('end', date('Y-m-d'));
|
||||
$times = $request->get('times');
|
||||
if (!empty($times) && is_array($times)) {
|
||||
$start = $times[0];
|
||||
$end = $times[1];
|
||||
}
|
||||
// 姓名,职务,手机号,订单金额,直播时长
|
||||
$mobile = $request->get('mobile', '');
|
||||
$query = Admins::whereIn('type', [2, 3]);
|
||||
if (!empty($mobile)) {
|
||||
$query->where('mobile', $mobile);
|
||||
}
|
||||
|
||||
$list = $query->order('id', 'desc')->paginate($request->get('limit', 10));
|
||||
foreach ($list as $work) {
|
||||
$work->orders = 0;
|
||||
$work->total = 0;
|
||||
$work->asset_total = 0;
|
||||
$work->work_time = 0;
|
||||
|
||||
$statics = LiveRoomWorks::staticOrder($work->type, $work->id, $start, $end);
|
||||
if ($statics) {
|
||||
$work->orders = $statics->orders;
|
||||
$work->total = $statics->total/100;
|
||||
$work->asset_total = $statics->asset_total/100;
|
||||
$work->work_time = $statics->work_time;
|
||||
}
|
||||
}
|
||||
return $this->success($list);
|
||||
}
|
||||
|
||||
public function test() {
|
||||
$data = LiveRoomWorks::staticOrder(3, 38, '2024-09-17 16:00:00', '2024-09-18 15:59:59');
|
||||
return $this->success($data);
|
||||
}
|
||||
}
|
|
@ -4,11 +4,13 @@ require_once(__DIR__.'/xlsxwriter.class.php');
|
|||
|
||||
use app\model\Admins;
|
||||
use app\model\Backs;
|
||||
use app\model\Blacks;
|
||||
use app\model\Follows;
|
||||
use app\model\Orders;
|
||||
use app\model\Logs;
|
||||
use app\model\ThirdMobileLogs;
|
||||
use app\server\AliCloudApiService;
|
||||
use app\server\SMS;
|
||||
use app\server\ThirdApiService;
|
||||
use app\server\Orders as ServerOrders;
|
||||
use stdClass;
|
||||
use support\Log;
|
||||
|
@ -24,11 +26,15 @@ class OrderController extends base
|
|||
$timetype = $request->get('timetype');
|
||||
$times = $request->get('times');
|
||||
$os_status = $request->get('os_status');
|
||||
$isRefunded = $request->get('is_refunded', 0);
|
||||
|
||||
$where = [];
|
||||
if(!$request->admin->is_super) {
|
||||
$where = [['admin_id','=', $request->admin->id]];
|
||||
} else {
|
||||
$where = [['admin_id', '>', 0]];
|
||||
}
|
||||
$where[] = ['is_refunded', '=', $isRefunded];
|
||||
|
||||
if($sn) {
|
||||
$where[] = ['sn','=', $sn];
|
||||
|
@ -47,9 +53,16 @@ class OrderController extends base
|
|||
|
||||
if($os_status) {
|
||||
if ($os_status[0] == array_search(Orders::OSS[4],Orders::OSS)){
|
||||
$query->whereRaw(Orders::AllOssStatusSql[$os_status[1]]);
|
||||
if (isset($os_status[1]) && is_numeric($os_status[1])) {
|
||||
$query->whereRaw(Orders::AllOssStatusSql[$os_status[1]]);
|
||||
}
|
||||
}else{
|
||||
$query->where('os', $os_status[0] ?? 0 )->where('order_status', $os_status[1] ?? 0);
|
||||
if (isset($os_status[0]) && is_numeric($os_status[0])) {
|
||||
$query->where('os', $os_status[0]);
|
||||
}
|
||||
if (isset($os_status[1]) && is_numeric($os_status[1])) {
|
||||
$query->where('order_status', $os_status[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,24 +138,27 @@ class OrderController extends base
|
|||
|
||||
$list = $orders->visible(['admin' => ['username','name','avatar']])->hidden(['check_sn'])->append(['order_status_name','status_name','os_name']);
|
||||
|
||||
$localMobiles = [];
|
||||
foreach ($list as &$value) {
|
||||
$mobileInfo = $value['mobileInfo'] ?? '';
|
||||
if (empty($value['mobileInfo'])) {
|
||||
try {
|
||||
$mobileInfo = (new AliCloudApiService())->getMobileArea($value['mobile']);
|
||||
if (isset($localMobiles[$value['mobile']])) {
|
||||
// 防止重复查询第三方接口
|
||||
$mobileInfo = $localMobiles[$value['mobile']];
|
||||
} else {
|
||||
$mobileInfo = (new ThirdApiService())->getMobileArea($value['mobile']);
|
||||
$localMobiles[$value['mobile']] = $mobileInfo;
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$mobileInfo = [];
|
||||
Log::info('查询手机归属地失败:' . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
$value['mobileInfo'] = $mobileInfo;
|
||||
// if (!empty($mobileInfo)) {
|
||||
// $value['mobile'] = $value['mobile'] . sprintf('(%s-%s)', $mobileInfo['area'], $mobileInfo['originalIsp']);
|
||||
// }
|
||||
}
|
||||
|
||||
$_oss = [];
|
||||
$_oss[] = [];
|
||||
foreach (Orders::OSS as $key=>$os) {
|
||||
$_oss[$key] = ['label' => $os,'value' => $key];
|
||||
if($key == 1) {
|
||||
|
@ -153,6 +169,12 @@ class OrderController extends base
|
|||
$statss = Orders::DouyinStatus;
|
||||
}elseif ($key == 4) {
|
||||
$statss = Orders::AllOssStatus;
|
||||
}elseif($key ==5) {
|
||||
$statss = Orders::DouyinStatus;
|
||||
}elseif($key ==6) {
|
||||
$statss = Orders::TongchengStatus;
|
||||
}elseif($key ==6) {
|
||||
$statss = Orders::OrderStatus;
|
||||
}
|
||||
|
||||
$_ch = [];
|
||||
|
@ -163,7 +185,7 @@ class OrderController extends base
|
|||
$_oss[$key]['children'] = $_ch;
|
||||
}
|
||||
|
||||
return $this->success($list,null,['timetype'=> Orders::timeType, 'oss' => $_oss]);
|
||||
return $this->success($list,null,['timetype'=> Orders::timeType, 'oss' => array_values($_oss)]);
|
||||
}
|
||||
|
||||
public function all(Request $request) {
|
||||
|
@ -239,9 +261,8 @@ class OrderController extends base
|
|||
if(empty($desc) || empty($status)) return $this->error(2004, '跟进说明需要填写!');
|
||||
if(empty($personnel)) return $this->error(2004, '人员情况需要填写!');
|
||||
if(empty($travel_date)) return $this->error(2004, '出游时间需要填写!');
|
||||
if ($status == 1){
|
||||
if (in_array($status, [0, 1])){
|
||||
if(empty($next_follow)) return $this->error(2004, '下次跟进时间需要填写!');
|
||||
|
||||
}
|
||||
if ($status == 2){
|
||||
$next_follow = '';
|
||||
|
@ -372,6 +393,40 @@ class OrderController extends base
|
|||
return $this->success($backs->append(['order_status_name','os_name']),null, Orders::OSS);
|
||||
}
|
||||
|
||||
// 批量流转出
|
||||
public function backBatch(Request $request) {
|
||||
$sn = $request->post('sn');
|
||||
if (empty($sn) || !is_array($sn)) {
|
||||
return $this->error(2001, '请选择流转的订单');
|
||||
}
|
||||
$toAdminId = $request->post('to_admin_id');
|
||||
if (!$toAdminId) {
|
||||
return $this->error(2001, '请选择流转的客服');
|
||||
}
|
||||
|
||||
// Orders::whereIn('sn', $sn)->update(['admin_id'=> $toAdminId]);
|
||||
|
||||
foreach ($sn as $value) {
|
||||
$item = Orders::where('sn', $value)->find();
|
||||
if($item->admin_id == $toAdminId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Backs::create([
|
||||
'order_id' => $item->id,
|
||||
'admin_id' => $toAdminId,
|
||||
'admin' => $item->admin_id,
|
||||
'apply_id' => $request->admin->id,
|
||||
'status' => 1
|
||||
]);
|
||||
Orders::where('sn', $value)->update(['admin_id'=> $toAdminId]);
|
||||
// 发送短信
|
||||
\app\server\Orders::sendOrderSms($toAdminId, $item);
|
||||
}
|
||||
|
||||
return $this->success(true);
|
||||
}
|
||||
|
||||
//把订单拉回
|
||||
public function back(Request $request) {
|
||||
$sn = $request->post('sn');
|
||||
|
@ -568,6 +623,42 @@ class OrderController extends base
|
|||
}
|
||||
}
|
||||
|
||||
return $this->success(implode("\n", $flow));
|
||||
}catch(\Exception $e) {
|
||||
Log::info(sprintf('oneClickRepair error:%s, %s, %s', $e->getMessage(), $e->getFile(), $e->getLine()) );
|
||||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约处理
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function changeAppointmentStatus(Request $request)
|
||||
{
|
||||
try {
|
||||
$ids = $request->post('id', 0);
|
||||
$idArr = explode(',', $ids);
|
||||
|
||||
$flow = [];
|
||||
foreach ($idArr as $id) {
|
||||
Log::info('同步订单ID:' . $id);
|
||||
|
||||
$order = Orders::where('id', $id)->find();
|
||||
|
||||
if (empty($order)) {
|
||||
return $this->error(2004, '记录没有找到.');
|
||||
}
|
||||
|
||||
// 订单是待使用状态,先同步第三方状态
|
||||
$order['appointment_status'] = 2;
|
||||
$order->save();
|
||||
}
|
||||
|
||||
return $this->success(implode("\n", $flow));
|
||||
}catch(\Exception $e) {
|
||||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\model\Admins;
|
||||
use app\model\Onlines;
|
||||
use app\model\Orders;
|
||||
use app\model\Products;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\Redis;
|
||||
|
||||
class ProductsController extends base {
|
||||
/**
|
||||
* 线路列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function list(Request $request) {
|
||||
$query = Products::where('status', 1)->order('id', 'desc');
|
||||
if($username = $request->get('username')) {
|
||||
$query->where('username', $username);
|
||||
}
|
||||
if($status = $request->get('status')) {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
if($is_order = $request->get('is_order')) {
|
||||
$query->where('is_order', $is_order);
|
||||
}
|
||||
|
||||
$list = $query->paginate($request->get('limit',1000));
|
||||
return $this->success($list,null,['oss' => array_values(array_map(function ($os, $k) {
|
||||
return ['id' => $k, 'os' => $os];
|
||||
}, Orders::OSS, array_keys(Orders::OSS)))]);
|
||||
}
|
||||
|
||||
public function add(Request $request) {
|
||||
if (!$request->post('os')) {
|
||||
return $this->error(2001, '请选择平台.');
|
||||
}
|
||||
if (!$request->post('product_name')) {
|
||||
return $this->error(2001, '线路名称必填');
|
||||
}
|
||||
if (!$request->post('third_product_id')) {
|
||||
return $this->error(2001, '线路id必填');
|
||||
}
|
||||
|
||||
$where = ['os' => $request->post('os'), 'third_product_id' => $request->post('third_product_id')];
|
||||
$product = (new Products())->where($where)->find();
|
||||
if (!empty($product)) {
|
||||
return $this->error(2002, '线路已存在');
|
||||
}
|
||||
|
||||
$product = new Products();
|
||||
$product->os = $request->post('os');
|
||||
$product->third_product_id = $request->post('third_product_id');
|
||||
$product->product_name = $request->post('product_name');
|
||||
$product->status = 1;
|
||||
$product->save();
|
||||
Log::info('product:' . json_encode($product));
|
||||
return $this->success([]);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,18 @@ class QaController extends base
|
|||
}])
|
||||
->paginate($limit);
|
||||
|
||||
$list = json_decode(json_encode($list), true);
|
||||
if (isset($list['data']) && is_array($list['data'])) {
|
||||
foreach ($list['data'] as &$item) {
|
||||
if (isset($item['img_zip']) && !empty($item['img_zip'])) {
|
||||
$item['img_zip'] = json_decode($item['img_zip'], true);
|
||||
}
|
||||
if (isset($item['trip_zip']) && !empty($item['trip_zip'])) {
|
||||
$item['trip_zip'] = json_decode($item['trip_zip'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($list);
|
||||
}
|
||||
|
||||
|
@ -65,8 +77,12 @@ class QaController extends base
|
|||
$list = $list->paginate($request->get('limit',10))->toArray();
|
||||
|
||||
foreach ($list['data'] as &$item) {
|
||||
$item['img_zip'] = $item['img_zip'] ? explode(',', $item['img_zip']) : [];
|
||||
$item['trip_zip'] = $item['trip_zip'] ? explode(',', $item['trip_zip']) : [];
|
||||
if (isset($item['img_zip']) && !empty($item['img_zip'])) {
|
||||
$item['img_zip'] = json_decode($item['img_zip'], true);
|
||||
}
|
||||
if (isset($item['trip_zip']) && !empty($item['trip_zip'])) {
|
||||
$item['trip_zip'] = json_decode($item['trip_zip'], true);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($list);
|
||||
|
@ -90,15 +106,22 @@ class QaController extends base
|
|||
if (empty($post['city_id'])) return $this->error(2001, 'city_id data cannot be empty!');
|
||||
if (empty($post['title'])) return $this->error(2001, 'title data cannot be empty!');
|
||||
|
||||
if ($post['trip_zip']) {
|
||||
$post['trip_zip'] = implode(',', $post['trip_zip']);
|
||||
if ($post['trip_zip'] && is_array($post['trip_zip'])) {
|
||||
$post['trip_zip'] = json_encode($post['trip_zip']);
|
||||
}
|
||||
if ($post['img_zip']) {
|
||||
$post['img_zip'] = implode(',', $post['img_zip']);
|
||||
if ($post['img_zip'] && is_array($post['img_zip'])) {
|
||||
$post['img_zip'] = json_encode($post['img_zip']);
|
||||
}
|
||||
|
||||
$qaQuestion = $post['qaQuestions'] ?? null;
|
||||
unset($post['qaQuestions']);
|
||||
if (isset($post['update_time'])) {
|
||||
unset($post['update_time']);
|
||||
}
|
||||
if (isset($post['id'])) {
|
||||
unset($post['id']);
|
||||
}
|
||||
$post['create_time'] = time();
|
||||
|
||||
try {
|
||||
Db::transaction(function () use ($post,$qaQuestion){
|
||||
|
@ -130,11 +153,11 @@ class QaController extends base
|
|||
unset($post['update_time']);
|
||||
unset($post['qaQuestions']);
|
||||
|
||||
if ($post['trip_zip']) {
|
||||
$post['trip_zip'] = implode(',', $post['trip_zip']);
|
||||
if (isset($post['trip_zip']) && $post['trip_zip']) {
|
||||
$post['trip_zip'] = json_encode($post['trip_zip']);
|
||||
}
|
||||
if ($post['img_zip']) {
|
||||
$post['img_zip'] = implode(',', $post['img_zip']);
|
||||
if (isset($post['img_zip']) && $post['img_zip']) {
|
||||
$post['img_zip'] = json_encode($post['img_zip']);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -19,7 +19,7 @@ class UploadController extends base
|
|||
public function index(Request $request)
|
||||
{
|
||||
$file = $request->file("file");
|
||||
|
||||
|
||||
if (!$file->isValid()) {
|
||||
return $this->error(400, 'upload fail, code=' . $file->getUploadErrorCode());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use app\model\Admins;
|
||||
use app\model\LiveRoomWorks;
|
||||
use app\model\Orders;
|
||||
use app\model\Sales;
|
||||
use app\model\Works;
|
||||
use Carbon\Carbon;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use think\facade\Db;
|
||||
|
||||
class LiveRoomWorkCommand extends Command
|
||||
{
|
||||
|
||||
protected static $defaultName = 'LiveRoomWorkCommand';
|
||||
protected static $defaultDescription = '直播间排班表处理';
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('LiveRoomWorkCommand')
|
||||
->setDescription('直播间排班表处理')
|
||||
->setDefinition(
|
||||
new InputDefinition(array(
|
||||
new InputOption('room_id', 'd', InputOption::VALUE_REQUIRED),
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('LiveRoomWorkService start');
|
||||
// 找出直播已结束的排班
|
||||
$now = Carbon::now()->toDateTimeString();
|
||||
$endRooms = LiveRoomWorks::where([['end', '<', $now]])->whereNull('orders')->select();
|
||||
|
||||
// 统计排班数据
|
||||
foreach ($endRooms as $endRoom) {
|
||||
$orderSum = Orders::where('live_room_work_id', $endRoom->id)
|
||||
->fieldRaw('count(1) as order_num')
|
||||
->fieldRaw('sum(total_price) as total_price')
|
||||
->find();
|
||||
LiveRoomWorks::where('id', $endRoom->id)->update(['orders' => $orderSum->order_num ?? 0, 'total' => $orderSum->total_price ?? 0]);
|
||||
}
|
||||
|
||||
$output->writeln('LiveRoomWorkService end');
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
namespace app\command;
|
||||
|
||||
use app\admin\controller\AdminController;
|
||||
use app\common\Error;
|
||||
use app\model\Admins;
|
||||
use app\model\Blacks;
|
||||
use app\model\FilterMobiles;
|
||||
use app\model\Finances;
|
||||
use app\model\Logs;
|
||||
use app\model\Orders;
|
||||
|
@ -41,10 +44,10 @@ class SpiderDy extends Command
|
|||
);
|
||||
}
|
||||
|
||||
protected function users()
|
||||
protected function users($routeType)
|
||||
{
|
||||
if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->select();
|
||||
// if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
|
||||
$us = [];
|
||||
foreach ($users as $u) {
|
||||
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
|
||||
|
@ -60,11 +63,21 @@ class SpiderDy extends Command
|
|||
|
||||
protected $_redis_pool = [];
|
||||
|
||||
protected function poolUser($status = 0)
|
||||
protected function poolUser($status = 0, $categoryDesc = '')
|
||||
{
|
||||
$routeType = 10;
|
||||
// 抖音境内外类型判断
|
||||
$abroadKeyWords = ['曼谷', '港', '澳', '泰国', '普吉岛', '境外'];
|
||||
foreach ($abroadKeyWords as $kw) {
|
||||
if (mb_strpos($categoryDesc, $kw) !== false) {
|
||||
$routeType = 20;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$status .= $routeType;
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
$this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
|
||||
$users = $this->users();
|
||||
$users = $this->users($routeType);
|
||||
$_users = [];
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
foreach ($users as $user) {
|
||||
|
@ -137,18 +150,6 @@ class SpiderDy extends Command
|
|||
return 1;
|
||||
}
|
||||
|
||||
// echo "状态1\n";
|
||||
// $this->poolUser(1);
|
||||
// echo "状态2\n";
|
||||
// $this->poolUser(2);
|
||||
// echo "状态3\n";
|
||||
// $this->poolUser(3);
|
||||
// echo "状态4\n";
|
||||
// $this->poolUser(4);
|
||||
// echo "状态5\n";
|
||||
// $this->poolUser(5);
|
||||
// return 1;
|
||||
|
||||
// $this->checks($output);
|
||||
// $output->writeln('CHECK spider:dy');
|
||||
|
||||
|
@ -166,9 +167,14 @@ class SpiderDy extends Command
|
|||
// // $this->_kuaishouOrder($start, $end, false);
|
||||
// }
|
||||
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, false);
|
||||
// 8点20 开始分配订单
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$startTime = strtotime(date('Y-m-d 09:10'));
|
||||
if (time() > $startTime) {
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, false);
|
||||
}
|
||||
|
||||
if (date('H') >= 1 && date('H') <= 7) {
|
||||
$this->reload($output);
|
||||
|
@ -228,19 +234,15 @@ class SpiderDy extends Command
|
|||
$order->is_check = 1;
|
||||
$order->check_sn = $json->check_sn;
|
||||
$back = $order->save();
|
||||
echo "订单在自己名下";
|
||||
} else {
|
||||
// echo "订单在自己名下2 $order_id";
|
||||
$order = Orders::where('sn', $order_id)->find();
|
||||
// print_r($order->toArray());
|
||||
if (!empty($order) && $order->admin_id == 0) {
|
||||
echo '订单不在自己的名下,并且没有分人。';
|
||||
$order->is_check = 1;
|
||||
$order->check_sn = $json->check_sn;
|
||||
$order->admin_id = $json->admin_id;
|
||||
$back = $order->save();
|
||||
} elseif (!empty($order) && $order->admin_id !== $json->admin_id) {
|
||||
echo '订单不在自己的名下,并且分人了。';
|
||||
$item = new Orders();
|
||||
$item->os = 1;
|
||||
$item->sn = $order->sn;
|
||||
|
@ -299,7 +301,7 @@ class SpiderDy extends Command
|
|||
{
|
||||
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 6;
|
||||
$pages = 3;
|
||||
$page = 1;
|
||||
|
||||
while (true) {
|
||||
|
@ -328,10 +330,10 @@ class SpiderDy extends Command
|
|||
break;*/
|
||||
|
||||
case 3:
|
||||
// echo '==========pages='.$pages;
|
||||
case 5:
|
||||
try {
|
||||
$dou = new Douyin();
|
||||
$list = $dou->get($page, $start, $end);
|
||||
$dou = new Douyin($k);
|
||||
$list = $dou->get($page, $start, $end, '');
|
||||
$pages = $dou->totalPage;
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . $e);
|
||||
|
@ -344,31 +346,50 @@ class SpiderDy extends Command
|
|||
}
|
||||
|
||||
foreach ($list as $order) {
|
||||
// 过滤一日游
|
||||
if ($order->os == 3 && strpos($order->category_desc, '一日游') !== false) {
|
||||
Log::info("抖音 跳过订单:{$order->order_id}");
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();
|
||||
|
||||
if (empty($item)) {
|
||||
$order->is_zhibo = $this->zhibo($order->product_name, $order->os);
|
||||
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
if (FilterMobiles::isFilterMobile($order->mobile)) {
|
||||
$admin_id = 0;
|
||||
} else {
|
||||
$admin_id = $this->poolUser($order->orderStatus);
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
} else {
|
||||
// $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
|
||||
try {
|
||||
$admin_id = \app\server\Orders::poolUser($order->orderStatus, $order->product_id);
|
||||
} catch (\Exception $exception) {
|
||||
Log::info(sprintf('dy create order fail:%s, order_id:%s', $exception->getMessage(), $order->sn));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($admin_id)) return null;
|
||||
}
|
||||
|
||||
if (empty($admin_id)) return null;
|
||||
$order->admin_id = $admin_id;
|
||||
$order->give_time = time();
|
||||
|
||||
//判断是否需要发短信
|
||||
if (($order->os == 1 && array_key_exists($order->order_status, [1 => 1, 3 => 3])) ||
|
||||
($order->os == 2 && array_key_exists($order->order_status, [2 => 2, 3 => 3, 4 => 4])) ||
|
||||
($order->os == 3 && $order->order_status == 1)) {
|
||||
// $this->sms($admin_id, $order);
|
||||
if ($order->order_status == 1) {
|
||||
$this->sms($admin_id, $order);
|
||||
}
|
||||
|
||||
$work = \app\server\Orders::getLiveRoomWork($order->create_at, $order->product_id);
|
||||
if ($work) {
|
||||
$order->live_room_work_id = $work->id;
|
||||
}
|
||||
|
||||
//新获得一个用户的,提示管理员有新的订单
|
||||
Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
|
||||
$item = new Orders();
|
||||
|
@ -381,6 +402,10 @@ class SpiderDy extends Command
|
|||
}
|
||||
}
|
||||
|
||||
if ($item->order_status !== 2 && $order->order_status == 2) {
|
||||
Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
|
||||
}
|
||||
|
||||
$back = $item->save($order->toArray());
|
||||
|
||||
if ($back) {
|
||||
|
@ -388,6 +413,10 @@ class SpiderDy extends Command
|
|||
}
|
||||
}
|
||||
|
||||
// 数据小于50, 结束
|
||||
if (empty($list)) {
|
||||
break;
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +426,7 @@ class SpiderDy extends Command
|
|||
{
|
||||
$back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
|
||||
if (!$back) return;
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 3)->wherein('status', [1, 2, 3])->select();
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->whereIn('os', [3, 5])->wherein('status', [1, 2, 3])->select();
|
||||
foreach ($orders as $order) {
|
||||
$this->reloadStatus($order->sn, $order->os, $output);
|
||||
}
|
||||
|
@ -422,7 +451,8 @@ class SpiderDy extends Command
|
|||
$it = $m->get(1, null, null, $item->sn);
|
||||
break;*/
|
||||
case 3:
|
||||
$m = new Douyin();
|
||||
case 5:
|
||||
$m = new Douyin($item->os);
|
||||
$it = $m->get(1, null, null, $item->sn);
|
||||
break;
|
||||
|
||||
|
@ -458,18 +488,14 @@ class SpiderDy extends Command
|
|||
{
|
||||
$user = Admins::cache(true)->where('id', $admin_id)->find();
|
||||
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
|
||||
echo "发送短信\n";
|
||||
print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
$has = Blacks::where('mobile', $order->mobile)->find();
|
||||
if (empty($has) && !empty($order->mobile)) {
|
||||
SMS::juhe_sms_send($order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]);
|
||||
} else {
|
||||
echo "黑名单不发送短信\n";
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
} else {
|
||||
echo "不发送短信\n";
|
||||
print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
namespace app\command;
|
||||
|
||||
use app\admin\controller\AdminController;
|
||||
use app\model\Admins;
|
||||
use app\model\Blacks;
|
||||
use app\model\FilterMobiles;
|
||||
use app\model\Finances;
|
||||
use app\model\Logs;
|
||||
use app\model\Orders;
|
||||
|
@ -42,10 +44,10 @@ class SpiderMt extends Command
|
|||
);
|
||||
}
|
||||
|
||||
protected function users()
|
||||
protected function users($routeType)
|
||||
{
|
||||
if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->select();
|
||||
// if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
|
||||
$us = [];
|
||||
foreach ($users as $u) {
|
||||
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
|
||||
|
@ -84,11 +86,13 @@ class SpiderMt extends Command
|
|||
|
||||
protected $_redis_pool = [];
|
||||
|
||||
protected function poolUser($status = 0)
|
||||
protected function poolUser($status = 0, $categoryDesc = '')
|
||||
{
|
||||
$routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
|
||||
$status .= $routeType;
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
$this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
|
||||
$users = $this->users();
|
||||
$users = $this->users($routeType);
|
||||
$_users = [];
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
foreach ($users as $user) {
|
||||
|
@ -134,7 +138,7 @@ class SpiderMt extends Command
|
|||
Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', (array)json_encode($e));
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
throw new \Exception('没有可以分配的用户' . $status . '--' . $categoryDesc);
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
@ -158,21 +162,8 @@ class SpiderMt extends Command
|
|||
|
||||
if ($orderid) {
|
||||
$this->reloadStatus($orderid, $os, $output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// echo "状态1\n";
|
||||
// $this->poolUser(1);
|
||||
// echo "状态2\n";
|
||||
// $this->poolUser(2);
|
||||
// echo "状态3\n";
|
||||
// $this->poolUser(3);
|
||||
// echo "状态4\n";
|
||||
// $this->poolUser(4);
|
||||
// echo "状态5\n";
|
||||
// $this->poolUser(5);
|
||||
// return 1;
|
||||
|
||||
// $this->checks($output);
|
||||
// $output->writeln('CHECK spider:mt');
|
||||
|
||||
|
@ -181,7 +172,7 @@ class SpiderMt extends Command
|
|||
// return 1;
|
||||
|
||||
// sleep(5);
|
||||
|
||||
|
||||
// $time = strtotime(date('Y-m-d'));
|
||||
// for ($i = 0; $i <= $d; $i++) {
|
||||
// $day = $time - $i * 24 * 3600;
|
||||
|
@ -191,9 +182,13 @@ class SpiderMt extends Command
|
|||
// // $this->_kuaishouOrder($start, $end, false);
|
||||
// }
|
||||
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, false);
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$startTime = strtotime(date('Y-m-d 09:10'));
|
||||
if (time() > $startTime) {
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, $orderid);
|
||||
}
|
||||
|
||||
if (date('H') >= 1 && date('H') <= 7) {
|
||||
$this->reload($output);
|
||||
|
@ -253,20 +248,16 @@ class SpiderMt extends Command
|
|||
$order->is_check = 1;
|
||||
$order->check_sn = $json->check_sn;
|
||||
$back = $order->save();
|
||||
echo "订单在自己名下";
|
||||
} else {
|
||||
// echo "订单在自己名下2 $order_id";
|
||||
$order = Orders::where('sn', $order_id)->find();
|
||||
// print_r($order->toArray());
|
||||
if (!empty($order) && $order->admin_id == 0) {
|
||||
echo '订单不在自己的名下,并且没有分人。';
|
||||
$order->is_check = 1;
|
||||
$order->check_sn = $json->check_sn;
|
||||
$order->admin_id = $json->admin_id;
|
||||
$order->give_time = time();
|
||||
$back = $order->save();
|
||||
} elseif (!empty($order) && $order->admin_id !== $json->admin_id) {
|
||||
echo '订单不在自己的名下,并且分人了。';
|
||||
$item = new Orders();
|
||||
$item->os = 1;
|
||||
$item->sn = $order->sn;
|
||||
|
@ -326,7 +317,7 @@ class SpiderMt extends Command
|
|||
{
|
||||
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 6;
|
||||
$pages = 20;
|
||||
$page = 1;
|
||||
|
||||
while (true) {
|
||||
|
@ -335,15 +326,11 @@ class SpiderMt extends Command
|
|||
|
||||
switch ($k) {
|
||||
case 1:
|
||||
case 7:
|
||||
try {
|
||||
$mei = new Meituan();
|
||||
$list = $mei->get($page, $start, $end);
|
||||
$mei = new Meituan($k);
|
||||
$list = $mei->get($page, $start, $end, $order_id);
|
||||
// $pages = $mei->totalPage;
|
||||
|
||||
if ($mei->totalPage === 1) {
|
||||
$pages = 1;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . $e);
|
||||
}
|
||||
|
@ -378,27 +365,42 @@ class SpiderMt extends Command
|
|||
|
||||
$item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();
|
||||
if (empty($item)) {
|
||||
$order->is_zhibo = $this->zhibo($order->product_name, $order->os);
|
||||
//$order->is_zhibo = $this->zhibo($order->product_name, $order->os);
|
||||
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
// 刷单账号
|
||||
if (FilterMobiles::isFilterMobile($order->mobile)) {
|
||||
$admin_id = 0;
|
||||
} else {
|
||||
$admin_id = $this->poolUser($order->orderStatus);
|
||||
}
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (empty($admin_id)) return null;
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
} else {
|
||||
try {
|
||||
// $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
|
||||
$admin_id = \app\server\Orders::poolUser($order->orderStatus, $order->product_id);
|
||||
} catch (\Exception $exception) {
|
||||
Log::info(sprintf('mt create order fail:%s, order_id:%s', $exception->getMessage(), $order->sn));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (empty($admin_id)) return null;
|
||||
}
|
||||
$order->admin_id = $admin_id;
|
||||
$order->give_time = time();
|
||||
|
||||
//判断是否需要发短信
|
||||
if (($order->os == 1 && array_key_exists($order->order_status, [1 => 1, 3 => 3])) ||
|
||||
($order->os == 2 && array_key_exists($order->order_status, [2 => 2, 3 => 3, 4 => 4])) ||
|
||||
($order->os == 3 && $order->order_status == 1)) {
|
||||
$this->sms($admin_id, $order);
|
||||
if ((in_array($order->os, [1, 7]) && array_key_exists($order->order_status, [1 => 1, 3 => 3]))) {
|
||||
if ($admin_id > 0) {
|
||||
$this->sms($admin_id, $order);
|
||||
}
|
||||
}
|
||||
$work = \app\server\Orders::getLiveRoomWork($order->create_at, $order->product_id);
|
||||
if ($work) {
|
||||
$order->live_room_work_id = $work->id;
|
||||
}
|
||||
Log::info(sprintf('mt create order success order_id:%s', $order->sn));
|
||||
//新获得一个用户的,提示管理员有新的订单
|
||||
Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
|
||||
$item = new Orders();
|
||||
|
@ -411,6 +413,10 @@ class SpiderMt extends Command
|
|||
}
|
||||
}
|
||||
|
||||
if ($item->order_status !== 4 && $order->order_status == 4) {
|
||||
Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
|
||||
}
|
||||
|
||||
$back = $item->save($order->toArray());
|
||||
|
||||
if ($back) {
|
||||
|
@ -418,6 +424,10 @@ class SpiderMt extends Command
|
|||
}
|
||||
}
|
||||
|
||||
// 数据小于50, 结束
|
||||
if (empty($list)) {
|
||||
break;
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
}
|
||||
|
@ -440,11 +450,13 @@ class SpiderMt extends Command
|
|||
$item = Orders::where($w)->find();
|
||||
if (empty($item)) {
|
||||
$output->writeln('没有找到订单');
|
||||
return;
|
||||
}
|
||||
$it = null;
|
||||
switch ($item->os) {
|
||||
case 1:
|
||||
$m = new Meituan();
|
||||
case 7:
|
||||
$m = new Meituan($item->os);
|
||||
$it = $m->get(1, null, null, $item->sn);
|
||||
break;
|
||||
/* case 2:
|
||||
|
@ -488,19 +500,16 @@ class SpiderMt extends Command
|
|||
{
|
||||
$user = Admins::cache(true)->where('id', $admin_id)->find();
|
||||
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
|
||||
echo "发送短信\n";
|
||||
print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
$has = Blacks::where('mobile', $order->mobile)->find();
|
||||
if (empty($has) && !empty($order->mobile)) {
|
||||
SMS::juhe_sms_send($order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]);
|
||||
} else {
|
||||
echo "黑名单不发送短信\n";
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
} else {
|
||||
echo "不发送短信\n";
|
||||
print_r([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
Log::info('不发送短信' . json_encode([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,408 @@
|
|||
<?php
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use app\admin\controller\AdminController;
|
||||
use app\model\Admins;
|
||||
use app\model\Blacks;
|
||||
use app\model\Finances;
|
||||
use app\model\Orders;
|
||||
use app\server\SMS;
|
||||
use app\server\Tongcheng;
|
||||
use stdClass;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* 同程数据拉取
|
||||
*/
|
||||
class SpiderTc extends Command
|
||||
{
|
||||
protected static $defaultName = 'spider:tc';
|
||||
protected static $defaultDescription = '同程订单拉取器';
|
||||
|
||||
protected $_users = [];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('spider:tc')
|
||||
->setDescription('同程订单拉取器')
|
||||
->setDefinition(
|
||||
new InputDefinition(array(
|
||||
new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
protected function users($routeType)
|
||||
{
|
||||
// if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
|
||||
$us = [];
|
||||
foreach ($users as $u) {
|
||||
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
|
||||
if (empty($ru)) continue;
|
||||
|
||||
$_u = new stdClass();
|
||||
$_u->username = $u->id;
|
||||
$us[] = $_u;
|
||||
};
|
||||
$this->_users = $us;
|
||||
return $this->_users;
|
||||
}
|
||||
|
||||
protected $_redis_pool = [];
|
||||
|
||||
protected function poolUser($status = 0, $categoryDesc = '')
|
||||
{
|
||||
$routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
|
||||
$status .= $routeType;
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
$this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
|
||||
$users = $this->users($routeType);
|
||||
$_users = [];
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
foreach ($users as $user) {
|
||||
$_users[$user->username] = 0;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, 0);
|
||||
}
|
||||
$this->_redis_pool[$status] = $_users;
|
||||
} else {
|
||||
asort($this->_redis_pool[$status]);
|
||||
$key_users = array_keys($this->_redis_pool[$status]);
|
||||
$username = $key_users[0];
|
||||
$max = $this->_redis_pool[$status][$username];
|
||||
$_users = [];
|
||||
foreach ($users as $user) {
|
||||
$_users[] = $user->username;
|
||||
if (!in_array($user->username, $key_users)) {
|
||||
$this->_redis_pool[$status][$username] = $max;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, $max);
|
||||
}
|
||||
}
|
||||
foreach ($this->_redis_pool[$status] as $username => $val) {
|
||||
if (!in_array($username, $_users)) {
|
||||
unset($this->_redis_pool[$status][$username]);
|
||||
Redis::hDel('CRM:Pool:' . $status, $username);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$username = null;
|
||||
try {
|
||||
$pool = $this->_redis_pool[$status];
|
||||
if (empty($pool)) $pool = [];
|
||||
asort($pool);
|
||||
$keys = array_keys($pool);
|
||||
// if(!!config('app.debug', true)) return 1;
|
||||
if (empty($keys)) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户');
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
$username = $keys[0];
|
||||
$this->_redis_pool[$status][$username] += 1;
|
||||
Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', (array)json_encode($e));
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
/** @var InputInterface $output */
|
||||
protected $output;
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// $name = $input->getArgument('name');
|
||||
$this->output = $output;
|
||||
$output->writeln('START spider:tc:'.date('Y-m-d H:i:s'));
|
||||
|
||||
$os = $input->getOption('os');
|
||||
$orderid = $input->getOption('sn');
|
||||
$d = $input->getOption('day');
|
||||
if (empty($d)) {
|
||||
$d = 40;
|
||||
}
|
||||
|
||||
if ($orderid) {
|
||||
$this->reloadStatus($orderid, $os, $output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// echo "状态1\n";
|
||||
// $this->poolUser(1);
|
||||
// echo "状态2\n";
|
||||
// $this->poolUser(2);
|
||||
// echo "状态3\n";
|
||||
// $this->poolUser(3);
|
||||
// echo "状态4\n";
|
||||
// $this->poolUser(4);
|
||||
// echo "状态5\n";
|
||||
// $this->poolUser(5);
|
||||
// return 1;
|
||||
|
||||
// $this->checks($output);
|
||||
// $output->writeln('CHECK spider:dy');
|
||||
|
||||
// $day = new Douyin();
|
||||
// print_r($day->get(1));
|
||||
// return 1;
|
||||
|
||||
// sleep(5);
|
||||
// $time = strtotime(date('Y-m-d'));
|
||||
// for ($i = 0; $i <= $d; $i++) {
|
||||
// $day = $time - $i * 24 * 3600;
|
||||
// $start = date('Y-m-d', $day);
|
||||
// $end = date('Y-m-d 23:59:59', $day);
|
||||
// $this->orders($start, $end, false);
|
||||
// // $this->_kuaishouOrder($start, $end, false);
|
||||
// }
|
||||
|
||||
// 8点20 开始分配订单
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$startTime = strtotime(date('Y-m-d 09:10'));
|
||||
if (time() > $startTime) {
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$output->writeln('END spider:tc:start:'.$start);
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, false);
|
||||
}
|
||||
|
||||
if (date('H') >= 1 && date('H') <= 7) {
|
||||
$this->reload($output);
|
||||
}
|
||||
|
||||
$output->writeln('END spider:tc:'.date('Y-m-d H:i:s'));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function orders($start = null, $end = null, $order_id = false)
|
||||
{
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 10;
|
||||
$page = 1;
|
||||
while (true) {
|
||||
if ($page > $pages) break;
|
||||
$list = [];
|
||||
|
||||
switch ($k) {
|
||||
case 6:
|
||||
try {
|
||||
$dou = new Tongcheng($k);
|
||||
$list = $dou->get($page, $start, $end, '');
|
||||
$pages = $dou->totalPage;
|
||||
} catch (\Exception $e) {
|
||||
Log::info('同程订单拉取失败:' . dirname(__FILE__) . __LINE__ . $e);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($list as $order) {
|
||||
$item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();
|
||||
|
||||
if (empty($item)) {
|
||||
$order->is_zhibo = 2;
|
||||
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
} else {
|
||||
// $admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
|
||||
try {
|
||||
$admin_id = \app\server\Orders::poolUser($order->orderStatus, $order->product_id);
|
||||
} catch (\Exception $exception) {
|
||||
Log::info(sprintf('tc create order fail:%s, order_id:%s', $exception->getMessage(), $order->sn));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($admin_id)) return null;
|
||||
$order->admin_id = $admin_id;
|
||||
$order->give_time = time();
|
||||
|
||||
//判断是否需要发短信 200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成
|
||||
if (in_array($order->order_status, [200, 205, 210, 310, 300]) ) {
|
||||
$this->sms($admin_id, $order);
|
||||
}
|
||||
$work = \app\server\Orders::getLiveRoomWork($order->create_at, $order->product_id);
|
||||
if ($work) {
|
||||
$order->live_room_work_id = $work->id;
|
||||
}
|
||||
//新获得一个用户的,提示管理员有新的订单
|
||||
Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
|
||||
$item = new Orders();
|
||||
}
|
||||
|
||||
if ($order->travel_date && empty($order->travel_end)) {
|
||||
$days = $this->_days($order);
|
||||
if ($days) {
|
||||
$order->travel_end = date('Y-m-d 00:00:00', strtotime($order->travel_date) + $days * 24 * 3600);
|
||||
}
|
||||
}
|
||||
|
||||
if ($item->order_status !== 2 && $order->order_status == 2) {
|
||||
Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
|
||||
}
|
||||
|
||||
$back = $item->save($order->toArray());
|
||||
|
||||
if ($back) {
|
||||
$this->_finance(0, $item->id, $item->asset_price);
|
||||
}
|
||||
}
|
||||
|
||||
// 数据小于50, 结束
|
||||
if (empty($list)) {
|
||||
break;
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function reload($output)
|
||||
{
|
||||
$back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
|
||||
if (!$back) return;
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 6)->wherein('status', [1, 2, 3])->select();
|
||||
foreach ($orders as $order) {
|
||||
$this->reloadStatus($order->sn, $order->os, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $admin_id
|
||||
* @param $order
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
private function sms($admin_id, $order) {
|
||||
$user = Admins::cache(true)->where('id', $admin_id)->find();
|
||||
$templateId = 261607;
|
||||
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
|
||||
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
$has = Blacks::where('mobile', $order->mobile)->find();
|
||||
if (empty($has) && !empty($order->mobile)) {
|
||||
SMS::juhe_sms_send($order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]);
|
||||
} else {
|
||||
sleep(10);
|
||||
}
|
||||
} else {
|
||||
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
}
|
||||
}
|
||||
|
||||
private function reloadStatus($orderid, $os, $output)
|
||||
{
|
||||
$w[] = ['sn', '=', $orderid];
|
||||
if ($os) $w[] = ['os', '=', $os];
|
||||
$item = Orders::where($w)->find();
|
||||
if (empty($item)) {
|
||||
$output->writeln('没有找到订单');
|
||||
}
|
||||
|
||||
$m = new Tongcheng($os);
|
||||
$it = $m->get(1, null, null, $item->sn);
|
||||
|
||||
|
||||
if ($it) {
|
||||
$back = $item->save($it[0]);
|
||||
if ($back) {
|
||||
$this->_finance(0, $item->id, $item->asset_price);
|
||||
}
|
||||
} else {
|
||||
$output->writeln('没有拉取到数据:' . $orderid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function _days($order)
|
||||
{
|
||||
if (stripos($order->product_name, '一日') !== false) {
|
||||
return 1;
|
||||
}
|
||||
preg_match('/(\d)天/', $order->product_name, $all);
|
||||
if (!empty($all) && intval($all[1]) > 0) {
|
||||
return $all[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function zhibo($title, $os = 0)
|
||||
{
|
||||
if ($os == 3) {
|
||||
|
||||
return 2;
|
||||
}
|
||||
if (
|
||||
strlen($title) - 3 == strripos($title, "!")
|
||||
|| strlen($title) - 1 == strripos($title, "!")
|
||||
) {
|
||||
return 1;
|
||||
} elseif (strlen($title) - 3 == strripos($title, "甄")) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function _finance($type = 1, $order_id = 0, $price = 0)
|
||||
{
|
||||
// $fa = Finances::where('order_id', $order_id)->where('type', $type)->find();
|
||||
$back = Redis::set('CRM:ORDER:LOCK:' . $order_id, time(), 'EX', 6, 'NX');
|
||||
if (!$back) return;
|
||||
|
||||
$total = Finances::where('order_id', $order_id)->sum('total'); //总的关于这个订单的金额
|
||||
//如果总金额大于提交上来的核销金额,那就是退费的
|
||||
//如果提交上来的金额小于总金额,那就是核销的
|
||||
if ($total > $price) {
|
||||
$type = 2;
|
||||
$fee = -($total - $price);
|
||||
} elseif ($total < $price) {
|
||||
$type = 1;
|
||||
$fee = $price - $total;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
Finances::create([
|
||||
'order_id' => $order_id,
|
||||
'type' => $type,
|
||||
'total' => $fee,
|
||||
'status' => 1
|
||||
]);
|
||||
return;
|
||||
|
||||
// if(empty($fa)) {
|
||||
// if($type == 2) {
|
||||
// $has = Finances::where('order_id', $order_id)->where('type', 1)->find();
|
||||
// if(empty($has)) return;
|
||||
// }
|
||||
// Finances::create([
|
||||
// 'order_id' => $order_id,
|
||||
// 'type' => $type,
|
||||
// 'total' => $price,
|
||||
// 'status' => 1
|
||||
// ]);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace app\model;
|
||||
|
||||
use app\common\Keys;
|
||||
use support\Redis;
|
||||
|
||||
class FilterMobiles extends base
|
||||
{
|
||||
/**
|
||||
* @param string $mobile
|
||||
* @param bool $refresh
|
||||
* @return bool
|
||||
* @throws \think\db\exception\BindParamException
|
||||
*/
|
||||
public static function isFilterMobile(string $mobile, bool $refresh = false): bool
|
||||
{
|
||||
$key = 'order_filter_mobiles';
|
||||
|
||||
if ($refresh || !Redis::exists($key)) {
|
||||
$list = self::query()->column('id', 'mobile');
|
||||
|
||||
if (!empty($list)) {
|
||||
$chunks = array_chunk($list, 50, true);
|
||||
|
||||
foreach($chunks as $mobiles) {
|
||||
Redis::hMSet($key, $mobiles);
|
||||
}
|
||||
|
||||
Redis::expire($key, 60*60*24);
|
||||
}
|
||||
}
|
||||
|
||||
return Redis::hExists($key, $mobile);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
namespace app\model;
|
||||
|
||||
class LiveRoom extends base {
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
namespace app\model;
|
||||
|
||||
class LiveRoomWorks extends base {
|
||||
public function zhubo() {
|
||||
return $this->hasOne(Admins::class, 'id', 'zhubo_id')->field(['id', 'name', 'mobile']);
|
||||
}
|
||||
|
||||
public function zhongkong() {
|
||||
return $this->hasOne(Admins::class, 'id', 'zhongkong_id')->field(['id', 'name', 'mobile']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $day
|
||||
* @return LiveRoom[]|array|\think\Collection|\think\db\Query[]|\think\model\Collection
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getDayWork($day, $liveRoomId) {
|
||||
$end = date('Y-m-d', strtotime($day) + 24*60*60);
|
||||
return self::where([
|
||||
['start', '>', $day],
|
||||
['end', '<', $end],
|
||||
'live_room_id' => $liveRoomId,
|
||||
])->with(['zhubo', 'zhongkong'])
|
||||
->order('start', 'desc')
|
||||
->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $roomId
|
||||
* @param $start
|
||||
* @param $end
|
||||
* @return bool
|
||||
*/
|
||||
public static function dayWorkIsExists($id, $roomId, $start, $end) {
|
||||
return self::where([
|
||||
['start', '>', $start],
|
||||
['end', '<', $end],
|
||||
'live_room_id' => $roomId,
|
||||
['id', '!=', $id]
|
||||
])->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $zhuboId
|
||||
* @param $day
|
||||
* @return bool
|
||||
*/
|
||||
public static function zhuboWorkIsExists($id, $zhuboId, $day) {
|
||||
return self::where([
|
||||
'day' => $day,
|
||||
'zhubo_id' => $zhuboId,
|
||||
['id', '!=', $id]
|
||||
])->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $day
|
||||
* @return LiveRoomWorks[]|array|\think\Collection|\think\db\Query[]|\think\model\Collection
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function inWorkAdmin($day) {
|
||||
return self::where(['day' => $day,])->field(['zhubo_id'])->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $adminId
|
||||
* @param $start
|
||||
* @param $end
|
||||
*/
|
||||
public static function staticOrder($type, $adminId, $start, $end) {
|
||||
$field = $type == 3 ? 'zhongkong_id' : 'zhubo_id';
|
||||
return self::where([
|
||||
['start', '>', $start],
|
||||
['end', '<', $end],
|
||||
[$field, '=', $adminId]
|
||||
])->fieldRaw('ifnull(sum(orders), 0) as orders')
|
||||
->fieldRaw('ifnull(sum(total), 0) as total')
|
||||
->fieldRaw('ifnull(sum(asset_total), 0) as asset_total')
|
||||
->fieldRaw('ifnull(sum(TIMESTAMPDIFF(HOUR, `start`, `end`)), 0) as work_time')
|
||||
->find();
|
||||
}
|
||||
}
|
|
@ -16,18 +16,21 @@ class Orders extends base
|
|||
const DouyinReservationStatus = [1 => '未预约', 2 => '待接单', 3 => '已预约', 4 => '已取消', 5 => '已完成', 6 => '取消/退款申请'];
|
||||
const DouyinStatus = [1 => '未核销', 2 => '已核销', 3 => '申请退款中', 4 => '已退款', 5 => '部分核销'];
|
||||
|
||||
// 订单状态(100 - 待付款,150-用户取消,200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成,400-已关闭)
|
||||
const TongchengStatus = [100 => '待付款', 150 => '用户取消', 200 => '待使用', 205 => '预约中(抖音)', 210 => '已预约(抖音)', 310 => '已履约(抖音)', 300 => '已完成', 400 => '已关闭'];
|
||||
|
||||
const AllOssStatus = [1 => '待使用', 2 => '已核销', 3 => '已退款'];
|
||||
// 全部 未核销 已核销 已退款 未付款 已取消 待支付 申请退款中 部分核销
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
|
||||
const AllOssStatusSql = [
|
||||
1 => '((os=1 and order_status=3) or (os=2 and order_status=4) or (os=3 and order_status=1))', //待使用
|
||||
2 => '((os=1 and order_status=4) or (os=2 and order_status=5) or (os=3 and order_status=2))', //已核销
|
||||
3 => '((os=1 and order_status=5) or (os=3 and order_status=4))' //已退款(快手暂无已退款状态)
|
||||
1 => '((os in (1,7) and order_status=3) or (os=2 and order_status=4) or (os in ("3", "5") and order_status=1))', //待使用
|
||||
2 => '((os in (1,7) and order_status=4) or (os=2 and order_status=5) or (os in ("3", "5") and order_status=2))', //已核销
|
||||
3 => '((os in (1,7) and order_status=5) or (os in ("3", "5") and order_status=4))' //已退款(快手暂无已退款状态)
|
||||
];
|
||||
|
||||
const StatusName = ['待跟进', '跟进中', '已核销', '核销失败', '放弃跟单'];
|
||||
const OSS = [1 => '美团', 2 => '快手', 3 => '抖音', 4 => '全平台'];
|
||||
const OSS = [1 => '美团(甄选)', '7' => '美团(新国旅)', 2 => '快手', 3 => '抖音(甄选)', '5' => '抖音(新国旅)', '6' => '同程', 4 => '全平台'];
|
||||
|
||||
const timeType = ['create_time' => '添加记录时间', 'update_time' => '修改记录时间', 'last_follow' => '最后跟进时间', 'next_follow' => '下次跟进时间', 'travel_date' => '出行时间', 'create_at' => '下单时间'];
|
||||
|
||||
|
@ -35,10 +38,14 @@ class Orders extends base
|
|||
|
||||
public function getOrderStatusNameAttr($val)
|
||||
{
|
||||
if ($this->os == 1)
|
||||
if ($this->os == 1 || $this->os == 7)
|
||||
return self::OrderStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 3)
|
||||
return self::DouyinStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 5)
|
||||
return self::DouyinStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 6)
|
||||
return self::TongchengStatus[$this->order_status] ?? '未知';
|
||||
else
|
||||
return self::KuaishouStatus[$this->order_status] ?? '未知';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
namespace app\model;
|
||||
|
||||
class Products extends base {
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
namespace app\server;
|
||||
|
||||
use app\model\ThirdMobileLogs;
|
||||
use support\Log;
|
||||
|
||||
/**
|
||||
* 阿里云市场相关接口
|
||||
*/
|
||||
class AliCloudApiService {
|
||||
/**
|
||||
* @param $mobile
|
||||
* @return array|mixed
|
||||
* @throws \think\db\exception\BindParamException
|
||||
*/
|
||||
public function getMobileArea($mobile) {
|
||||
$host = "https://jumcvit.market.alicloudapi.com";
|
||||
$path = "/mobile/area";
|
||||
$method = "POST";
|
||||
$appcode = "4402db67815049c18a55a996b5644f5b";
|
||||
$headers = array();
|
||||
array_push($headers, "Authorization:APPCODE " . $appcode);
|
||||
//根据API的要求,定义相对应的Content-Type
|
||||
array_push($headers, "Content-Type".":"."application/x-www-form-urlencoded; charset=UTF-8");
|
||||
$bodys = "mobile_number=" . $mobile;
|
||||
$url = $host . $path;
|
||||
|
||||
$aliData = $this->curlRequest($url, $method, $headers, $bodys);
|
||||
if (isset($aliData['code']) && $aliData['code'] == 200) {
|
||||
ThirdMobileLogs::query()->insert([
|
||||
'mobile' => $mobile,
|
||||
'area' => $aliData['data']['area'],
|
||||
'originalIsp' => $aliData['data']['originalIsp'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $aliData['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param $method
|
||||
* @param $headers
|
||||
* @param $bodys
|
||||
* @return mixed
|
||||
*/
|
||||
private function curlRequest($url, $method, $headers, $bodys){
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, false);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
//设定返回信息中是否包含响应信息头,启用时会将响应信息头作为数据流输出,true 表示输出信息头, false表示不输出信息头
|
||||
//如果想将响应结果json字符串转为json数组,建议将 CURLOPT_HEADER 设置成 false
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
if (1 == strpos("$".$url, "https://"))
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $bodys);
|
||||
curl_close($curl);
|
||||
list($header, $body) = explode("\r\n\r\n", curl_exec($curl), 2);
|
||||
return json_decode($body, true);
|
||||
}
|
||||
}
|
|
@ -15,16 +15,19 @@ class Douyin
|
|||
|
||||
private $cookie = '';
|
||||
private $id = '';
|
||||
private $os = '';
|
||||
private $token = '';
|
||||
private $tryTimes = 0;
|
||||
private $gate = 'https://life.douyin.com';
|
||||
public $totalPage = 6;
|
||||
private $keywords = ['泰国', '普吉岛', '西藏', 'S', 'G', 's', 'g'];
|
||||
|
||||
public function __construct()
|
||||
public function __construct($os = 3)
|
||||
{
|
||||
$this->cookie = $this->_cookie();
|
||||
$this->id = $this->_id();
|
||||
$this->token = $this->_token();
|
||||
$this->os = $os;
|
||||
$this->token = $this->_token('', $os);
|
||||
}
|
||||
|
||||
public function login()
|
||||
|
@ -86,7 +89,6 @@ class Douyin
|
|||
|
||||
if ($list && $list->status_code == 0 && !empty($list->order_list)) {
|
||||
foreach ($list->order_list as $order) {
|
||||
echo "抖音 订单号:{$order->order_info->order_id} \n\n";
|
||||
if (empty($cert)) {
|
||||
$cert = $this->_cert($order->order_info->order_id);
|
||||
if (empty($cert)) {
|
||||
|
@ -160,18 +162,19 @@ class Douyin
|
|||
$this->totalPage = 1;
|
||||
return $_list;
|
||||
}
|
||||
echo date('Y-m-d', $start) . '--' . date('Y-m-d', $end) . " 抖音 page:{$page} total_count:" . $list->data->pagination->total_count . " page_count:" . $list->data->pagination->page_count . " \n\n";
|
||||
Log::info(date('Y-m-d', $start) . '--' . date('Y-m-d', $end) . " 抖音 page:{$page} total_count:" . $list->data->pagination->total_count . " page_count:" . $list->data->pagination->page_count );
|
||||
|
||||
foreach ($list->data->list as $order) {
|
||||
echo "抖音 订单号:{$order->order_id} \n\n";
|
||||
Log::info("抖音 订单号:{$order->order_id} \n\n");
|
||||
|
||||
$orderDetail = $this->_orderDetail($order->order_id, $order->status);
|
||||
if (empty($orderDetail)) {
|
||||
Log::info("抖音 订单详情拉取失败:{$order->order_id}");
|
||||
throw new Exception("抖音拉单{$order->order_id}详情获取失败");
|
||||
}
|
||||
|
||||
$item = new Orders();
|
||||
$item->os = 3;
|
||||
$item->os = $this->os;
|
||||
$item->sn = $order->order_id;
|
||||
$item->product_id = $order->sku->sku_id;
|
||||
$item->product_name = $order->sku->title;
|
||||
|
@ -187,8 +190,8 @@ class Douyin
|
|||
$item->asset_status = $order->status ?? 0;
|
||||
$item->category_desc = $order->sku->title;
|
||||
$item->asset_price = $order->amount->verify_amount ?? 0;
|
||||
$item->is_refunded = $item->order_status == 4 ? 1 : 0; // 是否已退款(1-已退款,0-未退款)
|
||||
//抖音的核销金额需要查核销订单
|
||||
|
||||
if ($item->create_at < strtotime('2024-05-22') * 1000) {
|
||||
$this->totalPage = 1;
|
||||
break;
|
||||
|
@ -201,7 +204,7 @@ class Douyin
|
|||
|
||||
//if(mb_strrpos($item->product_name, "S") === false) continue; G 达人 S 自己
|
||||
// if (!(mb_strrpos($item->product_name, "S") || mb_strrpos($item->product_name, "G") || mb_strrpos($item->product_name, "甄"))) continue;
|
||||
|
||||
|
||||
$kw_match = false;
|
||||
|
||||
foreach ($this->keywords as $kw) {
|
||||
|
@ -211,7 +214,7 @@ class Douyin
|
|||
}
|
||||
}
|
||||
|
||||
if (!$kw_match) {
|
||||
if ($this->os == 3 && !$kw_match) {
|
||||
printf("skip order: %s %s\n", $item->sn, $item->product_name);
|
||||
continue;
|
||||
}
|
||||
|
@ -280,64 +283,10 @@ class Douyin
|
|||
return true;
|
||||
}
|
||||
|
||||
/*public function _killMiddleProcesses($pattern, $maxProcesses)
|
||||
{
|
||||
// 检查操作系统是否为 Linux
|
||||
if (PHP_OS !== 'Linux') {
|
||||
echo "当前系统不是 Linux,跳过执行。\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取当前进程的 PID
|
||||
$currentPid = getmypid();
|
||||
|
||||
// 获取进程列表
|
||||
$command = "ps aux | grep '$pattern' | grep -v grep | grep -v '$currentPid' | awk '{print $2,$10}'";
|
||||
$output = [];
|
||||
exec($command, $output);
|
||||
|
||||
$processCount = count($output);
|
||||
|
||||
// 如果进程数量超过最大值,则终止中间部分的 x-12 个进程
|
||||
if ($processCount > $maxProcesses) {
|
||||
$processesToKill = $processCount - $maxProcesses;
|
||||
$processesKilled = 0;
|
||||
|
||||
// 找到运行时间最短的不包含自己的进程并终止它
|
||||
foreach ($output as $line) {
|
||||
list($pid, $runtime) = explode(' ', $line);
|
||||
$runtimeParts = explode(':', $runtime);
|
||||
$hours = intval($runtimeParts[0]);
|
||||
$minutes = intval($runtimeParts[1]);
|
||||
$totalMinutes = $hours * 60 + $minutes;
|
||||
|
||||
|
||||
if ($pid !== $currentPid) {
|
||||
exec("kill -9 $pid");
|
||||
$processesKilled++;
|
||||
|
||||
echo "Killed process with PID: $pid\n";
|
||||
|
||||
if ($processesKilled >= $processesToKill) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($processesKilled === 0) {
|
||||
echo "No processes to kill.\n";
|
||||
}
|
||||
} else {
|
||||
echo "Process count is not over the limit.\n";
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
|
||||
public function _killMiddleProcesses($pattern, $maxProcesses)
|
||||
{
|
||||
// 检查操作系统是否为 Linux
|
||||
if (PHP_OS !== 'Linux') {
|
||||
echo "当前系统不是 Linux,跳过执行。\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -388,14 +337,14 @@ class Douyin
|
|||
exec("kill -9 {$process['pid']}");
|
||||
$processesKilled++;
|
||||
|
||||
echo "Killed process with PID: {$process['pid']}\n";
|
||||
Log::info("Killed process with PID: {$process['pid']}\n");
|
||||
}
|
||||
|
||||
if ($processesKilled === 0) {
|
||||
echo "No processes to kill.\n";
|
||||
Log::info( "No processes to kill.\n");
|
||||
}
|
||||
} else {
|
||||
echo "Process count is not over the limit.\n";
|
||||
Log::info( "Process count is not over the limit.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -408,7 +357,7 @@ class Douyin
|
|||
'order_id' => $orderId,
|
||||
'book_order_id' => '',
|
||||
'status' => $status,
|
||||
'root_life_account_id' => $this->_id()
|
||||
'root_life_account_id' => $this->_id($this->os)
|
||||
]);
|
||||
return $orderDetail->data ?? null;
|
||||
}
|
||||
|
@ -486,22 +435,31 @@ class Douyin
|
|||
|
||||
public function _cookie($data = '')
|
||||
{
|
||||
if ($data) Redis::set('Douyin:cookie', $data);
|
||||
return Redis::get('Douyin:cookie');
|
||||
$key = 'Douyin:cookie';
|
||||
if ($this->os == 5) {
|
||||
$key = 'Douyin:cookie-' . $this->os;
|
||||
}
|
||||
if ($data) Redis::set($key, $data);
|
||||
return Redis::get($key);
|
||||
}
|
||||
|
||||
public function _id($id = '')
|
||||
{
|
||||
if ($id) Redis::set('Douyin:id', $id);
|
||||
return Redis::get('Douyin:id');
|
||||
if ($this->os == 5) {
|
||||
return '7399206501845403686';
|
||||
} else {
|
||||
// return '7259680722519066679';
|
||||
return Redis::get('Douyin:id');
|
||||
}
|
||||
}
|
||||
|
||||
protected $_try = 0;
|
||||
|
||||
public function _token($token = '')
|
||||
{
|
||||
if ($token) Redis::set('Douyin:token', $token, 'ex', 3600 * 24 - 50);
|
||||
$token = Redis::get('Douyin:token');
|
||||
$dyKey = sprintf('Douyin:token-%s', $this->os);
|
||||
if ($token) Redis::set($dyKey, $token, 'ex', 3600 * 24 - 50);
|
||||
$token = Redis::get($dyKey);
|
||||
if (empty($token) && $this->_cookie()) {
|
||||
if ($this->_try > 3) {
|
||||
throw new Exception("cookie 失效");
|
||||
|
@ -509,10 +467,10 @@ class Douyin
|
|||
$id = $this->_curl('/life/gate/v1/user/detail', null, 'HEAD');
|
||||
$this->_try++;
|
||||
if ($id) {
|
||||
Redis::set('Douyin:token', $id, 'ex', 3600 * 24 - 50);
|
||||
Redis::set($dyKey, $id, 'ex', 3600 * 24 - 50);
|
||||
}
|
||||
}
|
||||
return Redis::get('Douyin:token');
|
||||
return Redis::get($dyKey);
|
||||
}
|
||||
|
||||
public function _curl($url, $params, $method = 'GET')
|
||||
|
@ -523,6 +481,7 @@ class Douyin
|
|||
if ($requestCount == 1) {
|
||||
Redis::expire($key, 604800); // 7天
|
||||
}
|
||||
$cookiePath = sprintf(runtime_path() . '%s_dy_cookie.txt', $this->os);
|
||||
|
||||
$http = $this->gate . $url;
|
||||
if ($method == 'GET') {
|
||||
|
@ -540,21 +499,22 @@ class Douyin
|
|||
'Content-type: application/json'
|
||||
];
|
||||
if ($method == 'GET' || $method == 'POST') {
|
||||
$header[] = 'x-secsdk-csrf-token: ' . $this->_token();
|
||||
$header[] = 'x-secsdk-csrf-token: ' . $this->_token('', $this->os);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiePath);
|
||||
$header[] = 'x-secsdk-csrf-request: 1';
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie());
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie(''));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiePath);
|
||||
if ($method == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
|
||||
}
|
||||
|
||||
$body = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
if (!in_array($method, ['GET', 'POST'])) {
|
||||
|
@ -569,6 +529,16 @@ class Douyin
|
|||
}
|
||||
return null;
|
||||
}
|
||||
return json_decode($body);
|
||||
|
||||
$res = json_decode($body);
|
||||
if (!isset($res->status_code) || $res->status_code != 0) {
|
||||
Log::info("抖音 os:{$this->os} \n\n");
|
||||
Log::info( "抖音 body:{$body} \n\n");
|
||||
if ($this->tryTimes > 1) {
|
||||
(new ThirdApiService())->weComNotice($this->os);
|
||||
}
|
||||
$this->tryTimes++;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
|
@ -10,14 +10,17 @@ class Meituan {
|
|||
private $cookie = '';
|
||||
private $gate = 'https://lvyou.meituan.com';
|
||||
public $totalPage = 6;
|
||||
public $os;
|
||||
private $tryTimes = 0;
|
||||
|
||||
public function __construct()
|
||||
public function __construct($os = 1)
|
||||
{
|
||||
$this->os = $os;
|
||||
$this->cookie = $this->_cookie();
|
||||
}
|
||||
|
||||
public function login() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function voucher($check_sn) {
|
||||
|
@ -51,7 +54,7 @@ class Meituan {
|
|||
|
||||
$params = [
|
||||
'page' => $page,
|
||||
'count' => 20,
|
||||
'count' => 50,
|
||||
'orderId' => $orderId,
|
||||
'productId' => '',
|
||||
'orderTimeTo' => $end ?? '',
|
||||
|
@ -74,21 +77,21 @@ class Meituan {
|
|||
}
|
||||
}
|
||||
|
||||
if($list && $list->code == 0) {
|
||||
$this->totalPage = $list->data->totalPage;
|
||||
}
|
||||
|
||||
$_list = [];
|
||||
if($list && $list->code == 0 && $list->data && is_array($list->data->orderList)) {
|
||||
foreach($list->data->orderList as $order) {
|
||||
echo "美团 订单号:{$order->orderId} \n\n";
|
||||
Log::info("美团 订单号:{$order->orderId} \n\n");
|
||||
|
||||
if(in_array($order->orderId, ['',''])) {
|
||||
echo "异常订单:". $order->orderId;
|
||||
Log::info( "异常订单:". $order->orderId);
|
||||
sleep(100);
|
||||
}
|
||||
// 过滤未付款订单
|
||||
if ($order->orderStatus == 1) {
|
||||
continue;
|
||||
}
|
||||
$item = new Orders();
|
||||
$item->os = 1;
|
||||
$item->os = $this->os;
|
||||
$item->sn = $order->orderId;
|
||||
$item->product_id = $order->productId;
|
||||
$item->product_name = $order->productName;
|
||||
|
@ -103,18 +106,21 @@ class Meituan {
|
|||
$item->order_status = $order->orderStatus;
|
||||
$item->refund_status = $order->refundStatus;
|
||||
$item->category_desc = $order->categoryDesc;
|
||||
$item->is_zhibo = $order->bizOrderChannel == 5 ? 1 : 0; // 是否直播(5-视频号,3-小程序)
|
||||
$item->asset_price = $order->orderStatus == 4 ? $order->totalPrice: 0; //已核销订单,核销金额为订单金额
|
||||
$item->is_refunded = $item->order_status == 5 ? 1 : 0; // 是否已退款(1-已退款,0-未退款)
|
||||
|
||||
$_list[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $_list; //返回半成品
|
||||
}
|
||||
|
||||
public function _cookie($data = '') {
|
||||
if($data) Redis::set('Meituan:cookie', $data);
|
||||
return Redis::get('Meituan:cookie');
|
||||
$key = sprintf('Meituan:cookie-%s', $this->os);
|
||||
if($data) Redis::set($key, $data);
|
||||
return Redis::get($key);
|
||||
}
|
||||
|
||||
public function _curl($url, $params, $method = 'GET') {
|
||||
|
@ -132,7 +138,7 @@ class Meituan {
|
|||
}
|
||||
|
||||
$ch = curl_init($http);
|
||||
|
||||
|
||||
$header = [
|
||||
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
|
||||
'Sec-Ch-Ua-Platform: "Windows"',
|
||||
|
@ -149,8 +155,19 @@ class Meituan {
|
|||
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
|
||||
}
|
||||
|
||||
echo $body = curl_exec($ch);
|
||||
$body = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return json_decode($body);
|
||||
$res = json_decode($body);
|
||||
if (!isset($res->code) || $res->code != 0) {
|
||||
Log::info('os:' . $this->os);
|
||||
Log::info('http:' . $http);
|
||||
Log::info('body:' . $body);
|
||||
|
||||
if ($this->tryTimes > 1) {
|
||||
(new ThirdApiService())->weComNotice($this->os);
|
||||
}
|
||||
$this->tryTimes++;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
|
@ -3,27 +3,34 @@
|
|||
namespace app\server;
|
||||
|
||||
use app\common\Error;
|
||||
use app\model\Admins;
|
||||
use app\model\Admins as AdminsModel;
|
||||
use app\model\Blacks;
|
||||
use app\model\FilterMobiles;
|
||||
use app\model\Finances as FinancesModel;
|
||||
use app\model\LiveRoomWorks;
|
||||
use app\model\Orders as OrdersModel;
|
||||
use app\model\Products;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
|
||||
class Orders {
|
||||
public static function isDaishiyong(OrdersModel $order): bool
|
||||
protected static $redisPool = [];
|
||||
public static function isDaishiyong(OrdersModel $order): bool
|
||||
{
|
||||
// 根据 OrdersModel::AllOssStatusSql[1] 进行判断
|
||||
// ((os=1 and order_status=3) or (os=2 and order_status=4) or (os=3 and order_status=1))
|
||||
return $order->os == 1 && $order->order_status == 3
|
||||
|| $order->os == 2 && $order->order_status == 4
|
||||
|| $order->os == 3 && $order->order_status == 1;
|
||||
return (in_array($order->os, [1, 7]) && $order->order_status == 3)
|
||||
|| ($order->os == 2 && $order->order_status == 4)
|
||||
|| (in_array($order->os, [3, 5]) && in_array($order->order_status, [1, 5]))
|
||||
|| (in_array($order->os, [6]) && in_array($order->order_status, [200]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @params []OrdersModel $order
|
||||
* @return array
|
||||
*/
|
||||
public static function reminderOrders(OrdersModel ...$orders)
|
||||
public static function reminderOrders(OrdersModel ...$orders)
|
||||
{
|
||||
$admin_ids = [];
|
||||
$sns = [];
|
||||
|
@ -42,6 +49,7 @@ class Orders {
|
|||
$ttl = 86400;
|
||||
$result = [];
|
||||
|
||||
$admins = array_column($admins, null, 'id');
|
||||
foreach($orders as $order) {
|
||||
$admin_mobile = $admins[$order->admin_id] ?? '';
|
||||
|
||||
|
@ -49,6 +57,11 @@ class Orders {
|
|||
$result[$order->sn] = Error::undefined('client mobile or admin mobile invalid');
|
||||
continue;
|
||||
}
|
||||
if (FilterMobiles::isFilterMobile($order->mobile)) {
|
||||
$result[$order->sn] = Error::undefined('刷单账单');
|
||||
continue;
|
||||
}
|
||||
$admin_mobile = $admin_mobile['mobile'] ?? '';
|
||||
|
||||
if (Blacks::CExists($order->mobile)) {
|
||||
$result[$order->sn] = Error::ERR_SMS_BLACKS;
|
||||
|
@ -75,17 +88,18 @@ class Orders {
|
|||
|
||||
$result[$order->sn] = [];
|
||||
}
|
||||
|
||||
|
||||
return count($orders) > 1 ? $result : reset($result);
|
||||
}
|
||||
|
||||
public static function syncFromThird(OrdersModel $order)
|
||||
{
|
||||
$got = null;
|
||||
|
||||
|
||||
switch ($order->os) {
|
||||
case 1:
|
||||
$mt = new Meituan();
|
||||
case 7:
|
||||
$mt = new Meituan($order->os);
|
||||
$it = $mt->get(1, null, null, $order->sn);
|
||||
|
||||
if ($it) {
|
||||
|
@ -94,13 +108,14 @@ class Orders {
|
|||
|
||||
break;
|
||||
case 3:
|
||||
$dy = new Douyin();
|
||||
case 5:
|
||||
$dy = new Douyin($order->os);
|
||||
$it = $dy->get(1, null, null, $order->sn);
|
||||
if ($it) {
|
||||
$got = $it[0];
|
||||
|
||||
// 查询未预约状态
|
||||
if ($order->appointment_status != 1) {
|
||||
if ($order->appointment_status == 0) {
|
||||
$appointment_status = $dy->_orderMakeAppointmentStatus($order->sn);
|
||||
if ($appointment_status !== null) {
|
||||
$got['appointment_status'] = 1;
|
||||
|
@ -108,6 +123,14 @@ class Orders {
|
|||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 6:
|
||||
$tc = new Tongcheng($order->os);
|
||||
$it = $tc->get(1, null, null, $order->sn);
|
||||
|
||||
if ($it) {
|
||||
$got = $it[0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -128,7 +151,7 @@ class Orders {
|
|||
public static function finance($type = 1, $order_id = 0, $price = 0)
|
||||
{
|
||||
//总的关于这个订单的金额
|
||||
$total = FinancesModel::where('order_id', $order_id)->sum('total');
|
||||
$total = FinancesModel::where('order_id', $order_id)->sum('total');
|
||||
//如果总金额大于提交上来的核销金额,那就是退费的
|
||||
//如果提交上来的金额小于总金额,那就是核销的
|
||||
|
||||
|
@ -165,7 +188,8 @@ class Orders {
|
|||
$got = null;
|
||||
switch ($order->os) {
|
||||
case 1:
|
||||
$mt = new Meituan();
|
||||
case 7:
|
||||
$mt = new Meituan($order->os);
|
||||
$it = $mt->get(1, null, null, $order->sn);
|
||||
|
||||
if ($it) {
|
||||
|
@ -174,7 +198,8 @@ class Orders {
|
|||
|
||||
break;
|
||||
case 3:
|
||||
$dy = new Douyin();
|
||||
case 5:
|
||||
$dy = new Douyin($order->os);
|
||||
$it = $dy->get(1, null, null, $order->sn);
|
||||
if ($it) {
|
||||
$got = $it[0];
|
||||
|
@ -196,4 +221,134 @@ class Orders {
|
|||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $orderCreateTime
|
||||
* @param $productId
|
||||
* @return array|mixed|\think\Model
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getLiveRoomWork(int $orderCreateTime, $productId) {
|
||||
$orderCreateDate = date('Y-m-d H:i:s', $orderCreateTime/1000);
|
||||
$roomWork = LiveRoomWorks::join('live_room', 'live_room_works.live_room_id=live_room.id')
|
||||
->where('live_room_works.start', '<', $orderCreateDate)
|
||||
->where('live_room_works.end', '>', $orderCreateDate)
|
||||
->whereRaw(sprintf('find_in_set(%s, live_room.`product_ids`)', $productId))
|
||||
->field(['live_room_works.id'])
|
||||
->find();
|
||||
|
||||
return $roomWork;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配用户
|
||||
* @param int $status
|
||||
* @param string $categoryDesc
|
||||
* @return int|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function poolUser($status, $thirdProductId) {
|
||||
$status .= $thirdProductId;
|
||||
if (empty(self::$redisPool[$status])) {
|
||||
self::$redisPool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
|
||||
$users = self::users($thirdProductId);
|
||||
shuffle($users);
|
||||
$_users = [];
|
||||
if (empty(self::$redisPool[$status])) {
|
||||
foreach ($users as $user) {
|
||||
$_users[$user->username] = 0;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, 0);
|
||||
}
|
||||
self::$redisPool[$status] = $_users;
|
||||
} else {
|
||||
asort(self::$redisPool[$status]);
|
||||
$key_users = array_keys(self::$redisPool[$status]);
|
||||
$username = $key_users[0];
|
||||
$max = self::$redisPool[$status][$username];
|
||||
$_users = [];
|
||||
foreach ($users as $user) {
|
||||
$_users[] = $user->username;
|
||||
if (!in_array($user->username, $key_users)) {
|
||||
self::$redisPool[$status][$username] = $max;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, $max);
|
||||
}
|
||||
}
|
||||
foreach (self::$redisPool[$status] as $username => $val) {
|
||||
if (!in_array($username, $_users)) {
|
||||
unset(self::$redisPool[$status][$username]);
|
||||
Redis::hDel('CRM:Pool:' . $status, $username);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$username = null;
|
||||
try {
|
||||
$pool = self::$redisPool[$status];
|
||||
if (empty($pool)) $pool = [];
|
||||
asort($pool);
|
||||
$keys = array_keys($pool);
|
||||
if (empty($keys)) {
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
$username = $keys[0];
|
||||
self::$redisPool[$status][$username] += 1;
|
||||
Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', func_get_args());
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $thirdProductId
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
protected static function users($thirdProductId) {
|
||||
$product = Products::query()->where('third_product_id', $thirdProductId)->find();
|
||||
if (empty($product)) {
|
||||
return [];
|
||||
}
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->whereFindInSet('product_ids', $product->id)->select();
|
||||
$us = [];
|
||||
foreach ($users as $u) {
|
||||
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
|
||||
if (empty($ru)) continue;
|
||||
|
||||
$_u = new \stdClass();
|
||||
$_u->username = $u->id;
|
||||
$us[] = $_u;
|
||||
};
|
||||
|
||||
return $us;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送订单短信
|
||||
* @param $admin_id
|
||||
* @param $order
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function sendOrderSms($admin_id, $order)
|
||||
{
|
||||
$user = Admins::cache(true)->where('id', $admin_id)->find();
|
||||
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
|
||||
$has = Blacks::where('mobile', $order->mobile)->find();
|
||||
if (empty($has) && !empty($order->mobile)) {
|
||||
SMS::juhe_sms_send($order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]);
|
||||
} else {
|
||||
sleep(10);
|
||||
}
|
||||
} else {
|
||||
Log::info('订单未发送短息:' . json_encode([$order->mobile, 261607, ['title' => $order->product_name, 'mobile' => $user->mobile]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
namespace app\server;
|
||||
|
||||
use app\model\Orders;
|
||||
use app\model\ThirdMobileLogs;
|
||||
use http\Client;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
|
||||
/**
|
||||
* 阿里云市场相关接口
|
||||
*/
|
||||
class ThirdApiService {
|
||||
private $notice = '%s token已过期,请及时更换';
|
||||
|
||||
/**
|
||||
* @param $mobile
|
||||
* @return array|mixed
|
||||
* @throws \think\db\exception\BindParamException
|
||||
*/
|
||||
public function getMobileArea($mobile) {
|
||||
$host = "https://jumcvit.market.alicloudapi.com";
|
||||
$path = "/mobile/area";
|
||||
$method = "POST";
|
||||
$appcode = "4402db67815049c18a55a996b5644f5b";
|
||||
$headers = array();
|
||||
array_push($headers, "Authorization:APPCODE " . $appcode);
|
||||
//根据API的要求,定义相对应的Content-Type
|
||||
array_push($headers, "Content-Type".":"."application/x-www-form-urlencoded; charset=UTF-8");
|
||||
$bodys = "mobile_number=" . $mobile;
|
||||
$url = $host . $path;
|
||||
|
||||
$aliData = $this->curlMobileRequest($url, $method, $headers, $bodys);
|
||||
if (isset($aliData['code']) && $aliData['code'] == 200) {
|
||||
ThirdMobileLogs::query()->insert([
|
||||
'mobile' => $mobile,
|
||||
'area' => $aliData['data']['area'],
|
||||
'originalIsp' => $aliData['data']['originalIsp'],
|
||||
]);
|
||||
}
|
||||
|
||||
return $aliData['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param $method
|
||||
* @param $headers
|
||||
* @param $bodys
|
||||
* @return mixed
|
||||
*/
|
||||
private function curlMobileRequest($url, $method, $headers, $bodys){
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, false);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
//设定返回信息中是否包含响应信息头,启用时会将响应信息头作为数据流输出,true 表示输出信息头, false表示不输出信息头
|
||||
//如果想将响应结果json字符串转为json数组,建议将 CURLOPT_HEADER 设置成 false
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
if (1 == strpos("$".$url, "https://"))
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $bodys);
|
||||
curl_close($curl);
|
||||
list($header, $body) = explode("\r\n\r\n", curl_exec($curl), 2);
|
||||
return json_decode($body, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企微提醒
|
||||
* @param $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function weComNotice($os) {
|
||||
$url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=e138b55c-2886-4729-922e-9a8c753f75ee';
|
||||
$method = 'POST';
|
||||
$message = sprintf($this->notice, Orders::OSS[$os] ?? '');
|
||||
$bodys = [
|
||||
'msgtype' => 'text',
|
||||
'text' => [
|
||||
'content' => $message
|
||||
]
|
||||
];
|
||||
|
||||
$key = 'notice-' . $os;
|
||||
if (Redis::setNx($key, 1)) {
|
||||
Redis::expire($key, 600); // 十分钟内通知一次
|
||||
$this->curlRequest($url, $method, [], $bodys);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param $method
|
||||
* @param $headers
|
||||
* @param $bodys
|
||||
* @return mixed
|
||||
*/
|
||||
private function curlRequest($url, $method, $headers, $bodys){
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, false);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
//设定返回信息中是否包含响应信息头,启用时会将响应信息头作为数据流输出,true 表示输出信息头, false表示不输出信息头
|
||||
//如果想将响应结果json字符串转为json数组,建议将 CURLOPT_HEADER 设置成 false
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
if (1 == strpos("$".$url, "https://"))
|
||||
{
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
|
||||
}
|
||||
if (is_array($bodys)) {
|
||||
$bodys = json_encode($bodys);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $bodys);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array_merge($headers, [
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($bodys)
|
||||
]));
|
||||
curl_close($curl);
|
||||
list($header, $body) = explode("\r\n\r\n", curl_exec($curl), 2);
|
||||
Log::info(sprintf('third req:%s, res:%s', $url, $body));
|
||||
return json_decode($body, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
<?php
|
||||
|
||||
namespace app\server;
|
||||
|
||||
use app\model\Orders;
|
||||
use Exception;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
/**
|
||||
* 同程订单处理
|
||||
*/
|
||||
class Tongcheng {
|
||||
private $os = '';
|
||||
protected $cookie;
|
||||
private $gate = 'https://ebk.17u.cn';
|
||||
public $totalPage = 6;
|
||||
private $tryTimes = 0;
|
||||
|
||||
public function __construct($os = 6)
|
||||
{
|
||||
$this->cookie = $this->_cookie();
|
||||
$this->os = $os;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ModelNotFoundException
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($page, $start = null, $end = null, $orderId = '')
|
||||
{
|
||||
if (empty($start) || empty($end)) {
|
||||
$start = date('Y-m-d 00:00:00');
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
}
|
||||
|
||||
if ($orderId) {
|
||||
$start = $end = null;
|
||||
}
|
||||
|
||||
$_list = [];
|
||||
$list = $this->_certificateList($start, $end, $page, $orderId);
|
||||
if (empty($list->data->list) || $list->code != 1000) {
|
||||
$this->totalPage = 1;
|
||||
return $_list;
|
||||
}
|
||||
Log::info($start . '--' . $end . " 同程 page:{$page} total_count:" . $list->data->totalCount . " page_count:" . $list->data->totalPage);
|
||||
|
||||
foreach ($list->data->list as $order) {
|
||||
Log::info("同程 订单号:{$order->orderId} \n\n");
|
||||
|
||||
// $orderDetail = $this->_orderDetail($order->order_id, $order->status);
|
||||
// if (empty($orderDetail)) {
|
||||
// Log::info("同程 订单详情拉取失败:{$order->order_id}");
|
||||
// throw new Exception("同程拉单{$order->order_id}详情获取失败");
|
||||
// }
|
||||
|
||||
$order->orderAmount = $order->orderAmount * 100;
|
||||
$item = new Orders();
|
||||
$item->os = $this->os;
|
||||
$item->sn = $order->orderId;
|
||||
$item->product_id = $order->lineId;
|
||||
$item->product_name = $order->title;
|
||||
$item->category_id = $order->agentFinderId;
|
||||
$item->category_desc = $order->agentFinderNickname;
|
||||
$item->create_at = strtotime($order->createTime) * 1000;
|
||||
$item->mobile = $order->mobile;
|
||||
$item->travel_date = null;
|
||||
$item->total_price = $order->orderAmount;
|
||||
$item->quantity = $order->productCount;
|
||||
$item->unit_price = $order->orderAmount/$order->productCount;
|
||||
$item->actual_price = $order->orderAmount;
|
||||
$item->order_status = $order->orderStatus; // 订单状态(100 - 待付款,150-用户取消,200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成,400-已关闭)
|
||||
$item->appointment_status = in_array($order->orderStatus, [210, 310, 300]) ? 1 : 0; // 是否已预约
|
||||
|
||||
$item->asset_status = $order->status ?? 0; // 核销状态
|
||||
$item->asset_price = $order->orderStatus == 300 ? $order->orderAmount : 0; // 核销金额
|
||||
//抖音的核销金额需要查核销订单
|
||||
|
||||
$_list[] = $item;
|
||||
}
|
||||
|
||||
return $_list; //返回半成品
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function _certificateList($start, $end, $page, $orderId)
|
||||
{
|
||||
$params = [
|
||||
'begin' => $start,// 开始时间,格式:2024-09-01 00:00:00
|
||||
'end' => $end,// 结束时间 格式:2024-09-01 00:00:00
|
||||
'orderStatus' => "",// 订单状态
|
||||
'current' => $page, // 当前数量
|
||||
'size' => 50, // 显示数量
|
||||
'orderId' => $orderId, // 订单号
|
||||
];
|
||||
$this->_getRetriesLock();
|
||||
|
||||
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
|
||||
if (empty($list) || $list->code != 1000) {
|
||||
$this->_getRetriesLock();
|
||||
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
|
||||
if (empty($list) || $list->code != 1000) {
|
||||
Log::error('===查询时间:' . $start . '--' . $end . '====certificate_list: ' . json_encode($list));
|
||||
throw new Exception("同程拉单失败,Err:" . json_encode($list));
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function _getRetriesLock(): bool
|
||||
{
|
||||
$pattern = 'php webman spider:tc';
|
||||
$maxProcesses = 8;
|
||||
$this->_killMiddleProcesses($pattern, $maxProcesses);
|
||||
|
||||
|
||||
$maxRetries = 5;
|
||||
$retries = 0;
|
||||
while ($retries < $maxRetries) {
|
||||
$back = Redis::set('SpiderTc:CertificateList:lock', time(), 'EX', 1, 'NX');
|
||||
if ($back) {
|
||||
break;
|
||||
}
|
||||
$retries++;
|
||||
sleep(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function _killMiddleProcesses($pattern, $maxProcesses)
|
||||
{
|
||||
// 检查操作系统是否为 Linux
|
||||
if (PHP_OS !== 'Linux') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取当前进程的 PID
|
||||
$currentPid = getmypid();
|
||||
|
||||
// 获取进程列表
|
||||
$command = "ps aux | grep '$pattern' | grep -v grep | grep -v '$currentPid' | awk '{print $2,$10}'";
|
||||
$output = [];
|
||||
exec($command, $output);
|
||||
|
||||
$processList = [];
|
||||
foreach ($output as $line) {
|
||||
list($pid, $runtime) = explode(' ', $line);
|
||||
$runtimeParts = explode(':', $runtime);
|
||||
$hours = intval($runtimeParts[0]);
|
||||
$minutes = intval($runtimeParts[1]);
|
||||
$totalMinutes = $hours * 60 + $minutes;
|
||||
$processList[] = ['pid' => $pid, 'runtime' => $totalMinutes];
|
||||
}
|
||||
|
||||
// 按运行时间排序
|
||||
usort($processList, function ($a, $b) {
|
||||
return $a['runtime'] <=> $b['runtime'];
|
||||
});
|
||||
|
||||
// 过滤掉当前 PID 和运行时间最短的 PID
|
||||
if (!empty($processList)) {
|
||||
array_shift($processList); // 移除运行时间最短的
|
||||
}
|
||||
$processList = array_filter($processList, function ($process) use ($currentPid) {
|
||||
return $process['pid'] != $currentPid;
|
||||
});
|
||||
|
||||
$processCount = count($processList);
|
||||
|
||||
// 如果进程数量超过最大值,则终止中间部分的进程
|
||||
if ($processCount > $maxProcesses) {
|
||||
$processesToKill = $processCount - $maxProcesses;
|
||||
$processesKilled = 0;
|
||||
|
||||
// 杀死运行时间最短的进程
|
||||
foreach ($processList as $process) {
|
||||
if ($processesKilled >= $processesToKill) {
|
||||
break;
|
||||
}
|
||||
|
||||
exec("kill -9 {$process['pid']}");
|
||||
$processesKilled++;
|
||||
|
||||
Log::info("Killed process with PID: {$process['pid']}\n");
|
||||
}
|
||||
|
||||
if ($processesKilled === 0) {
|
||||
Log::info("No processes to kill.\n");
|
||||
}
|
||||
} else {
|
||||
Log::info("Process count is not over the limit.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function _orderDetail($orderId = null, $status = null)
|
||||
{
|
||||
$orderDetail = $this->_curl("/life/trip/v2/travel_agency/book/detail", [
|
||||
'order_id' => $orderId,
|
||||
'book_order_id' => '',
|
||||
'status' => $status,
|
||||
]);
|
||||
return $orderDetail->data ?? null;
|
||||
}
|
||||
|
||||
public function _cookie($data = '')
|
||||
{
|
||||
$key = 'Tongcheng:cookie-' . $this->os;
|
||||
if ($data) Redis::set($key, $data);
|
||||
return Redis::get($key);
|
||||
}
|
||||
|
||||
public function _curl($url, $params, $method = 'GET')
|
||||
{
|
||||
// 请求次数统计
|
||||
$key = sprintf("Tongcheng:ReqiestCount:%s", date('Y-m-d'));
|
||||
$requestCount = Redis::incrBy($key, 1);
|
||||
if ($requestCount == 1) {
|
||||
Redis::expire($key, 604800); // 7天
|
||||
}
|
||||
$cookiePath = sprintf(runtime_path() . '%s_tc_cookie.txt', $this->os);
|
||||
|
||||
$http = $this->gate . $url;
|
||||
if ($method == 'GET') {
|
||||
$http = $http . '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
$ch = curl_init($http);
|
||||
|
||||
$header = [
|
||||
'Content-type: application/json'
|
||||
];
|
||||
if ($method == 'GET' || $method == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiePath);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie());
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiePath);
|
||||
if ($method == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
|
||||
}
|
||||
$body = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
if (!in_array($method, ['GET', 'POST'])) {
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($body, 0, $header_size);
|
||||
$in = explode("\n", $body);
|
||||
foreach ($in as $i) {
|
||||
if (stripos($i, 'x-ware-csrf-token') !== false) {
|
||||
$inn = explode(',', $i);
|
||||
return $inn[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$res = json_decode($body);
|
||||
if (!isset($res->code) || $res->code != 1000) {
|
||||
Log::info( "同城 body:{$body} \n\n");
|
||||
if ($this->tryTimes > 1) {
|
||||
(new ThirdApiService())->weComNotice($this->os);
|
||||
}
|
||||
$this->tryTimes++;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
.app-container[data-v-45d18cae]{position:relative;padding-bottom:60px}.el-table[data-v-45d18cae],.filter-container[data-v-45d18cae]{padding-bottom:52px}.search[data-v-45d18cae]{margin-left:10px}
|
|
@ -1 +0,0 @@
|
|||
.pagination-container[data-v-6af373ef]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-6af373ef]{display:none}
|
|
@ -0,0 +1 @@
|
|||
.app-container[data-v-7aa35cbf]{position:relative;padding-bottom:60px}.el-table[data-v-7aa35cbf],.filter-container[data-v-7aa35cbf]{padding-bottom:52px}.search[data-v-7aa35cbf]{margin-left:10px}
|
|
@ -1 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-d6692e38]{position:relative;padding-bottom:60px}.el-table[data-v-d6692e38],.filter-container[data-v-d6692e38]{padding-bottom:52px}
|
||||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-6226c3ab]{position:relative;padding-bottom:60px}.el-table[data-v-6226c3ab],.filter-container[data-v-6226c3ab]{padding-bottom:52px}
|
|
@ -0,0 +1 @@
|
|||
.app-container[data-v-97931c7e]{position:relative;padding-bottom:60px}[data-v-97931c7e] .el-tabs__nav-wrap:after{display:none}.el-table[data-v-97931c7e],.filter-container[data-v-97931c7e]{padding-bottom:5px}[data-v-97931c7e] .el-row{height:50px;line-height:50px}.head_lable[data-v-97931c7e]{font-size:14px;color:#3d3d3d;font-weight:700;margin-right:10px}.scheduling_head[data-v-97931c7e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:28px}.scheduling_tab[data-v-97931c7e]{display:inline-block;padding:12px 28px;font-size:16px;border:1px solid #e2e2e2;border-radius:5px;cursor:pointer}.scheduling_tab+.scheduling_tab[data-v-97931c7e]{margin-left:10px}.active[data-v-97931c7e]{border-color:#1269ff}.el-icon-circle-plus[data-v-97931c7e]{color:#367af0;font-size:16px}.scheduling_tab_pana[data-v-97931c7e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.scheduling_tab_pana .table-list[data-v-97931c7e]{-ms-flex-preferred-size:14.3%;flex-basis:14.3%}.scheduling_tab_pana .table-list .table-list_item[data-v-97931c7e]{height:56px;background:#e4ecff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid #d7ddeb;margin-right:-1px;margin-bottom:-1px}.scheduling_tab_pana .table-list .table-list_item .tit[data-v-97931c7e]{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;justify-content:space-evenly}.scheduling_tab_pana .table-list .table-list-box[data-v-97931c7e]{padding:15px;font-size:14px;color:#fff;border:1px solid #d7ddeb;margin-right:-1px;margin-bottom:-1px}.scheduling_tab_pana .table-list .table-list-box .border[data-v-97931c7e]{padding:13px;background:#367af0;cursor:pointer}
|
|
@ -1 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-29e14a4a]{position:relative;padding-bottom:60px}.el-table[data-v-29e14a4a],.filter-container[data-v-29e14a4a]{padding-bottom:5px}
|
||||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-4d8f2a06]{position:relative;padding-bottom:60px}.el-table[data-v-4d8f2a06],.filter-container[data-v-4d8f2a06]{padding-bottom:5px}
|
|
@ -0,0 +1 @@
|
|||
@font-face{font-family:PingFang;src:url(../../static/fonts/PingFang\ SC.212ada59.ttf);font-weight:400;font-style:normal}body[data-v-2a6e779e]{font-family:PingFang!important}.infinite-list[data-v-2a6e779e]{list-style-type:none;height:calc(100vh - 154px);padding:0;margin:0}.desc_container+.desc_container[data-v-2a6e779e]{margin-top:10px;padding-top:10px}.desc_container .desc_title[data-v-2a6e779e]{font-size:18px;font-weight:500;color:#333;line-height:25px;margin-bottom:10px}.desc_container .desc_content[data-v-2a6e779e]{font-size:14px;font-weight:300}.problem .problem_form[data-v-2a6e779e]{margin-top:10px;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.problem .problem_container[data-v-2a6e779e],.problem .problem_form[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex}.problem .problem_container .problem_left[data-v-2a6e779e]{font-family:PingFang,sans-serif;font-weight:300;width:18%;background:#fff;padding:0 20px;border-right:2px solid #46a6ff;height:calc(100vh - 154px)}.problem .problem_container .problem_left .btn[data-v-2a6e779e]{color:#fff;padding:10px 20px;cursor:pointer;text-align:center;background:#46a6ff;border-radius:10px}.problem .problem_container .problem_left .btn+.btn[data-v-2a6e779e]{margin-top:10px}.problem .problem_container .problem_right[data-v-2a6e779e]{width:100%;background:#fff;padding:0 20px}.problem .problem_container .problem_right .problem_right_container+.problem_right_container[data-v-2a6e779e]{margin-top:20px}.problem .problem_container .problem_right .problem_right_container .title[data-v-2a6e779e]{font-size:20px;font-weight:600;margin-bottom:10px;color:#46a6ff}.problem .problem_container .problem_right .problem_right_container .title[data-v-2a6e779e]>:first-child{margin-right:40px}.problem .problem_container .problem_right .problem_right_container .desc[data-v-2a6e779e]{font-size:14px;color:#666;line-height:24px}.problem .problem_container .problem_right .problem_right_container .desc .copy-button[data-v-2a6e779e]{margin-left:300px}.image-list-horizontal[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex;overflow-x:auto;white-space:nowrap;padding:10px 0}.image-card[data-v-2a6e779e]{display:inline-block;width:150px;margin-right:10px}.image-preview[data-v-2a6e779e]{width:100%;height:100px;-o-object-fit:cover;object-fit:cover}.image-preview-full[data-v-2a6e779e]{width:100%;max-height:600px}.image-footer[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.file-list-horizontal[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex;overflow-x:auto;white-space:nowrap;padding:10px 0}.file-card[data-v-2a6e779e]{display:inline-block;width:400px;margin-right:10px}.file-info[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;overflow:hidden}.file-icon[data-v-2a6e779e]{font-size:24px;margin-right:10px}.file-name[data-v-2a6e779e]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:calc(100% - 40px)}.file-footer[data-v-2a6e779e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}
|
|
@ -1 +0,0 @@
|
|||
@font-face{font-family:PingFang;src:url(../../static/fonts/PingFang\ SC.212ada59.ttf);font-weight:400;font-style:normal}body[data-v-d572e954]{font-family:PingFang!important}.infinite-list[data-v-d572e954]{list-style-type:none;height:calc(100vh - 154px);padding:0;margin:0}.desc_container+.desc_container[data-v-d572e954]{margin-top:10px;padding-top:10px}.desc_container .desc_title[data-v-d572e954]{font-size:18px;font-weight:500;color:#333;line-height:25px;margin-bottom:10px}.desc_container .desc_content[data-v-d572e954]{font-size:14px;font-weight:300}.problem .problem_form[data-v-d572e954]{margin-top:10px;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.problem .problem_container[data-v-d572e954],.problem .problem_form[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex}.problem .problem_container .problem_left[data-v-d572e954]{font-family:PingFang,sans-serif;font-weight:300;width:18%;background:#fff;padding:0 20px;border-right:2px solid #46a6ff;height:calc(100vh - 154px)}.problem .problem_container .problem_left .btn[data-v-d572e954]{color:#fff;padding:10px 20px;cursor:pointer;text-align:center;background:#46a6ff;border-radius:10px}.problem .problem_container .problem_left .btn+.btn[data-v-d572e954]{margin-top:10px}.problem .problem_container .problem_right[data-v-d572e954]{width:100%;background:#fff;padding:0 20px}.problem .problem_container .problem_right .problem_right_container+.problem_right_container[data-v-d572e954]{margin-top:20px}.problem .problem_container .problem_right .problem_right_container .title[data-v-d572e954]{font-size:20px;font-weight:600;margin-bottom:10px;color:#46a6ff}.problem .problem_container .problem_right .problem_right_container .title[data-v-d572e954]>:first-child{margin-right:40px}.problem .problem_container .problem_right .problem_right_container .desc[data-v-d572e954]{font-size:14px;color:#666;line-height:24px}.problem .problem_container .problem_right .problem_right_container .desc .copy-button[data-v-d572e954]{margin-left:300px}.image-list-horizontal[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex;overflow-x:auto;white-space:nowrap;padding:10px 0}.image-card[data-v-d572e954]{display:inline-block;width:150px;margin-right:10px}.image-preview[data-v-d572e954]{width:100%;height:100px;-o-object-fit:cover;object-fit:cover}.image-preview-full[data-v-d572e954]{width:100%;max-height:600px}.image-footer[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.file-list-horizontal[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex;overflow-x:auto;white-space:nowrap;padding:10px 0}.file-card[data-v-d572e954]{display:inline-block;width:400px;margin-right:10px}.file-info[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;overflow:hidden}.file-icon[data-v-d572e954]{font-size:24px;margin-right:10px}.file-name[data-v-d572e954]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:calc(100% - 40px)}.file-footer[data-v-d572e954]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}
|
|
@ -0,0 +1 @@
|
|||
.pagination-container[data-v-6af373ef]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-6af373ef]{display:none}[data-v-ea07b72c].el-select{width:100%}.addRoutes[data-v-ea07b72c]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:end}
|
|
@ -1 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-f648eafc]{position:relative;padding-bottom:60px}.el-table[data-v-f648eafc],.filter-container[data-v-f648eafc]{padding-bottom:52px}
|
||||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-79892438]{position:relative;padding-bottom:60px}.el-table[data-v-79892438],.filter-container[data-v-79892438]{padding-bottom:5px}
|
|
@ -1 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-71de5b60]{position:relative;padding-bottom:60px}.el-table[data-v-71de5b60],.filter-container[data-v-71de5b60]{padding-bottom:52px}
|
||||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-4c275e32]{position:relative;padding-bottom:60px}.el-table[data-v-4c275e32],.filter-container[data-v-4c275e32]{padding-bottom:52px}
|
|
@ -0,0 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.disable-layer[data-v-25113710]{width:100%;height:100%;background:#f5f7fa;position:absolute;top:0;left:0;z-index:99;opacity:.5}.scrollable-container[data-v-3b4f3a4e]{height:500px}[data-v-3b4f3a4e].el-scrollbar .el-scrollbar__wrap{overflow-x:hidden}.upload-list .wu-yu[data-v-3b4f3a4e],.upload-list[data-v-3b4f3a4e]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.upload-list .wu-yu[data-v-3b4f3a4e]{margin-bottom:10px;position:relative;width:110px;-ms-flex-line-pack:justify;align-content:space-between}.upload-list .wu-yu+.wu-yu[data-v-3b4f3a4e]{margin-left:5px}.upload-list .wu-yu[data-v-3b4f3a4e] .el-input{width:100px;margin:10px 0 10px 10px}.filter-items[data-v-3b4f3a4e]{position:fixed;left:70%;z-index:66}.img-box[data-v-3b4f3a4e]{position:relative;display:inline-block;width:100px;margin-bottom:10px;margin-left:10px}.img-box+.img-box[data-v-3b4f3a4e]{margin-left:10px}.img-box .desc[data-v-3b4f3a4e]{line-height:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.avatar-uploader[data-v-3b4f3a4e] .el-upload{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-icon-plus[data-v-3b4f3a4e]{display:inline-block;margin-left:10px}.el-icon-folder[data-v-3b4f3a4e]{color:#409eff!important;font-size:100px}.close[data-v-3b4f3a4e]{position:absolute;top:-10px;right:-15px;font-size:18px;color:#409eff}.mistake-content[data-v-3b4f3a4e],.qa-desc[data-v-3b4f3a4e]{display:-webkit-box;display:-ms-flexbox;display:flex}.mistake-left[data-v-3b4f3a4e]{width:90%}.mistake-right[data-v-3b4f3a4e]{padding-left:20px;height:auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-container[data-v-3b4f3a4e]{position:relative;padding-bottom:60px}.el-table[data-v-3b4f3a4e],.filter-container[data-v-3b4f3a4e]{padding-bottom:52px}.mistake-btn[data-v-3b4f3a4e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;margin-top:10px}.search[data-v-3b4f3a4e]{margin-left:10px}.avatar-uploader .el-upload[data-v-3b4f3a4e]{border:1px solid #131313;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-3b4f3a4e]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-3b4f3a4e]{border:1px solid #979797;border-radius:15px;font-size:28px;color:#8c939d;width:100px;height:100px;line-height:100px;text-align:center;position:relative}
|
|
@ -1 +0,0 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.disable-layer[data-v-25113710]{width:100%;height:100%;background:#f5f7fa;position:absolute;top:0;left:0;z-index:99;opacity:.5}.img-box[data-v-6b889b2e]{position:relative;display:inline-block;width:100px;margin-bottom:10px}.img-box+.img-box[data-v-6b889b2e]{margin-left:10px}.img-box .desc[data-v-6b889b2e]{line-height:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.avatar-uploader[data-v-6b889b2e] .el-upload{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-icon-plus[data-v-6b889b2e]{display:inline-block;margin-left:10px}.el-icon-folder[data-v-6b889b2e]{color:#409eff!important;font-size:100px}.close[data-v-6b889b2e]{position:absolute;top:-10px;right:-8px;font-size:18px;color:#409eff}.mistake-content[data-v-6b889b2e],.qa-desc[data-v-6b889b2e]{display:-webkit-box;display:-ms-flexbox;display:flex}.mistake-left[data-v-6b889b2e]{width:90%}.mistake-right[data-v-6b889b2e]{padding-left:20px;height:auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.app-container[data-v-6b889b2e]{position:relative;padding-bottom:60px}.el-table[data-v-6b889b2e],.filter-container[data-v-6b889b2e]{padding-bottom:52px}.mistake-btn[data-v-6b889b2e]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;margin-top:10px}.search[data-v-6b889b2e]{margin-left:10px}.avatar-uploader .el-upload[data-v-6b889b2e]{border:1px solid #131313;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload[data-v-6b889b2e]:hover{border-color:#409eff}.avatar-uploader-icon[data-v-6b889b2e]{border:1px solid #979797;border-radius:15px;font-size:28px;color:#8c939d;width:100px;height:100px;line-height:100px;text-align:center;position:relative}
|
|
@ -0,0 +1 @@
|
|||
.pagination-container[data-v-28fdfbeb]{padding:32px 16px;position:fixed;bottom:0;left:0;width:100%;background:#fff;padding:40px 280px;-webkit-box-shadow:0 -2px 10px rgba(0,0,0,.1);box-shadow:0 -2px 10px rgba(0,0,0,.1);z-index:100}.pagination-container.hidden[data-v-28fdfbeb]{display:none}.app-container[data-v-78a03c33]{position:relative;padding-bottom:60px}.el-table[data-v-78a03c33],.filter-container[data-v-78a03c33]{padding-bottom:52px}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-24cd5960"],{"5c7c":function(t,e,n){"use strict";n.r(e);var i=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"app-container"},[n("el-table",{directives:[{name:"loading",rawName:"v-loading",value:t.listLoading,expression:"listLoading"}],staticStyle:{width:"100%"},attrs:{data:t.list,border:"",fit:"","highlight-current-row":""}},[n("el-table-column",{attrs:{align:"center",label:"ID",width:"60",prop:"id"}}),n("el-table-column",{attrs:{align:"center",label:"姓名",width:"80",prop:"username"}}),n("el-table-column",{attrs:{align:"center",label:"状态",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[0===e.row.isOnline?n("el-tag",{attrs:{type:"border-card"}},[t._v("下线")]):t._e(),1===e.row.isOnline?n("el-tag",{attrs:{type:"success"}},[t._v("在线")]):t._e(),2===e.row.isOnline?n("el-tag",{attrs:{type:"info"}},[t._v("没上线")]):t._e()]}}])}),n("el-table-column",{attrs:{align:"center",label:"是否分单",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("el-switch",{attrs:{"active-value":1,"inactive-value":0},on:{change:function(n){return t.updateStatus(e.row)}},model:{value:e.row.isEndWork,callback:function(n){t.$set(e.row,"isEndWork",n)},expression:"scope.row.isEndWork"}})]}}])}),n("el-table-column",{attrs:{align:"center",label:"在线时长",width:"120"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(Math.floor((e.row.data?e.row.data.onlineTime:e.row.onlineTime)/60)||"--")+" 分钟 ")]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"上线时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.start_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"停止分单时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.end_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"下线时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.last_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"路线"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.last_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])})],1)],1)},a=[],l={name:"GetOnlineList",components:{},data:function(){return{statusArr:{0:"禁用",1:"启用"},list:[],total:0,loading:!1,listLoading:!0,listQuery:{page:1,limit:10,status:null,content:""},dialogCreate:!1,dialogEdit:!1,item:{},anchors:{}}},created:function(){this.listQuery.status=this.$route.query.status||null,this.listQuery.content=this.$route.query.content||null,this.getOnlineList()},methods:{getOnlineList:function(){var t=this;this.listLoading=!0,this.$axios.get("/admin/admin/getOnlineList",{params:this.listQuery}).then((function(e){t.list=e.data,t.listLoading=!1})).catch((function(){t.listLoading=!1}))},updateStatus:function(t){var e=this;this.$axios.post("/admin/admin/editInfo",{id:t.id,order_num:t.order_num,is_order:t.isEndWork}).then((function(){e.getOnlineList()})).catch((function(){}))}}},s=l,r=(n("89a4"),n("2877")),o=Object(r["a"])(s,i,a,!1,null,"45d18cae",null);e["default"]=o.exports},"89a4":function(t,e,n){"use strict";n("d4f7")},d4f7:function(t,e,n){}}]);
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-27f79c9e"],{"5c7c":function(t,e,n){"use strict";n.r(e);var i=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"app-container"},[n("el-table",{directives:[{name:"loading",rawName:"v-loading",value:t.listLoading,expression:"listLoading"}],staticStyle:{width:"100%"},attrs:{data:t.list,border:"",fit:"","highlight-current-row":""}},[n("el-table-column",{attrs:{align:"center",label:"ID",width:"60",prop:"id"}}),n("el-table-column",{attrs:{align:"center",label:"姓名",width:"80",prop:"username"}}),n("el-table-column",{attrs:{align:"center",label:"状态",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[0===e.row.isOnline?n("el-tag",{attrs:{type:"border-card"}},[t._v("下线")]):t._e(),1===e.row.isOnline?n("el-tag",{attrs:{type:"success"}},[t._v("在线")]):t._e(),2===e.row.isOnline?n("el-tag",{attrs:{type:"info"}},[t._v("没上线")]):t._e()]}}])}),n("el-table-column",{attrs:{align:"center",label:"是否分单",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("el-switch",{attrs:{"active-value":1,"inactive-value":0},on:{change:function(n){return t.updateStatus(e.row)}},model:{value:e.row.isEndWork,callback:function(n){t.$set(e.row,"isEndWork",n)},expression:"scope.row.isEndWork"}})]}}])}),n("el-table-column",{attrs:{align:"center",label:"在线时长",width:"120"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(Math.floor((e.row.data?e.row.data.onlineTime:e.row.onlineTime)/60)||"--")+" 分钟 ")]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"上线时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.start_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"停止分单时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.end_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])}),n("el-table-column",{attrs:{width:"138px",align:"center",label:"下线时间"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",[t._v(t._s(t._f("parseTime")(e.row.last_work_time,"{y}-{m}-{d} {h}:{i}")))])]}}])})],1)],1)},a=[],l={name:"GetOnlineList",components:{},data:function(){return{statusArr:{0:"禁用",1:"启用"},list:[],total:0,loading:!1,listLoading:!0,listQuery:{page:1,limit:10,status:null,content:""},dialogCreate:!1,dialogEdit:!1,item:{},anchors:{}}},created:function(){this.listQuery.status=this.$route.query.status||null,this.listQuery.content=this.$route.query.content||null,this.getOnlineList()},methods:{getOnlineList:function(){var t=this;this.listLoading=!0,this.$axios.get("/admin/admin/getOnlineList",{params:this.listQuery}).then((function(e){t.list=e.data,t.listLoading=!1})).catch((function(){t.listLoading=!1}))},updateStatus:function(t){var e=this;this.$axios.post("/admin/admin/editInfo",{id:t.id,order_num:t.order_num,is_order:t.isEndWork}).then((function(){e.getOnlineList()})).catch((function(){}))}}},s=l,o=(n("d8ad"),n("2877")),r=Object(o["a"])(s,i,a,!1,null,"7aa35cbf",null);e["default"]=r.exports},a659:function(t,e,n){},d8ad:function(t,e,n){"use strict";n("a659")}}]);
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0de3a1"],{"856d":function(t,e,l){"use strict";l.r(e);var i=function(){var t=this,e=t.$createElement,l=t._self._c||e;return l("div",{staticClass:"app-container"},[l("div",{staticClass:"filter-container"},[l("el-date-picker",{staticClass:"filter-item",attrs:{type:"datetimerange","default-time":["00:00:00","23:59:59"],"range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期"},model:{value:t.listQuery.times,callback:function(e){t.$set(t.listQuery,"times",e)},expression:"listQuery.times"}}),l("el-select",{staticClass:"filter-item",attrs:{filterable:"",placeholder:"请选择"},model:{value:t.listQuery.os,callback:function(e){t.$set(t.listQuery,"os",e)},expression:"listQuery.os"}},[l("el-option",{key:"",attrs:{label:"请选择",value:""}}),t._l(t.oss,(function(t,e){return l("el-option",{key:e,attrs:{label:t,value:e}})}))],2),l("el-button",{staticClass:"filter-item",attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.getList}},[t._v(" 搜索 ")])],1),l("el-table",{directives:[{name:"loading",rawName:"v-loading",value:t.listLoading,expression:"listLoading"}],staticStyle:{width:"100%"},attrs:{data:t.list,border:"",fit:"","highlight-current-row":""}},[l("el-table-column",{attrs:{align:"center",fixed:"",label:"姓名",width:"120",prop:"admin.name"}}),l("el-table-column",{attrs:{align:"center",label:"订单数",width:"120",prop:"orders"}}),l("el-table-column",{attrs:{align:"center",label:"订单总金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.total_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"核销数",width:"120",prop:"assets"}}),l("el-table-column",{attrs:{align:"center",label:"核销金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.asset_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"未付款订单",width:"120",prop:"nopays"}}),l("el-table-column",{attrs:{align:"center",label:"未付款金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.nopay_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"核销率(按订单)",width:"160"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.write_rate)+"% ")]}}])}),l("el-table-column",{attrs:{align:"center",width:"180",label:"核销率(按销售额)"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.write_rate_price)+"% ")]}}])})],1)],1)},a=[],s=l("5530"),n=(l("a15b"),l("d81d"),l("b64b"),{name:"Datalist",data:function(){return{oss:null,list:[],listLoading:!0,listQuery:{}}},created:function(){this.getList()},methods:{getList:function(t){var e=this;if(1!=t)this.listQuery.excel=0,this.$axios.get("/admin/data/index",{params:this.listQuery}).then((function(t){e.list=t.data,e.oss=t.ext.oss,e.listLoading=!1}));else{if(this.listQuery.excel=1,!this.listQuery.times)return void this.$message({message:"请选择日期",type:"warning"});var l=this.listQuery.times[0]instanceof Date,i=Object(s["a"])(Object(s["a"])({},this.listQuery),{},{times:[l?this.listQuery.times[0].toISOString():"",l?this.listQuery.times[1].toISOString():""]});window.open("/admin/data/index?"+this.objectToQuery(i))}},objectToQuery:function(t){return Object.keys(t).map((function(e){var l=t[e];return void 0==l||null==l?"":encodeURIComponent(e)+"="+encodeURIComponent(l)})).join("&")}}}),r=n,o=l("2877"),c=Object(o["a"])(r,i,a,!1,null,null,null);e["default"]=c.exports}}]);
|
|
@ -0,0 +1 @@
|
|||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0de3a1"],{"856d":function(t,e,l){"use strict";l.r(e);var i=function(){var t=this,e=t.$createElement,l=t._self._c||e;return l("div",{staticClass:"app-container"},[l("div",{staticClass:"filter-container"},[l("el-date-picker",{staticClass:"filter-item",attrs:{type:"datetimerange","default-time":["00:00:00","23:59:59"],"range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期"},model:{value:t.listQuery.times,callback:function(e){t.$set(t.listQuery,"times",e)},expression:"listQuery.times"}}),l("el-select",{staticClass:"filter-item",attrs:{filterable:"",placeholder:"请选择"},model:{value:t.listQuery.os,callback:function(e){t.$set(t.listQuery,"os",e)},expression:"listQuery.os"}},[l("el-option",{key:"",attrs:{label:"请选择",value:""}}),t._l(t.oss,(function(t,e){return l("el-option",{key:e,attrs:{label:t,value:e}})}))],2),l("el-button",{staticClass:"filter-item",attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.getList}},[t._v(" 搜索 ")]),l("el-button",{staticClass:"filter-item",attrs:{type:"primary",icon:"el-icon-search"},on:{click:function(e){return t.getList(1)}}},[t._v(" 导出 ")])],1),l("el-table",{directives:[{name:"loading",rawName:"v-loading",value:t.listLoading,expression:"listLoading"}],staticStyle:{width:"100%"},attrs:{data:t.list,border:"",fit:"","highlight-current-row":""}},[l("el-table-column",{attrs:{align:"center",fixed:"",label:"姓名",width:"120",prop:"admin.name"}}),l("el-table-column",{attrs:{align:"center",label:"订单数",width:"120",prop:"orders"}}),l("el-table-column",{attrs:{align:"center",label:"订单总金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.total_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"核销数",width:"120",prop:"assets"}}),l("el-table-column",{attrs:{align:"center",label:"核销金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.asset_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"未付款订单",width:"120",prop:"nopays"}}),l("el-table-column",{attrs:{align:"center",label:"未付款金额"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.nopay_price/100)+" ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"核销率(按订单)",width:"160"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.write_rate)+"% ")]}}])}),l("el-table-column",{attrs:{align:"center",width:"180",label:"核销率(按销售额)"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.write_rate_price)+"% ")]}}])}),l("el-table-column",{attrs:{align:"center",label:"当月核销率(按订单)",width:"160"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.month_write_rate)+"% ")]}}])}),l("el-table-column",{attrs:{align:"center",width:"180",label:"当月核销率(按销售额)"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v(" "+t._s(e.row.month_write_rate_price)+"% ")]}}])})],1)],1)},a=[],n=l("5530"),s=(l("a15b"),l("d81d"),l("b64b"),{name:"Datalist",data:function(){return{oss:null,list:[],listLoading:!0,listQuery:{}}},created:function(){this.getList()},methods:{getList:function(t){var e=this;if(1!=t)this.listQuery.excel=0,this.$axios.get("/admin/data/index",{params:this.listQuery}).then((function(t){e.list=t.data,e.oss=t.ext.oss,e.listLoading=!1}));else{if(this.listQuery.excel=1,!this.listQuery.times)return void this.$message({message:"请选择日期",type:"warning"});var l=this.listQuery.times[0]instanceof Date,i=Object(n["a"])(Object(n["a"])({},this.listQuery),{},{times:[l?this.listQuery.times[0].toISOString():"",l?this.listQuery.times[1].toISOString():""]});window.open("/admin/data/index?"+this.objectToQuery(i))}},objectToQuery:function(t){return Object.keys(t).map((function(e){var l=t[e];return void 0==l||null==l?"":encodeURIComponent(e)+"="+encodeURIComponent(l)})).join("&")}}}),r=s,o=l("2877"),c=Object(o["a"])(r,i,a,!1,null,null,null);e["default"]=c.exports}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1,28 @@
|
|||
{"status":200,"message":"\u6210\u529f","data":{"sellerOrderResultDOS":[],"showVerify":false,"page":{"currentPage":2,"pageSize":10,"totalCount":0,"noMore":false},"canVerify":false,"canBatchDelivery":false,"canAsyncExportOrder":true},"success":true,"traceId":"EL2AgICAsoKsChjdAyDS_sLB8TEowpfGgQ8="}
|
||||
{"status":200,"message":"\u6210\u529f","data":{"sellerOrderResultDOS":[],"showVerify":false,"page":{"currentPage":2,"pageSize":10,"totalCount":0,"noMore":false},"canVerify":false,"canBatchDelivery":false,"canAsyncExportOrder":true},"success":true,"traceId":"EL2AgICAsoKsChjdAyDS_sLB8TEowpfGgQ8="}
|
||||
|
||||
ALTER TABLE `travel`.`orders`
|
||||
MODIFY COLUMN `appointment_status` tinyint NOT NULL DEFAULT 0 COMMENT '是否已预约(0-未预约,1-已预约未处理,2-已预约已处理)' AFTER `next_remind_time`;
|
||||
|
||||
ALTER TABLE `admins`
|
||||
ADD COLUMN `type` tinyint NOT NULL DEFAULT 0 COMMENT '类型(0-管理员,1-客服,2-主播,3-中控)' AFTER `route_type`;
|
||||
|
||||
ALTER TABLE `orders`
|
||||
ADD COLUMN `live_room_works` int NOT NULL DEFAULT 0 COMMENT '排班表id' AFTER `appointment_status`;
|
||||
|
||||
|
||||
|
||||
2024/10/13
|
||||
ALTER TABLE `orders`
|
||||
ADD COLUMN `is_refunded` tinyint NOT NULL DEFAULT 0 COMMENT '是否已退款(0-否,1-是)' AFTER `update_time`;
|
||||
|
||||
update
|
||||
`orders`
|
||||
set is_refunded = 1
|
||||
WHERE
|
||||
`os` IN ( '1', '7' ) and order_status = 5;
|
||||
|
||||
update
|
||||
`orders`
|
||||
set is_refunded = 1
|
||||
WHERE
|
||||
(`os` IN ( '3', '5' ) and order_status = 4)
|
|
@ -526,3 +526,35 @@ function input(string $param = null, $default = null)
|
|||
{
|
||||
return is_null($param) ? request()->all() : request()->input($param, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一周的日期
|
||||
* @return array
|
||||
*/
|
||||
function get_week_days() {
|
||||
// 获取当前日期
|
||||
$today = new DateTime();
|
||||
|
||||
// 获取当前周的周一
|
||||
$monday = clone $today;
|
||||
$monday->modify('monday this week');
|
||||
|
||||
// 获取当前周的周日
|
||||
$sunday = clone $today;
|
||||
$sunday->modify('sunday this week');
|
||||
|
||||
// 初始化日期数组
|
||||
$dates = [];
|
||||
$dayNmae = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
|
||||
// 从周一到周日循环
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
$date = clone $monday;
|
||||
$date->modify("+$i days");
|
||||
$dates[] = [
|
||||
'date_name' => $dayNmae[$i],
|
||||
'date' => $date->format('Y-m-d')
|
||||
];
|
||||
}
|
||||
|
||||
return $dates;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue