新增排队叫号功能
This commit is contained in:
15849
dist-electron/main.js
15849
dist-electron/main.js
File diff suppressed because one or more lines are too long
@@ -24,6 +24,7 @@
|
|||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"reconnecting-websocket": "^4.4.0",
|
"reconnecting-websocket": "^4.4.0",
|
||||||
"serialport": "^12.0.0",
|
"serialport": "^12.0.0",
|
||||||
|
"speak-tts": "^2.0.8",
|
||||||
"swiper": "^11.1.1",
|
"swiper": "^11.1.1",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"vue": "^3.3.8",
|
"vue": "^3.3.8",
|
||||||
|
|||||||
134
src/api/queue.js
Normal file
134
src/api/queue.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* 排队叫号
|
||||||
|
*/
|
||||||
|
import request from "@/utils/request.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录获取
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callRecord(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "/callTable/callRecord",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 桌型列表
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callTable(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "/callTable",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加桌型
|
||||||
|
* @param {*} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function addCallTable(data) {
|
||||||
|
return request({
|
||||||
|
method: data.id ? "put" : "post",
|
||||||
|
url: "/callTable",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除桌型
|
||||||
|
* @param {*} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function delCallTable(data) {
|
||||||
|
return request({
|
||||||
|
method: "delete",
|
||||||
|
url: "/callTable",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置信息 获取
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callTableConfig(params) {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: "/callTable/config",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置信息 修改
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callTableConfigPut(data) {
|
||||||
|
return request({
|
||||||
|
method: "put",
|
||||||
|
url: "/callTable/config",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取号 排队列表获取
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callTableQueue(params) {
|
||||||
|
return request({
|
||||||
|
method: "GET",
|
||||||
|
url: "/callTable/queue",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取号 手动取号
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function takeNumber(data) {
|
||||||
|
return request({
|
||||||
|
method: "post",
|
||||||
|
url: "/callTable/takeNumber",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取号 修改叫号状态
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function updateState(data) {
|
||||||
|
return request({
|
||||||
|
method: "put",
|
||||||
|
url: "/callTable/updateState",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知叫号
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function callTableCall(data) {
|
||||||
|
return request({
|
||||||
|
method: "post",
|
||||||
|
url: "/callTable/call",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -87,6 +87,11 @@ const menus = ref([
|
|||||||
path: '/member',
|
path: '/member',
|
||||||
icon: 'User'
|
icon: 'User'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '排队',
|
||||||
|
path: '/queue',
|
||||||
|
icon: 'Timer'
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// label: '交班',
|
// label: '交班',
|
||||||
// path: '/work',
|
// path: '/work',
|
||||||
@@ -233,7 +238,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.more {
|
&.more {
|
||||||
margin-top: 120px;
|
margin-top: 90px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|||||||
114
src/components/uploadImg.vue
Normal file
114
src/components/uploadImg.vue
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<el-upload ref="uploadRef" v-model:file-list="fileList" :action="uploadUrl" :headers="headers" :list-type="listType"
|
||||||
|
:multiple="multiple" :limit="limit" :on-exceed="handleExceed" :on-change="handleChange"
|
||||||
|
:on-progress="handleProgress" :on-success="handleSuccess" :on-error="handleError" :before-upload="beforeUpload"
|
||||||
|
:accept="accept" :disabled="disabled">
|
||||||
|
<el-icon>
|
||||||
|
<Plus />
|
||||||
|
</el-icon>
|
||||||
|
<template v-slot:tip>
|
||||||
|
<div v-if="tip">{{ tip }}</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import useStorage from '@/utils/useStorage'
|
||||||
|
import { ElUpload, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const fileList = ref([])
|
||||||
|
|
||||||
|
// 定义接收的外部属性
|
||||||
|
const props = defineProps({
|
||||||
|
uploadUrl: {
|
||||||
|
type: String,
|
||||||
|
default: import.meta.env.MODE == 'development' ? '/api/shopInfo/upload' : import.meta.env.VITE_API_URL + '/shopInfo/upload',
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
token: useStorage.get("token"),
|
||||||
|
loginName: useStorage.get("userInfo").loginName,
|
||||||
|
clientType: 'pc'
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
listType: {
|
||||||
|
type: String,
|
||||||
|
default: 'picture-card',
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
tip: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
accept: {
|
||||||
|
type: String,
|
||||||
|
default: 'image/jpeg,image/png,image/gif',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
// 内部引用上传组件实例
|
||||||
|
const uploadRef = ref(null);
|
||||||
|
|
||||||
|
// 处理文件超出数量限制的情况
|
||||||
|
const handleExceed = (files, fileList) => {
|
||||||
|
ElMessage.warning(`超出最大允许上传图片数量:${props.limit}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理文件状态改变
|
||||||
|
const handleChange = (file, fileList) => {
|
||||||
|
console.log('图片文件状态改变', file, fileList);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理上传进度
|
||||||
|
const handleProgress = (event, file, fileList) => {
|
||||||
|
console.log('图片上传进度', event.percent);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理上传成功
|
||||||
|
const handleSuccess = (response, file, fileList) => {
|
||||||
|
ElMessage.success('图片上传成功');
|
||||||
|
console.log('图片上传成功响应', response);
|
||||||
|
emits('success', response.data)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理上传失败
|
||||||
|
const handleError = (error, file, fileList) => {
|
||||||
|
ElMessage.error('图片上传失败');
|
||||||
|
console.error('图片上传失败原因', error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传前校验,这里主要校验图片格式
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
const isImage = props.accept.split(',').some(format => file.type === format.trim());
|
||||||
|
if (!isImage) {
|
||||||
|
ElMessage.error('请选择正确格式的图片文件');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(arr) {
|
||||||
|
fileList.value = arr
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
init
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -57,6 +57,14 @@ const routes = [
|
|||||||
},
|
},
|
||||||
component: () => import("@/views/member/index.vue"),
|
component: () => import("@/views/member/index.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/queue",
|
||||||
|
name: "queue",
|
||||||
|
meta: {
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
component: () => import("@/views/queue/index.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/work",
|
path: "/work",
|
||||||
name: "work",
|
name: "work",
|
||||||
|
|||||||
139
src/views/queue/components/addTab.vue
Normal file
139
src/views/queue/components/addTab.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="showAddTable" :title="addTabForm.id ? '编辑桌型' : '新增桌型'" top="10vh" @closed="addTabFormReset">
|
||||||
|
<el-form ref="AddTabFormRef" :model="addTabForm" :rules="addTabFormRules" label-position="left"
|
||||||
|
label-width="100">
|
||||||
|
<el-form-item label="名称" prop="name">
|
||||||
|
<el-input v-model="addTabForm.name" placeholder="请输入名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="描述" prop="note">
|
||||||
|
<el-input v-model="addTabForm.note" placeholder="请输入描述,例如1-2人" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="等待时间" prop="waitTime">
|
||||||
|
<el-input v-model="addTabForm.waitTime" placeholder="0">
|
||||||
|
<template #append>分钟/1桌</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="号码前缀" prop="prefix">
|
||||||
|
<el-input v-model="addTabForm.prefix" placeholder="请输入英文字母,不支持中文" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开始号码" prop="start">
|
||||||
|
<el-input v-model="addTabForm.start" placeholder="请输入开始号码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="过号保留">
|
||||||
|
<el-input v-model="addTabForm.nearNum" :disabled="!addTabForm.isPostpone" placeholder="临近几桌提醒">
|
||||||
|
<template #prepend>
|
||||||
|
<el-checkbox v-model="addTabForm.isPostpone" :true-value="1" :false-value="0" label="开启顺延" />
|
||||||
|
</template>
|
||||||
|
<template #append>桌</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div class="footer" style="display: flex;">
|
||||||
|
<el-button style="width: 100%" @click="showAddTable = false">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" style="width: 100%" :loading="addTabFormLoading" @click="addTabConfirmHandle">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { addCallTable } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
const showAddTable = ref(false)
|
||||||
|
const addTabFormLoading = ref(false)
|
||||||
|
const AddTabFormRef = ref(null)
|
||||||
|
const resetAddTabForm = ref({})
|
||||||
|
const addTabForm = ref({
|
||||||
|
name: '',
|
||||||
|
note: '',
|
||||||
|
waitTime: '',
|
||||||
|
prefix: '',
|
||||||
|
start: '',
|
||||||
|
isPostpone: 0,
|
||||||
|
nearNum: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const addTabFormRules = ref({
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: ' ',
|
||||||
|
trigger: 'blur',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
waitTime: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: ' ',
|
||||||
|
trigger: 'blur',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
prefix: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: ' ',
|
||||||
|
trigger: 'blur',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
start: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: ' ',
|
||||||
|
trigger: 'blur',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
function addTabFormReset() {
|
||||||
|
addTabForm.value = { ...resetAddTabForm.value }
|
||||||
|
AddTabFormRef.value.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
function addTabConfirmHandle() {
|
||||||
|
AddTabFormRef.value.validate(async valid => {
|
||||||
|
try {
|
||||||
|
if (valid) {
|
||||||
|
addTabFormLoading.value = true
|
||||||
|
addTabForm.value.shopId = store.userInfo.shopId
|
||||||
|
if (addTabForm.value.id) {
|
||||||
|
addTabForm.value.callTableId = addTabForm.value.id
|
||||||
|
}
|
||||||
|
const res = await addCallTable(addTabForm.value)
|
||||||
|
addTabFormLoading.value = false
|
||||||
|
showAddTable.value = false
|
||||||
|
ElMessage.success(addTabForm.value.id ? '编辑成功' : '添加成功')
|
||||||
|
emits('success')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
addTabFormLoading.value = false
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(obj) {
|
||||||
|
if (obj && obj.id) {
|
||||||
|
addTabForm.value = { ...obj }
|
||||||
|
}
|
||||||
|
showAddTable.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
resetAddTabForm.value = { ...addTabForm.value }
|
||||||
|
})
|
||||||
|
</script>
|
||||||
108
src/views/queue/components/getNumber.vue
Normal file
108
src/views/queue/components/getNumber.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<!-- 取号 -->
|
||||||
|
<template>
|
||||||
|
<el-dialog title="取号" v-model="visible" @closed="onClose">
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
|
||||||
|
<el-form-item label="选择桌型">
|
||||||
|
<el-radio-group v-model="form.callTableId">
|
||||||
|
<el-radio :value="item.id" border v-for="item in list" :key="item.id">{{ item.name
|
||||||
|
}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号码" prop="phone">
|
||||||
|
<el-input v-model="form.phone" placeholder="请填写手机号" style="width: 60%;" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div class="footer" style="display: flex;padding-top: 30px;">
|
||||||
|
<el-button style="width: 100%" @click="visible = false">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { takeNumber } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
|
||||||
|
const list = ref([])
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const formRef = ref(null)
|
||||||
|
const resetForm = ref({})
|
||||||
|
const form = ref({
|
||||||
|
callTableId: '',
|
||||||
|
shopId: '',
|
||||||
|
phone: '',
|
||||||
|
note: '',
|
||||||
|
name: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = ref({
|
||||||
|
phone: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
let reg = /^(?:(?:\+|00)86)?1\d{10}$/
|
||||||
|
if (!reg.test(form.value.phone)) {
|
||||||
|
callback(new Error('手机号码不正确'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
function confirmHandle() {
|
||||||
|
formRef.value.validate(async vaild => {
|
||||||
|
try {
|
||||||
|
if (vaild) {
|
||||||
|
loading.value = true
|
||||||
|
form.value.shopId = store.userInfo.shopId
|
||||||
|
form.value.note = list.value.find(item => item.id == form.value.callTableId).note
|
||||||
|
form.value.name = list.value.find(item => item.id == form.value.callTableId).name
|
||||||
|
await takeNumber(form.value)
|
||||||
|
loading.value = false
|
||||||
|
ElMessage.success('取号成功')
|
||||||
|
emits('success')
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
function onClose() {
|
||||||
|
form.value = { ...resetForm.value }
|
||||||
|
formRef.value.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(arr) {
|
||||||
|
visible.value = true
|
||||||
|
list.value = [...arr]
|
||||||
|
form.value.callTableId = list.value[0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
resetForm.value = { ...form }
|
||||||
|
})
|
||||||
|
</script>
|
||||||
99
src/views/queue/components/record.vue
Normal file
99
src/views/queue/components/record.vue
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<!-- 叫号记录 -->
|
||||||
|
<template>
|
||||||
|
<el-dialog v-model="dialogVisible" title="叫号记录" @closed="reset" width="80vw">
|
||||||
|
<el-table :data="tableData.list" border style="height: 84%;" height="50vh">
|
||||||
|
<el-table-column label="桌号" prop="name"></el-table-column>
|
||||||
|
<el-table-column label="桌型" prop="note"></el-table-column>
|
||||||
|
<el-table-column label="手机号" prop="phone"></el-table-column>
|
||||||
|
<el-table-column label="状态" prop="state">
|
||||||
|
<template v-slot="scope">
|
||||||
|
{{ statusList[scope.row.state].text }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="时间" prop="callTime" width="200">
|
||||||
|
<template v-slot="scope">{{ dayjs(scope.row.callTime).format('YYYY-MM-DD HH:mm:ss') }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="pagination" style="padding-top:15px;display: flex;justify-content: flex-end;">
|
||||||
|
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.size"
|
||||||
|
layout="total, prev, pager, next" :total="tableData.total" background @current-change="paginationChange"
|
||||||
|
@size-change="paginationChange">
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { callRecord } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const tableData = reactive({
|
||||||
|
loading: false,
|
||||||
|
list: [],
|
||||||
|
page: 1,
|
||||||
|
size: 20,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
const statusList = {
|
||||||
|
'-1': {
|
||||||
|
type: 'warning',
|
||||||
|
text: '已取消'
|
||||||
|
},
|
||||||
|
0: {
|
||||||
|
type: 'danger',
|
||||||
|
text: '排队中'
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
type: 'success',
|
||||||
|
text: '叫号中'
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
type: 'success',
|
||||||
|
text: '已入座'
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
type: 'success',
|
||||||
|
text: '已过号'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页变化
|
||||||
|
function paginationChange(e) {
|
||||||
|
callRecordAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录数据
|
||||||
|
async function callRecordAjax() {
|
||||||
|
try {
|
||||||
|
tableData.loading = true
|
||||||
|
const res = await callRecord({
|
||||||
|
callTableId: '',
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
page: tableData.page,
|
||||||
|
size: tableData.size
|
||||||
|
})
|
||||||
|
tableData.loading = false
|
||||||
|
tableData.list = res.records
|
||||||
|
tableData.total = res.total
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
tableData.page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true
|
||||||
|
callRecordAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
75
src/views/queue/components/resultModal.vue
Normal file
75
src/views/queue/components/resultModal.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<!-- 播报结果 -->
|
||||||
|
<template>
|
||||||
|
<el-dialog title="提示" v-model="visible">
|
||||||
|
<div class="content">
|
||||||
|
<div style="font-size: 18px;">正在叫号,请稍等</div>
|
||||||
|
<el-alert :title="statusList[item.status].text" :type="statusList[item.status].type" :closable="false" />
|
||||||
|
</div>
|
||||||
|
<div class="footer" style="display: flex;">
|
||||||
|
<el-button style="width: 100%" @click="confirmHandle(2)">完成</el-button>
|
||||||
|
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle(3)">过号</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { updateState } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const item = ref({})
|
||||||
|
const loading = ref(false)
|
||||||
|
const statusList = {
|
||||||
|
'-1': {
|
||||||
|
type: 'warning',
|
||||||
|
text: '用户未订阅'
|
||||||
|
},
|
||||||
|
0: {
|
||||||
|
type: 'danger',
|
||||||
|
text: '失败'
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
type: 'success',
|
||||||
|
text: '成功'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过号修改状态
|
||||||
|
async function confirmHandle(state) {
|
||||||
|
try {
|
||||||
|
await updateState({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callQueueId: item.value.id,
|
||||||
|
state: state
|
||||||
|
})
|
||||||
|
visible.value = false
|
||||||
|
emits('success')
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(obj) {
|
||||||
|
visible.value = true
|
||||||
|
item.value = { ...obj }
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
233
src/views/queue/components/setting.vue
Normal file
233
src/views/queue/components/setting.vue
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="dialogVisible" title="基本设置" width="90vw" top="5vh" @closed="emits('success')">
|
||||||
|
<div class="scroll_y">
|
||||||
|
<el-form ref="formRef" :model="form" label-position="left" label-width="140">
|
||||||
|
<el-form-item label="排队页面地址">{{ config.pageAddress }}</el-form-item>
|
||||||
|
<el-form-item label="线上取号">
|
||||||
|
<el-switch v-model="form.isOnline" :active-value="1" :inactive-value="0"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="背景图片">
|
||||||
|
<UploadImg ref="UploadImgRef" @success="e => form.bgCover = e" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="桌型">
|
||||||
|
<el-table :data="tableData.list" border v-loading="tableData.loading">
|
||||||
|
<el-table-column label="名称" prop="name"></el-table-column>
|
||||||
|
<el-table-column label="描述" prop="note"></el-table-column>
|
||||||
|
<el-table-column label="等待时间[桌]" prop="waitTime"></el-table-column>
|
||||||
|
<el-table-column label="号码前缀" prop="prefix"></el-table-column>
|
||||||
|
<el-table-column label="开始号码" prop="start"></el-table-column>
|
||||||
|
<el-table-column label="操作">
|
||||||
|
<template #header>
|
||||||
|
<el-button type="primary" @click="AddTabRef.show()">添加</el-button>
|
||||||
|
</template>
|
||||||
|
<template v-slot="scope">
|
||||||
|
<div style="display: flex;gap: 10px;">
|
||||||
|
<el-text type="primary" @click="AddTabRef.show(scope.row)">编辑</el-text>
|
||||||
|
<el-text type="danger" @click="delCallTableHandle(scope.row)">删除</el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="title" style="padding-bottom: 20px;">通知模板</div>
|
||||||
|
<el-form-item label="排队成功提醒">
|
||||||
|
<el-input disabled style="width: 50%;" v-model="config.successMsg"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排队即将排到通知">
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
<el-input disabled style="width: 50%;" v-model="config.nearMsg"></el-input>
|
||||||
|
<el-input v-model="config.nearNum" disabled style="margin-top: 10px;">
|
||||||
|
<template #prepend>前面等待</template>
|
||||||
|
<template #append>桌时提醒</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排队到号提醒">
|
||||||
|
<el-input disabled style="width: 50%;" v-model="config.callingMsg"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<el-button style="width: 100%" @click="dialogVisible = false">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" style="width: 100%" :loading="loading" @click="confirmHandle">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<AddTab ref="AddTabRef" @success="getTableAjax" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import UploadImg from '@/components/uploadImg.vue'
|
||||||
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
|
import AddTab from './addTab.vue'
|
||||||
|
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { callTable, delCallTable, callTableConfig, callTableConfigPut } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
|
||||||
|
const AddTabRef = ref(null)
|
||||||
|
const formRef = ref(null)
|
||||||
|
const loading = ref(false)
|
||||||
|
const form = ref({
|
||||||
|
isOnline: 1,
|
||||||
|
bgCover: '',
|
||||||
|
nearNum: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function beforeAvatarUpload(file) {
|
||||||
|
console.log(2, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 桌型
|
||||||
|
const tableData = reactive({
|
||||||
|
loading: false,
|
||||||
|
list: []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 显示基本配置
|
||||||
|
function show() {
|
||||||
|
dialogVisible.value = true
|
||||||
|
|
||||||
|
getTableAjax()
|
||||||
|
callTableConfigAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除桌型
|
||||||
|
function delCallTableHandle(row) {
|
||||||
|
ElMessageBox.confirm('确认要删除吗?', '注意').then(async () => {
|
||||||
|
try {
|
||||||
|
tableData.loading = true
|
||||||
|
const res = await delCallTable({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callTableId: row.id
|
||||||
|
})
|
||||||
|
getTableAjax()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取桌型列表
|
||||||
|
async function getTableAjax() {
|
||||||
|
try {
|
||||||
|
tableData.loading = true
|
||||||
|
const res = await callTable({
|
||||||
|
page: 1,
|
||||||
|
size: 100,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callTableId: '',
|
||||||
|
state: ''
|
||||||
|
})
|
||||||
|
tableData.loading = false
|
||||||
|
tableData.list = res.records
|
||||||
|
} catch (error) {
|
||||||
|
tableData.loading = false
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取配置信息
|
||||||
|
const config = ref({})
|
||||||
|
const UploadImgRef = ref(null)
|
||||||
|
async function callTableConfigAjax() {
|
||||||
|
try {
|
||||||
|
const res = await callTableConfig({ shopId: store.userInfo.shopId })
|
||||||
|
config.value = res
|
||||||
|
form.value.nearNum = res.nearNum
|
||||||
|
if (res.bgCover) {
|
||||||
|
UploadImgRef.value.init([{ url: res.bgCover }])
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
const emits = defineEmits(['success'])
|
||||||
|
async function confirmHandle() {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
form.value.shopId = store.userInfo.shopId
|
||||||
|
const res = await callTableConfigPut(form.value)
|
||||||
|
loading.value = false
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
dialogVisible.value = false
|
||||||
|
emits('success')
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.avatar-uploader .el-upload {
|
||||||
|
border: 1px dashed var(--el-border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: var(--el-transition-duration-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader .el-upload:hover {
|
||||||
|
border-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon.avatar-uploader-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #8c939d;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader .avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
$btmH: 50px;
|
||||||
|
|
||||||
|
.scroll_y {
|
||||||
|
height: 65vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: $btmH;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 100px 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
height: $btmH;
|
||||||
|
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: $btmH*-1;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
282
src/views/queue/index.vue
Normal file
282
src/views/queue/index.vue
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
<template>
|
||||||
|
<div class="content">
|
||||||
|
<div class="card" style="flex: 1;">
|
||||||
|
<div class="tab_head">
|
||||||
|
<el-radio-group v-model="tabActive" @change="callTableQueueAjax">
|
||||||
|
<el-radio-button label="全部" value=""></el-radio-button>
|
||||||
|
<el-radio-button :label="item.name" :value="item.id" v-for="item in tabHeader"
|
||||||
|
:key="item.id"></el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<div class="btns">
|
||||||
|
<el-button type="danger" @click="GetNumberRef.show(tabHeader)">取号</el-button>
|
||||||
|
<el-button type="warning" @click="RecordRef.show()">叫号记录</el-button>
|
||||||
|
<el-button type="primary" @click="SettingRef.show()">基本设置</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="queue_list" v-loading="queueList.loading">
|
||||||
|
<div class="item" v-for="item in queueList.list" :key="item.id">
|
||||||
|
<div class="head">
|
||||||
|
<div class="row">
|
||||||
|
<div class="row_item">用户</div>
|
||||||
|
<div class="row_item">号码</div>
|
||||||
|
<div class="row_item">桌型</div>
|
||||||
|
<div class="row_item">等待</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="row_item">{{ item.phone }}</div>
|
||||||
|
<div class="row_item">{{ item.callNum }}</div>
|
||||||
|
<div class="row_item">{{ item.name }}</div>
|
||||||
|
<div class="row_item">{{ item.waitingCount }}分钟</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btm">
|
||||||
|
<el-button @click="cancaleHandle(item)">取消</el-button>
|
||||||
|
<el-button type="primary" @click="callHandle(item)">播报</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="empty">
|
||||||
|
<el-empty description="暂无数据~" v-if="!queueList.list.length" style="width: 100%;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pagination">
|
||||||
|
<el-pagination v-model:current-page="queueList.page" v-model:page-size="queueList.size"
|
||||||
|
layout="total, prev, pager, next" :total="queueList.total" background
|
||||||
|
@current-change="queueListChange" @size-change="queueListChange">
|
||||||
|
</el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 基本设置 -->
|
||||||
|
<Setting ref="SettingRef" @success="callTableAjax" />
|
||||||
|
<!-- 叫号记录 -->
|
||||||
|
<Record ref="RecordRef" />
|
||||||
|
<!-- 取号 -->
|
||||||
|
<GetNumber ref="GetNumberRef" @success="callTableQueueAjax" />
|
||||||
|
<!-- 播报状态 -->
|
||||||
|
<ResultModal ref="ResultModalRef" @success="callTableQueueAjax" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Speech from 'speak-tts'
|
||||||
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
|
import Setting from './components/setting.vue'
|
||||||
|
import Record from './components/record.vue'
|
||||||
|
import GetNumber from './components/getNumber.vue'
|
||||||
|
import ResultModal from './components/resultModal.vue'
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { callRecord, callTable, callTableQueue, updateState, callTableCall } from '@/api/queue.js'
|
||||||
|
import { useUser } from "@/store/user.js"
|
||||||
|
const store = useUser()
|
||||||
|
|
||||||
|
const SettingRef = ref(null)
|
||||||
|
const RecordRef = ref(null)
|
||||||
|
const GetNumberRef = ref(null)
|
||||||
|
const ResultModalRef = ref(null)
|
||||||
|
|
||||||
|
// 获取桌型列表
|
||||||
|
const tabHeader = ref([])
|
||||||
|
const tabActive = ref('')
|
||||||
|
async function callTableAjax() {
|
||||||
|
try {
|
||||||
|
const res = await callTable({
|
||||||
|
page: 1,
|
||||||
|
size: 100,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callTableId: '',
|
||||||
|
state: ''
|
||||||
|
})
|
||||||
|
tabHeader.value = res.records
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取号 排队列表获取 start
|
||||||
|
const queueList = reactive({
|
||||||
|
loading: false,
|
||||||
|
list: [],
|
||||||
|
page: 1,
|
||||||
|
size: 8,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
function queueListChange() {
|
||||||
|
callTableQueueAjax()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
async function callTableQueueAjax() {
|
||||||
|
try {
|
||||||
|
queueList.loading = true
|
||||||
|
const res = await callTableQueue({
|
||||||
|
page: queueList.page,
|
||||||
|
size: queueList.size,
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callTableId: tabActive.value,
|
||||||
|
state: ''
|
||||||
|
})
|
||||||
|
queueList.loading = false
|
||||||
|
queueList.list = res.records
|
||||||
|
queueList.total = res.total
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
queueList.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 取号 排队列表获取 end
|
||||||
|
|
||||||
|
// 取消排队
|
||||||
|
function cancaleHandle(item) {
|
||||||
|
ElMessageBox.confirm('确定要取消排队吗?', '注意').then(async () => {
|
||||||
|
try {
|
||||||
|
await updateState({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callQueueId: item.id,
|
||||||
|
state: '-1'
|
||||||
|
})
|
||||||
|
ElMessage.success('已取消')
|
||||||
|
callTableQueueAjax()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播报
|
||||||
|
async function callHandle(item) {
|
||||||
|
try {
|
||||||
|
startSpeech(`请${item.callNum}用餐`)
|
||||||
|
const res = await callTableCall({
|
||||||
|
shopId: store.userInfo.shopId,
|
||||||
|
callQueueId: item.id,
|
||||||
|
})
|
||||||
|
ResultModalRef.value.show({
|
||||||
|
...item,
|
||||||
|
status: res.state
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放声音
|
||||||
|
const speech = new Speech()
|
||||||
|
function speechInit(params) {
|
||||||
|
speech.init({
|
||||||
|
volume: 1, // 音量
|
||||||
|
lang: 'zh-CN', // 语言
|
||||||
|
rate: 1, // 语速1正常语速,2倍语速就写2
|
||||||
|
pitch: 1, // 音调
|
||||||
|
splitSentences: true, // 在句子结束时暂停
|
||||||
|
listeners: {
|
||||||
|
// 事件
|
||||||
|
onvoiceschanged: voices => {
|
||||||
|
// console.log('事件声音已更改', voices);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).then(data => {
|
||||||
|
console.log('语音已准备好,声音可用', data);
|
||||||
|
}).catch(err => {
|
||||||
|
console.log('初始化发生错误', err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始播报
|
||||||
|
function startSpeech(text) {
|
||||||
|
speech.speak({
|
||||||
|
text: text, //这里使用文字或者i18n 都可以 看自己需求
|
||||||
|
queue: true,
|
||||||
|
listeners: {
|
||||||
|
// 开始播放
|
||||||
|
onstart: () => {
|
||||||
|
console.log('Start utterance')
|
||||||
|
},
|
||||||
|
// 判断播放是否完毕
|
||||||
|
onend: () => {
|
||||||
|
console.log('End utterance')
|
||||||
|
},
|
||||||
|
// 恢复播放
|
||||||
|
onresume: () => {
|
||||||
|
console.log('Resume utterance')
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
console.log('成功!');
|
||||||
|
}).catch(e => {
|
||||||
|
console.error('发生错误:', e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
callTableAjax()
|
||||||
|
callTableQueueAjax()
|
||||||
|
|
||||||
|
if (speech.hasBrowserSupport()) {
|
||||||
|
console.log('语音播报加载成功,支持播报');
|
||||||
|
speechInit()
|
||||||
|
} else {
|
||||||
|
console.log('当前浏览器不支持语音播报');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card {
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab_head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue_list {
|
||||||
|
height: 80vh;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
grid-template-rows: repeat(4, 1fr);
|
||||||
|
grid-column-gap: 15px;
|
||||||
|
grid-row-gap: 15px;
|
||||||
|
padding: 15px 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.head {
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.row_item {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
flex: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btm {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user