123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- <script setup lang="ts">
- import AgoraRTC from "agora-rtc-sdk-ng"
- import type { IAgoraRTCClient, IMicrophoneAudioTrack, ICameraVideoTrack } from "agora-rtc-sdk-ng"
- import type { type_dyaw_xlfw_zxhd, type_dyaw_xlfw_zxhd_log, type_archives_item } from '~/types';
- import { Search } from '@element-plus/icons-vue'
- // import { ElMessage, ElMessageBox } from 'element-plus'
- import user from '~/store/user';
- import { createSocket, socketSend } from '~/utils/ws';
- import type { TSocketRes } from '~/utils/ws';
- import { formatTimestamp2Date } from '~/utils/time';
- import { CHAT_STATUS, CHAT_OPERATION } from '~/types';
- import { showConfirmDialog, showSuccessToast, showFailToast } from 'vant';
- let dyaw_xlfw_zxhd = $ref<type_dyaw_xlfw_zxhd>(JSON.parse(sessionStorage.getItem('dyaw_xlfw_zxhd')!))
- let dyaw_xlfw_zxhd_list = $ref<type_dyaw_xlfw_zxhd[] | undefined>()
- const emits = defineEmits<{
- (event: 'openRtcDialog', dyaw_xlfw_zxhd: type_dyaw_xlfw_zxhd, type: 'audio' | 'video'): void;
- }>()
- const props = defineProps<{ updateFnList: Function[] }>()
- function formatter(e: string) {
- if (!e) return e
- // 转义字符串中的危险字符
- return e.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
- }
- let infoList = $ref<Array<type_dyaw_xlfw_zxhd_log>>([])
- let inputValue = $ref('')
- let isSending = $ref(false)
- let TinyRef = $ref<typeof import('~/components/tinymce-area/index.vue')['default']>()
- async function handleClickSend(val?: string) {
- if (!dyaw_xlfw_zxhd) return;
- if (isSending) return;
- isSending = true
- const reqDate = {
- dxz_id: dyaw_xlfw_zxhd.dxz_id,
- dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
- dxzl_stu_user_realname: dyaw_xlfw_zxhd.dxz_stu_user_realname,
- dxzl_tea_user_id: dyaw_xlfw_zxhd.dxz_tea_user_id,
- dxzl_tea_user_realname: dyaw_xlfw_zxhd.dxz_tea_user_realname,
- dxzl_last_msg_content: encodeURIComponent(val || formatter(inputValue)),
- dxzl_type: (val || formatter(inputValue)).includes('<img') ? '2' : '1'
- }
- // const reqDate = {
- // dxz_id: dyaw_xlfw_zxhd.dxz_id,
- // dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
- // dxzl_stu_user_realname: dyaw_xlfw_zxhd.dxz_stu_user_realname,
- // dxzl_tea_user_id: dyaw_xlfw_zxhd.dxz_tea_user_id,
- // dxzl_tea_user_realname: dyaw_xlfw_zxhd.dxz_tea_user_realname,
- // dxzl_last_msg_content: encodeURIComponent(inputValue),
- // dxzl_type: inputValue.includes('><img') ? '2' : '1'
- // }
- // infoList.push({
- // create_user_id: user.user_id,
- // create_dateline: Date.now().toString().slice(0, 10),
- // ...reqDate
- // })
- TinyRef?.clear()
- // console.log('inputValue :>> ', inputValue);
- request({
- url: '/dyaw/xlfw_zxhd_log/add',
- data: {
- dyaw_xlfw_zxhd_log: reqDate
- }
- }).then(res => {
- if (res.code === '1') {
- const fullSendData = {
- create_user_id: user.user_id,
- create_dateline: Date.now().toString().slice(0, 10),
- ...reqDate,
- dxzl_id: `${res.data.insert_id}`
- }
- if (!ws||ws.readyState !== 1) {
- ws = createSocket(
- { teacher: user.user_id, student: dyaw_xlfw_zxhd.dxz_stu_user_id },
- {
- message(socketRes: TSocketRes<type_dyaw_xlfw_zxhd_log & { $?: boolean, dxz_stu_user_id?: string, dyaw_xlfw_zxhd: type_dyaw_xlfw_zxhd }>) {
- if (socketRes.from_client_name.endsWith('student')) {
- if (socketRes.content.$) {
- if (socketRes.content?.dxz_stu_user_id === dyaw_xlfw_zxhd?.dxz_stu_user_id) {
- dyaw_xlfw_zxhd = socketRes.content.dyaw_xlfw_zxhd
- }
- return;
- }
- infoList.push(socketRes.content)
- request({
- url: '/dyaw/xlfw_zxhd_log/index',
- data: {
- dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
- dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- limit: 0
- }
- })
- }
- }
- }
- )
- }
- infoList.push(fullSendData)
- socketSend(ws!, fullSendData)
- isSending = false
- }
- })
- }
- let ws = $ref<WebSocket>()
- let cardLoading = $ref(true)
- let unreadNum = $ref(0)
- // function getAllUnreadMsg() {
- // request({
- // url: '/dyaw/xlfw_zxhd_log/index',
- // data: {
- // dxzl_stu_user_id: dyaw_xlfw_zxhd?.dxz_stu_user_id,
- // dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- // limit: 1
- // }
- // }).then(res => {
- // if (res.code === '1') {
- // ifScroll = false
- // infoList = (res.data.page_data.reverse())
- // unreadNum = 0
- // }
- // nextTick(() => {
- // ifScroll = true
- // // scrollbarRef!.scrollTo(0, 0);
- // })
- // })
- // }
- // function handleClickStuCard(stu: type_dyaw_xlfw_zxhd) {
- // cardLoading = true
- // dyaw_xlfw_zxhd = stu
- // unreadNum = parseInt(stu.dxz_unread_msg_num)
- // stu.dxz_unread_msg_num = "0"
- // archivesList = []
- // ws?.close()
- // request({
- // url: '/dyaw/xlfw_zxhd_log/index',
- // data: {
- // dxzl_stu_user_id: stu.dxz_stu_user_id,
- // dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- // }
- // }).then(res => {
- // if (res.code === '1') {
- // infoList = res.data.page_data.reverse()
- // cardLoading = false
- // ws = createSocket(
- // { teacher: user.user_id, student: stu.dxz_stu_user_id },
- // {
- // message(socketRes: TSocketRes<type_dyaw_xlfw_zxhd_log & { $?: boolean, dxz_stu_user_id?: string, dyaw_xlfw_zxhd: type_dyaw_xlfw_zxhd }>) {
- // if (socketRes.from_client_name.endsWith('student')) {
- // if (socketRes.content.$) {
- // if (socketRes.content?.dxz_stu_user_id === dyaw_xlfw_zxhd?.dxz_stu_user_id) {
- // dyaw_xlfw_zxhd = socketRes.content.dyaw_xlfw_zxhd
- // }
- // return;
- // }
- // infoList.push(socketRes.content)
- // request({
- // url: '/dyaw/xlfw_zxhd_log/index',
- // data: {
- // dxzl_stu_user_id: stu.dxz_stu_user_id,
- // dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- // limit: 0
- // }
- // })
- // }
- // }
- // }
- // )
- // handleQueryArchives()
- // }
- // })
- // }
- unreadNum = parseInt(dyaw_xlfw_zxhd.dxz_unread_msg_num)
- dyaw_xlfw_zxhd.dxz_unread_msg_num = "0"
- request({
- url: '/dyaw/xlfw_zxhd_log/index',
- data: {
- dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
- dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- }
- }).then(res => {
- if (res.code === '1') {
- infoList = res.data.page_data.reverse()
- cardLoading = false
- ws = createSocket(
- { teacher: user.user_id, student: dyaw_xlfw_zxhd.dxz_stu_user_id },
- {
- message(socketRes: TSocketRes<type_dyaw_xlfw_zxhd_log & { $?: boolean, dxz_stu_user_id?: string, dyaw_xlfw_zxhd: type_dyaw_xlfw_zxhd }>) {
- if (socketRes.from_client_name.endsWith('student')) {
- if (socketRes.content.$) {
- if (socketRes.content?.dxz_stu_user_id === dyaw_xlfw_zxhd?.dxz_stu_user_id) {
- dyaw_xlfw_zxhd = socketRes.content.dyaw_xlfw_zxhd
- }
- return;
- }
- infoList.push(socketRes.content)
- request({
- url: '/dyaw/xlfw_zxhd_log/index',
- data: {
- dxzl_stu_user_id: dyaw_xlfw_zxhd.dxz_stu_user_id,
- dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- limit: 0
- }
- })
- }
- }
- }
- )
- handleQueryArchives()
- }
- })
- let ifScroll = $ref(true)
- function handleLoadMoreInfo() {
- request({
- url: '/dyaw/xlfw_zxhd_log/index',
- data: {
- dxzl_stu_user_id: dyaw_xlfw_zxhd?.dxz_stu_user_id,
- dxzl_tea_user_id: dyaw_xlfw_zxhd!.dxz_tea_user_id,
- zxhd_log_id: infoList[0].dxzl_id
- }
- }).then(res => {
- if (res.code === '1') {
- ifScroll = false
- if (res.data.page_data.length === 0) return showFailToast('暂无更多消息');
- infoList.unshift(...res.data.page_data.reverse())
- }
- })
- }
- const scrollbarRef = $ref<HTMLElement>()
- const scrollContainRef = $ref<HTMLElement>()
- function scrollToBottom() {
- if (!scrollbarRef) return;
- const scrollHeight = scrollContainRef!.scrollHeight;
- // console.log('scrollHeight : ', scrollHeight)
- scrollbarRef!.scrollTo(0, scrollHeight + 200);
- }
- watch(
- () => (infoList),
- () => {
- nextTick(() => {
- ifScroll && scrollToBottom();
- ifScroll = true
- })
- },
- {
- deep: true,
- }
- )
- const ArchivesCardRef = $ref<typeof import('~/components/archives-card/index.vue')['default']>()
- function handleSubmitArchives() {
- showConfirmDialog({ message: '一次咨询只能提交一次档案,请确认完毕后点击提交', title: '提示' })
- .then(() => {
- request({
- url: '/dyaw/xlfw_xsda_dajl/add',
- data: {
- dyaw_xlfw_xsda_dajl: ArchivesCardRef!.form
- }
- }).then(res => {
- if (res.code === '1') {
- showSuccessToast('提交成功');
- handleQueryArchives()
- } else {
- showFailToast('提交失败');
- }
- })
- })
- .catch(() => {
- showFailToast('取消提交');
- })
- }
- let archivesList = $ref<type_archives_item[]>([])
- function handleQueryArchives() {
- request({
- url: '/dyaw/xlfw_xsda_dajl/index',
- data: {
- user_id: dyaw_xlfw_zxhd!.dxz_stu_user_id
- }
- }).then(res => {
- if (res.code === '1') {
- archivesList = res.data.page_data
- }
- })
- }
- // ==========
- // chat audio/video
- // ==========
- // let RtcDialogRef = $ref<typeof import("~/components/rtc-dialog/index.vue")['default']>()
- // const ws2 = createSocket(
- // { teacher: user.user_id, student: '*' },
- // {
- // message(socketRes: TSocketRes<type_dyaw_xlfw_zxhd_log & { operate: CHAT_OPERATION }>) {
- // if (socketRes.from_client_name.endsWith('student')) {
- // // infoList.push(socketRes.content)
- // if (socketRes.content.dxzl_tea_user_id === user.user_id) {
- // console.log('RtcDialogRef : ', RtcDialogRef)
- // RtcDialogRef!.publisher(socketRes.content)
- // }
- // }
- // }
- // }
- // )
- // onMounted(() => {
- // RtcDialogRef!.init(ws2)
- // })
- async function handleAudioChatStart() {
- // RtcDialogRef!.open(dyaw_xlfw_zxhd, 'audio')
- emits('openRtcDialog', dyaw_xlfw_zxhd, 'audio')
- }
- async function handleVideoChatStart() {
- // RtcDialogRef!.open(dyaw_xlfw_zxhd, 'video')
- emits('openRtcDialog', dyaw_xlfw_zxhd, 'video')
- }
- function emitUpdateInfo(info: type_dyaw_xlfw_zxhd_log, isUpdate?: boolean) {
- if (!isUpdate) {
- if (info.dxz_id === dyaw_xlfw_zxhd?.dxz_id)
- infoList.push(info)
- }
- else {
- const target = infoList.find(item => (item.dxzl_id)?.toString() === info.dxzl_id?.toString())
- if (target)
- target.dxzl_last_msg_content = info.dxzl_last_msg_content
- }
- }
- props.updateFnList.push(emitUpdateInfo)
- onBeforeUnmount(() => {
- props.updateFnList.splice(0)
- ws?.close()
- })
- const router = useRouter()
- function onClickLeft() {
- router.back()
- }
- let showRightArchives = $ref(false)
- </script>
- <template>
- <div class="h-full flex justify-center divide-x">
- <div class="w-full h-full divide-y flex flex-col relative">
- <template v-if="dyaw_xlfw_zxhd">
- <van-nav-bar
- :title="`${dyaw_xlfw_zxhd.dxz_stu_user_realname} ${dyaw_xlfw_zxhd.dxz_stu_school_name} ${dyaw_xlfw_zxhd.dxz_class_name}`"
- left-text="" left-arrow @click-left="onClickLeft" right-text="学生档案" @click-right="showRightArchives = true"
- style="--van-nav-bar-background:#397FF6;--van-nav-bar-icon-color:#fff;--van-nav-bar-title-text-color:#fff;--van-nav-bar-title-font-size:18px;--van-nav-bar-text-color:#fff;" />
- <div ref="scrollbarRef"
- class="bg-hex-ededed space-y-2 flex-auto py-2 px-6 scrollbar scrollbar-thin scrollbar-thumb-rounded-md scrollbar-thumb-gray-200 scrollbar-track-transparent relative">
- <div ref="scrollContainRef" class="scrollContainRef space-y-2">
- <div v-show="!cardLoading" @click="handleLoadMoreInfo"
- class="w-full text-center text-sm text-blue-400 hover:underline underline-blue-400 cursor-pointer">查看更多
- </div>
- <info-item v-for="item in infoList" :key="item.dxzl_id" :left="item.create_user_id !== user.user_id" :d="item"
- :w="300"></info-item>
- </div>
- </div>
- <div class="bg-hex-e4e6eb p-5px flex justify-between space-x-2 items-end">
- <tinymce-area-m v-model="inputValue" ref="TinyRef" @click:audio="handleAudioChatStart" class="flex-auto"
- @click:video="handleVideoChatStart" @click:submit="handleClickSend"></tinymce-area-m>
- <van-button type="primary" @click="handleClickSend()">发送</van-button>
- </div>
- </template>
- <template v-else>
- <div class="bg-pink-300 flex justify-between h-48px items-center px-18px"></div>
- <div class="bg-hex-fff8fb flex-auto w-full flex_center">
- <el-empty description="请先选择聊天的学生"></el-empty>
- </div>
- </template>
- </div>
- <van-popup v-model:show="showRightArchives" position="right" :style="{ width: '100vw', height: '100vh' }">
- <div
- class="w-full h-full bg-white overflow-y-auto flex flex-col items-center px-2 py-2 divide-y scrollbar scrollbar-thin scrollbar-thumb-rounded-md scrollbar-thumb-gray-200 scrollbar-track-transparent">
- <div v-if="dyaw_xlfw_zxhd" :key="dyaw_xlfw_zxhd.dxz_stu_user_id">
- <van-sticky :offset-top="8">
- <div class="mb-4 flex justify-end">
- <van-button @click="showRightArchives = false" type="primary">返回</van-button>
- </div>
- </van-sticky>
- <div class="w-full"
- v-if="archivesList && (archivesList.length === 0 || dyaw_xlfw_zxhd.dxz_id !== archivesList[0].dxz_id)">
- <archives-card storage ref="ArchivesCardRef"
- :d="{ dxz_id: dyaw_xlfw_zxhd.dxz_id, user_id: dyaw_xlfw_zxhd.dxz_stu_user_id, dxxd_lfzxm: dyaw_xlfw_zxhd.dxz_stu_user_realname, dxxd_jfls: dyaw_xlfw_zxhd.dxz_tea_user_realname, dxxd_school_name: dyaw_xlfw_zxhd.dxz_stu_school_name, dxxd_class_name: dyaw_xlfw_zxhd.dxz_class_name, dxxd_date: formatTimestamp2Date(dyaw_xlfw_zxhd.create_dateline) }"></archives-card>
- <div class="flex_center py-2">
- <van-button @click="handleSubmitArchives" type="success" size="large">提交</van-button>
- </div>
- </div>
- <div class=" py-2 space-y-1">
- <div class="flex_center text-lg">历史档案</div>
- <el-empty v-show="archivesList.length === 0" :image-size="60" description="暂无历史档案"></el-empty>
- <archives-card disabled v-for="item in archivesList" :d="item" :key="item.dxxd_id"></archives-card>
- </div>
- </div>
- </div>
- </van-popup>
- </div>
- <!-- <rtc-dialog ref="RtcDialogRef" @update-info="emitUpdateInfo"></rtc-dialog> -->
- </template>
- <style scoped lang="scss">
- </style>
|