zdg #150
|
@ -1,9 +1,9 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 2794390 */
|
font-family: "iconfont"; /* Project id 2794390 */
|
||||||
src: url('iconfont.woff2?t=1724134927539') format('woff2'),
|
src: url('iconfont.woff2?t=1724212790213') format('woff2'),
|
||||||
url('iconfont.woff?t=1724134927539') format('woff'),
|
url('iconfont.woff?t=1724212790213') format('woff'),
|
||||||
url('iconfont.ttf?t=1724134927539') format('truetype'),
|
url('iconfont.ttf?t=1724212790213') format('truetype'),
|
||||||
url('iconfont.svg?t=1724134927539#iconfont') format('svg');
|
url('iconfont.svg?t=1724212790213#iconfont') format('svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
|
@ -14,6 +14,22 @@
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-yiwen:before {
|
||||||
|
content: "\e687";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-yiwen-01:before {
|
||||||
|
content: "\e688";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-yihuo:before {
|
||||||
|
content: "\e689";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-yiwen:before {
|
||||||
|
content: "\e6b1";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-zan:before {
|
.icon-zan:before {
|
||||||
content: "\e658";
|
content: "\e658";
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,34 @@
|
||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "20574719",
|
||||||
|
"name": "疑问",
|
||||||
|
"font_class": "yiwen",
|
||||||
|
"unicode": "e687",
|
||||||
|
"unicode_decimal": 59015
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "21052326",
|
||||||
|
"name": "yiwen-01",
|
||||||
|
"font_class": "yiwen-01",
|
||||||
|
"unicode": "e688",
|
||||||
|
"unicode_decimal": 59016
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "30456317",
|
||||||
|
"name": "疑惑",
|
||||||
|
"font_class": "yihuo",
|
||||||
|
"unicode": "e689",
|
||||||
|
"unicode_decimal": 59017
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33439935",
|
||||||
|
"name": "[疑问]",
|
||||||
|
"font_class": "a-yiwen",
|
||||||
|
"unicode": "e6b1",
|
||||||
|
"unicode_decimal": 59057
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "1242129",
|
"icon_id": "1242129",
|
||||||
"name": "赞",
|
"name": "赞",
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 302 KiB After Width: | Height: | Size: 337 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9,6 +9,7 @@
|
||||||
import * as TYPES from './enumbers' // sdk相关枚举
|
import * as TYPES from './enumbers' // sdk相关枚举
|
||||||
import MsgEnum from './msgEnum' // 消息相关枚举(自定义)
|
import MsgEnum from './msgEnum' // 消息相关枚举(自定义)
|
||||||
import IMListeners from './imLiseners' // im消息-监听器
|
import IMListeners from './imLiseners' // im消息-监听器
|
||||||
|
// @ts-ignore
|
||||||
const API = window.api
|
const API = window.api
|
||||||
// TIM生成签名
|
// TIM生成签名
|
||||||
// import * as GenerateUserSig from './userSig' // 引入签名生成器
|
// import * as GenerateUserSig from './userSig' // 引入签名生成器
|
||||||
|
@ -31,16 +32,23 @@ export class ImChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 构造函数
|
||||||
|
* @param {number} SDKAppID
|
||||||
|
* @param {string} userSig
|
||||||
|
* @param {string} userID
|
||||||
|
* @param {boolean} isInit
|
||||||
|
*/
|
||||||
constructor(SDKAppID, userSig, userID, isInit) {
|
constructor(SDKAppID, userSig, userID, isInit) {
|
||||||
this.SDKAppID = SDKAppID
|
this.SDKAppID = SDKAppID
|
||||||
this.userSig = userSig
|
this.userSig = userSig
|
||||||
this.userID = userID
|
this.userID = userID
|
||||||
// window.test = this
|
// window.test = this
|
||||||
if (isInit) return this.init()
|
if (isInit) this.init()
|
||||||
}
|
}
|
||||||
// 设置配置
|
// 设置配置
|
||||||
async setConfig() {
|
async setConfig() {
|
||||||
const res=await this.timChat.TIMSetConfig({ // TIMSetConfigParam
|
await this.timChat.TIMSetConfig({ // TIMSetConfigParam
|
||||||
json_config: { // JSONCongfig
|
json_config: { // JSONCongfig
|
||||||
set_config_log_level: TYPES.TIMLogLevel.kTIMLog_Test,
|
set_config_log_level: TYPES.TIMLogLevel.kTIMLog_Test,
|
||||||
set_config_callback_log_level: TYPES.TIMLogLevel.kTIMLog_Error,
|
set_config_callback_log_level: TYPES.TIMLogLevel.kTIMLog_Error,
|
||||||
|
@ -87,15 +95,18 @@ export class ImChat {
|
||||||
}
|
}
|
||||||
// 生成签名
|
// 生成签名
|
||||||
genTestUserSig() {
|
genTestUserSig() {
|
||||||
const options = {
|
// const options = {
|
||||||
SDKAppID: this.SDKAppID,
|
// SDKAppID: this.SDKAppID,
|
||||||
secretKey: this.secretKey,
|
// secretKey: this.secretKey,
|
||||||
userID: this.userID,
|
// userID: this.userID,
|
||||||
}
|
// }
|
||||||
const { userSig } = GenerateUserSig.genTestUserSig(options)
|
// const { userSig } = GenerateUserSig.genTestUserSig(options)
|
||||||
this.userSig = userSig
|
// this.userSig = userSig
|
||||||
}
|
}
|
||||||
// 监听
|
/**
|
||||||
|
* @description 监听消息
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
watch(callback) {
|
watch(callback) {
|
||||||
// // 先移除监听
|
// // 先移除监听
|
||||||
// this.timChat.TIMRemoveRecvNewMsgCallback()
|
// this.timChat.TIMRemoveRecvNewMsgCallback()
|
||||||
|
@ -167,7 +178,11 @@ export class ImChat {
|
||||||
return error
|
return error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 创建群组 群名和初始成员 userID
|
/**
|
||||||
|
* @description 创建群组 群名和初始成员 userID
|
||||||
|
* @param {any} name
|
||||||
|
* @param {any[]} memberList
|
||||||
|
*/
|
||||||
createGroup(name, memberList=[]) {
|
createGroup(name, memberList=[]) {
|
||||||
if (!this.timChat) return
|
if (!this.timChat) return
|
||||||
if (!!this.timGroupId) return console.log('群组已存在')
|
if (!!this.timGroupId) return console.log('群组已存在')
|
||||||
|
@ -216,7 +231,10 @@ export class ImChat {
|
||||||
data: '', // 用户自定义数据
|
data: '', // 用户自定义数据
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 设置群消息接收
|
/**
|
||||||
|
* @description 设置群消息接收
|
||||||
|
* @param {string} timGroupId
|
||||||
|
*/
|
||||||
setGroupMsgReceive(timGroupId) {
|
setGroupMsgReceive(timGroupId) {
|
||||||
if (!this.timGroupId) this.timGroupId = timGroupId || ''
|
if (!this.timGroupId) this.timGroupId = timGroupId || ''
|
||||||
if (!this.timGroupId) return console.log('timGroupId为空')
|
if (!this.timGroupId) return console.log('timGroupId为空')
|
||||||
|
@ -236,7 +254,11 @@ export class ImChat {
|
||||||
return error
|
return error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 发送消息
|
/**
|
||||||
|
* @description 发送消息
|
||||||
|
* @param {any} conv_id
|
||||||
|
* @param {any} msg
|
||||||
|
*/
|
||||||
sendMsg(conv_id, msg) {
|
sendMsg(conv_id, msg) {
|
||||||
if (!conv_id) return console.log('conv_id为空')
|
if (!conv_id) return console.log('conv_id为空')
|
||||||
if (typeof msg == 'object') msg = JSON.stringify(msg)
|
if (typeof msg == 'object') msg = JSON.stringify(msg)
|
||||||
|
@ -255,15 +277,33 @@ export class ImChat {
|
||||||
user_data: '', // 用户自定义数据
|
user_data: '', // 用户自定义数据
|
||||||
// callback: (data) => {}
|
// callback: (data) => {}
|
||||||
}
|
}
|
||||||
console.log('发送消息', option)
|
// console.log('发送消息', option)
|
||||||
|
this.setConsole('%cim-chat: 发送消息', option)
|
||||||
return this.timChat.TIMMsgSendMessageV2(option)
|
return this.timChat.TIMMsgSendMessageV2(option)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @description 发送群消息
|
||||||
|
* @param {any} msg
|
||||||
|
* @param {*} head
|
||||||
|
* @param {*} type
|
||||||
|
*/
|
||||||
|
sendMsgGroup(msg, head, type) {
|
||||||
|
const msgObj = this.getMsgObj(head, msg, type)
|
||||||
|
// console.log('发送群消息', msgObj)
|
||||||
|
return this.sendMsg(this.timGroupId, msgObj)
|
||||||
|
}
|
||||||
// 发送关闭(下课)消息
|
// 发送关闭(下课)消息
|
||||||
sendMsgClosed(){
|
sendMsgClosed(){
|
||||||
const msg = this.getMsgObj(MsgEnum.HEADS.MSG_closed, '下课', MsgEnum.TYPES.TEACHER)
|
const msg = this.getMsgObj(MsgEnum.HEADS.MSG_closed, '下课')
|
||||||
return this.sendMsg(this.timGroupId, msg)
|
return this.sendMsg(this.timGroupId, msg)
|
||||||
}
|
}
|
||||||
// 获取消息对象
|
/**
|
||||||
|
* @description 获取消息对象
|
||||||
|
* @param {string} msgHead
|
||||||
|
* @param {string} msg
|
||||||
|
* @param {string} type
|
||||||
|
* @param {string|number} sender
|
||||||
|
*/
|
||||||
getMsgObj(msgHead, msg, type, sender, option={}) {
|
getMsgObj(msgHead, msg, type, sender, option={}) {
|
||||||
if (!msgHead) throw new Error('msgHead is required')
|
if (!msgHead) throw new Error('msgHead is required')
|
||||||
if (!msg) throw new Error('msg is required')
|
if (!msg) throw new Error('msg is required')
|
||||||
|
@ -271,19 +311,27 @@ export class ImChat {
|
||||||
return {
|
return {
|
||||||
msgKey: msgHead,
|
msgKey: msgHead,
|
||||||
msgcontent: msg,
|
msgcontent: msg,
|
||||||
msgType: type ?? MsgEnum.TYPES.STUDENT, // 默认为学生
|
msgType: type || MsgEnum.TYPES.TEACHER, // 默认为老师
|
||||||
senduserid: sender ?? this.userID,
|
senduserid: sender ?? this.userID,
|
||||||
...option
|
...option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 设置控制台样式
|
/**
|
||||||
|
* @description 设置控制台样式
|
||||||
|
* @param {string} hearStr
|
||||||
|
* @param {string[]} args
|
||||||
|
*/
|
||||||
setConsole(hearStr,...args) {
|
setConsole(hearStr,...args) {
|
||||||
const css = 'color: #fff;background-color:#2ccb92;padding:3px 5px;border-radius:3px;'
|
const css = 'color: #fff;background-color:#2ccb92;padding:3px 5px;border-radius:3px;'
|
||||||
const time = new Date().toLocaleTimeString()
|
const time = new Date().toLocaleTimeString()
|
||||||
if (!hearStr) hearStr = '%c' + time
|
if (!hearStr) hearStr = '%c' + time
|
||||||
console.log(hearStr, css, ...args)
|
console.log(hearStr, css, ...args)
|
||||||
}
|
}
|
||||||
// 获取数据字符串
|
/**
|
||||||
|
* @description 获取数据字符串
|
||||||
|
* @param {*} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
toStr = (data) => {
|
toStr = (data) => {
|
||||||
if (typeof data === 'string') data = {type: data}
|
if (typeof data === 'string') data = {type: data}
|
||||||
return JSON.stringify(data)
|
return JSON.stringify(data)
|
||||||
|
|
|
@ -95,6 +95,7 @@ export class MsgEnum {
|
||||||
// === 新定义-消息头 ===
|
// === 新定义-消息头 ===
|
||||||
/** @desc: 点赞 */
|
/** @desc: 点赞 */
|
||||||
MSG_0001: 0x0001,
|
MSG_0001: 0x0001,
|
||||||
|
/** @desc: 疑惑 */
|
||||||
MSG_0002: 0x0002,
|
MSG_0002: 0x0002,
|
||||||
MSG_0003: 0x0003,
|
MSG_0003: 0x0003,
|
||||||
MSG_0004: 0x0004,
|
MSG_0004: 0x0004,
|
||||||
|
@ -109,6 +110,7 @@ export class MsgEnum {
|
||||||
MSG_0013: 0x000d,
|
MSG_0013: 0x000d,
|
||||||
MSG_0014: 0x000e,
|
MSG_0014: 0x000e,
|
||||||
MSG_0015: 0x000f,
|
MSG_0015: 0x000f,
|
||||||
|
/** @desc: 作业推送 */
|
||||||
MSG_0016: 0x0010,
|
MSG_0016: 0x0010,
|
||||||
MSG_0017: 0x0011,
|
MSG_0017: 0x0011,
|
||||||
MSG_0018: 0x0012,
|
MSG_0018: 0x0012,
|
||||||
|
|
|
@ -77,14 +77,14 @@ import { getSmarttalkPage, getPrepareById } from '@/api/file'
|
||||||
import SetHomework from '@/views/prepare/container/set-homework.vue'
|
import SetHomework from '@/views/prepare/container/set-homework.vue'
|
||||||
import FileImage from '@/components/file-image/index.vue'
|
import FileImage from '@/components/file-image/index.vue'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
import { ipcMsgSend } from '@/utils/tool'
|
import { ipcMsgSend, ipcMsgInvoke } from '@/utils/tool'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import { asyncLocalFile } from '@/utils/talkFile'
|
import { asyncLocalFile } from '@/utils/talkFile'
|
||||||
import Lesson from './lesson.vue';
|
import Lesson from './lesson.vue';
|
||||||
import { parseCataByNode } from '@/utils/talkFile'
|
import { parseCataByNode } from '@/utils/talkFile'
|
||||||
import outLink from '@/utils/linkConfig'
|
import outLink from '@/utils/linkConfig'
|
||||||
|
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息枚举
|
||||||
|
|
||||||
import { ipcMsgSend2 } from '@/utils/tool'
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const usertore = useUserStore().user
|
const usertore = useUserStore().user
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
|
@ -110,8 +110,10 @@ const sendHomework = (row) => {
|
||||||
setDialog.value = true
|
setDialog.value = true
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
const closeHomework = () => {
|
const closeHomework = async() => {
|
||||||
ipcMsgSend('tool-sphere:set:ignore', true)
|
ipcMsgSend('tool-sphere:set:ignore', true)
|
||||||
|
// 发送im消息-推送作业(app|平板)
|
||||||
|
await ipcMsgInvoke('im-chat:msg', curRow.value.id, MsgEnum.HEADS.MSG_0016)
|
||||||
setDialog.value = false
|
setDialog.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { onMounted, ref, reactive, watchEffect } from 'vue'
|
||||||
import { ImChat } from '@/plugins/imChat'
|
import { ImChat } from '@/plugins/imChat'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import * as http from '@/api/apiService' // 自定义api service
|
import * as http from '@/api/apiService' // 自定义api service
|
||||||
// import { ipcMsgSend, ipcHandle, ipcMain, ipcMsgInvoke } from '@/utils/tool' // 相关工具
|
import { ipcMsgSend, ipcHandle, ipcMain, ipcMsgInvoke } from '@/utils/tool' // 相关工具
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const emits = defineEmits(['change'])
|
const emits = defineEmits(['change'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -12,8 +12,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const imChatObj = reactive({imChat:null})
|
const imChatObj = reactive({imChat:null})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// console.log(imChatObj)
|
ipcMainHandle() // 绑定-监听ipcMain im相关消息
|
||||||
// initImChat()
|
|
||||||
})
|
})
|
||||||
// 初始化 im-chat
|
// 初始化 im-chat
|
||||||
const initImChat = async (timGroupId) => {
|
const initImChat = async (timGroupId) => {
|
||||||
|
@ -95,6 +94,14 @@ const logout = () => imChatObj.imChat?.logout()
|
||||||
// 解散群
|
// 解散群
|
||||||
const deleteGroup = () => imChatObj.imChat?.deleteGroup()
|
const deleteGroup = () => imChatObj.imChat?.deleteGroup()
|
||||||
|
|
||||||
|
// 绑定-监听ipcMain im相关消息
|
||||||
|
const ipcMainHandle = () => {
|
||||||
|
ipcMain?.removeHandler?.('im-chat:msg') // 先移除已有的 ipcMain 消息
|
||||||
|
ipcMain?.handle?.('im-chat:msg', (e, msg, head, type) => { // 重新绑定 ipcMain 消息
|
||||||
|
return imChatObj.imChat?.sendMsgGroup(msg, head, type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({ initImChat, logout, deleteGroup, imChatObj })
|
defineExpose({ initImChat, logout, deleteGroup, imChatObj })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="warp" ref="btnRef">
|
<div class="warp" ref="btnRef" :style="isFold?'min-height:auto;':''">
|
||||||
<slot name="start"></slot>
|
<slot name="start"></slot>
|
||||||
<!-- 工具按钮 -->
|
<!-- 工具按钮 -->
|
||||||
<el-space direction="vertical">
|
<el-space direction="vertical" v-show="!isFold">
|
||||||
<template v-for="(item,index) in list">
|
<template v-for="(item,index) in list">
|
||||||
<slot :name="item.prop" :item="item" :index="index">
|
<slot :name="item.prop" :item="item" :index="index">
|
||||||
<div class="c-btn flex flex-col items-center gap-2 p-2" @click.stop="clickHandel(item,$event)">
|
<div class="c-btn flex flex-col items-center gap-2 p-2" @click.stop="clickHandel(item,$event)">
|
||||||
|
@ -13,7 +13,11 @@
|
||||||
</template>
|
</template>
|
||||||
<slot name="append"></slot>
|
<slot name="append"></slot>
|
||||||
</el-space>
|
</el-space>
|
||||||
<slot name="end"></slot>
|
<slot name="end">
|
||||||
|
<span class="fold" @click="isFold=!isFold" :style="isFold?'margin: 5px;':''">
|
||||||
|
{{isFold?'<<<':'>>>'}}
|
||||||
|
</span>
|
||||||
|
</slot>
|
||||||
<!-- 内容部分 -->
|
<!-- 内容部分 -->
|
||||||
<transition name="el-fade-in">
|
<transition name="el-fade-in">
|
||||||
<div class="c-popover" :style="`--top: ${topPos}px;--height:${hPost}px;`" v-show="isVisible">
|
<div class="c-popover" :style="`--top: ${topPos}px;--height:${hPost}px;`" v-show="isVisible">
|
||||||
|
@ -54,6 +58,7 @@ const activeObj = ref(null) // 当前激活的按钮
|
||||||
const btnRef = ref(null) // 按钮元素-ref
|
const btnRef = ref(null) // 按钮元素-ref
|
||||||
const topPos = ref(30) // 顶部距离-内容的距离
|
const topPos = ref(30) // 顶部距离-内容的距离
|
||||||
const hPost = ref(0) // 顶部距离-内容的距离
|
const hPost = ref(0) // 顶部距离-内容的距离
|
||||||
|
const isFold = ref(false) // 是否折叠
|
||||||
let posBtnAll = {} // 存储位置
|
let posBtnAll = {} // 存储位置
|
||||||
// === 计算属性 ===
|
// === 计算属性 ===
|
||||||
const list = computed(() => props.data.map((o,i) => {
|
const list = computed(() => props.data.map((o,i) => {
|
||||||
|
@ -100,7 +105,7 @@ const clickHandel = (o, e) => {
|
||||||
min-width: 4em;
|
min-width: 4em;
|
||||||
border-radius: 4em;
|
border-radius: 4em;
|
||||||
background-color: #121212;
|
background-color: #121212;
|
||||||
.el-space{margin: 20px 0;}
|
.el-space{margin: 20px 0 0;}
|
||||||
.c-btn{
|
.c-btn{
|
||||||
color: #d9dce3;
|
color: #d9dce3;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -113,6 +118,20 @@ const clickHandel = (o, e) => {
|
||||||
background: #454545fa;
|
background: #454545fa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.fold{
|
||||||
|
display: block;
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
&:hover{
|
||||||
|
color: #409eff;
|
||||||
|
border-radius: 4px;
|
||||||
|
// background: #454545fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.c-popover{
|
.c-popover{
|
||||||
--top: 30px;
|
--top: 30px;
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<el-button v-if="props.test" type="primary" @click="trigger">测试</el-button>
|
<div v-if="props.test">
|
||||||
|
<el-button type="primary" @click="trigger">点赞</el-button>
|
||||||
|
<el-button type="primary" @click="trigger(1, '学生A')">疑惑</el-button>
|
||||||
|
</div>
|
||||||
<div ref="warpRef" class="c-warp">
|
<div ref="warpRef" class="c-warp">
|
||||||
<template v-for="(item, index) in iconCache.list">
|
<template v-for="(item, index) in iconCache.list">
|
||||||
<slot>
|
<slot>
|
||||||
<el-icon v-if="props.def"><Star /></el-icon>
|
<el-icon v-if="props.def"><Star /></el-icon>
|
||||||
<svg v-else class="icon" aria-hidden="true">
|
<div v-else class="item">
|
||||||
<use :xlink:href="`#icon-`+item.icon"></use>
|
<svg class="icon" aria-hidden="true">
|
||||||
</svg>
|
<use :xlink:href="`#icon-`+item.icon"></use>
|
||||||
|
</svg>
|
||||||
|
<!-- 学生姓名 -->
|
||||||
|
<div class="tip" v-if="item.name">
|
||||||
|
<span :title="item.name">{{item.name}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,18 +29,22 @@ const props = defineProps({ test: Boolean, def: Boolean })
|
||||||
const slots = useSlots() // 获取插槽
|
const slots = useSlots() // 获取插槽
|
||||||
let iconCache = reactive({list:[]}) // 图标缓存
|
let iconCache = reactive({list:[]}) // 图标缓存
|
||||||
const isSlot = !!Object.keys(slots).length // 是否使用了插槽
|
const isSlot = !!Object.keys(slots).length // 是否使用了插槽
|
||||||
// === 方法 ===
|
// === 触发 type 1 疑惑 def 点赞 ===
|
||||||
const trigger = async () => {
|
const trigger = async (type, name) => {
|
||||||
|
if (typeof type == 'string') { name = type; type = 1 } // 兼容
|
||||||
iconCache.list.push({
|
iconCache.list.push({
|
||||||
icon: isSlot||props.def ? '' : getRandomIcon() // 图标
|
name,
|
||||||
|
icon: isSlot||props.def ? '' : getRandomIcon(type) // 图标
|
||||||
})
|
})
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const el = warpRef.value.lastElementChild // 获取最后一个新加的元素
|
const el = warpRef.value.lastElementChild // 获取最后一个新加的元素
|
||||||
animInit(el)
|
const tipEl = el.querySelector('.tip') // 获取提示元素
|
||||||
|
// console.log(el)
|
||||||
|
animInit(el, tipEl, type)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 初始化动画
|
// 初始化动画
|
||||||
const animInit = (el) => {
|
const animInit = (el, tipEl, type) => {
|
||||||
const { height, width } = el.getBoundingClientRect()
|
const { height, width } = el.getBoundingClientRect()
|
||||||
const sumH = warpRef.value.clientHeight
|
const sumH = warpRef.value.clientHeight
|
||||||
const sumW = warpRef.value.clientWidth
|
const sumW = warpRef.value.clientWidth
|
||||||
|
@ -41,13 +54,23 @@ const animInit = (el) => {
|
||||||
let opacity = 0 // 透明度
|
let opacity = 0 // 透明度
|
||||||
let scale = 0 // 缩放
|
let scale = 0 // 缩放
|
||||||
let transform = '' // 旋转 缩放 偏移等操作
|
let transform = '' // 旋转 缩放 偏移等操作
|
||||||
|
let transform2 = '' // 旋转 缩放 偏移等操作-恢复
|
||||||
let right = getRandom(5, maxw, false, true) // 随机-右距离
|
let right = getRandom(5, maxw, false, true) // 随机-右距离
|
||||||
let isPlus = getRandomBool()?'':'-' // 随机-方向
|
let isPlus = getRandomBool()?'':'-' // 随机-方向
|
||||||
|
let isPlus2 = isPlus ? '' : '-' // 随机-方向-恢复
|
||||||
let rotate = getRandom(0, 60, false, true) // 随机-旋转
|
let rotate = getRandom(0, 60, false, true) // 随机-旋转
|
||||||
let scaleMax = getRandom(0.5, 1.5, true, true)+1 // 随机-缩放倍数
|
let scaleMax = getRandom(0.5, 1.5, true, true)+1 // 随机-缩放倍数
|
||||||
setStatic(el,'position','absolute') // 设置-定位
|
setStatic(el,'position','absolute') // 设置-定位
|
||||||
setStatic(el, 'right', right, 'px') // 设置-右距离
|
setStatic(el, 'right', right, 'px') // 设置-右距离
|
||||||
|
// 特殊处理
|
||||||
|
if (type === 1) { // 疑惑
|
||||||
|
rotate = getRandom(0, 15, false, true) // 随机-旋转
|
||||||
|
scaleMax = getRandom(2.5, 3, true, true) // 随机-缩放倍数
|
||||||
|
}
|
||||||
|
// console.log('zdg: ', right, isPlus, rotate, scaleMax, maxw)
|
||||||
|
|
||||||
const amFn = () => { // opacity: 0.5;
|
const amFn = () => { // opacity: 0.5;
|
||||||
|
// if (bottom == 130) return
|
||||||
// 到顶了- 移除元素
|
// 到顶了- 移除元素
|
||||||
if (bottom > maxH) {el.remove();resetIconCache();return}
|
if (bottom > maxH) {el.remove();resetIconCache();return}
|
||||||
// 透明度: 进入-慢慢出现
|
// 透明度: 进入-慢慢出现
|
||||||
|
@ -58,12 +81,16 @@ const animInit = (el) => {
|
||||||
// 缩放:退出-慢慢缩小
|
// 缩放:退出-慢慢缩小
|
||||||
else if (bottom > maxH - (scaleMax/0.1) && scale > 0) scale = toNumber(scale - 0.1)
|
else if (bottom > maxH - (scaleMax/0.1) && scale > 0) scale = toNumber(scale - 0.1)
|
||||||
bottom++
|
bottom++
|
||||||
// console.log('zdg: ', scale)
|
// console.log('zdg: ', scale) rotate(${isPlus2}${rotate}deg)
|
||||||
// 设置样式
|
// 设置样式
|
||||||
transform = `rotate(${isPlus}${rotate}deg) scale(${scale})`
|
transform = `rotate(${isPlus}${rotate}deg) scale(${scale})`
|
||||||
setStatic(el, 'bottom', bottom, 'px')
|
setStatic(el, 'bottom', bottom, 'px')
|
||||||
setStatic(el, 'opacity', opacity)
|
setStatic(el, 'opacity', opacity)
|
||||||
setStatic(el, 'transform', transform)
|
setStatic(el, 'transform', transform)
|
||||||
|
if (!!tipEl && type) {
|
||||||
|
transform2 = `rotate(${isPlus2}${rotate}deg) scale(${toNumber(1/scale)})`
|
||||||
|
setStatic(tipEl, 'transform', transform2)
|
||||||
|
}
|
||||||
requestAnimationFrame(amFn)
|
requestAnimationFrame(amFn)
|
||||||
}
|
}
|
||||||
amFn() // 初次执行
|
amFn() // 初次执行
|
||||||
|
@ -77,13 +104,21 @@ const resetIconCache = () => {
|
||||||
if (!len && iconCache.list.length) iconCache.list = []
|
if (!len && iconCache.list.length) iconCache.list = []
|
||||||
}
|
}
|
||||||
// 随机图案样式-默认
|
// 随机图案样式-默认
|
||||||
const getRandomIcon = () => {
|
const getRandomIcon = (type) => {
|
||||||
const iconArr = [ // 阿里icon
|
let iconArr = []
|
||||||
'zan10', 'zanping', 'zan9', 'dianzan-red', 'zan8', 'zan11', 'zan7', 'MBEfenggeduosetubiao-xihuan',
|
switch (type) {
|
||||||
'zan6', 'zan-yizan', 'zan5', 'yizan', 'zan4', 'zan3', 'zan2', 'zan1', 'zan'
|
case 1: // 阿里icon-疑惑
|
||||||
]
|
iconArr = ['yiwen', 'a-yiwen', 'yihuo', 'yiwen-01']
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
iconArr = [ // 阿里icon-点赞
|
||||||
|
'zan10', 'zanping', 'zan9', 'dianzan-red', 'zan8', 'zan11', 'zan7', 'MBEfenggeduosetubiao-xihuan',
|
||||||
|
'zan6', 'zan-yizan', 'zan5', 'yizan', 'zan4', 'zan3', 'zan2', 'zan1', 'zan'
|
||||||
|
]
|
||||||
|
break
|
||||||
|
}
|
||||||
const ind = getRandom(0, iconArr.length-1)
|
const ind = getRandom(0, iconArr.length-1)
|
||||||
return iconArr[ind]
|
return iconArr[ind]||''
|
||||||
}
|
}
|
||||||
// 随机数 isFloat:是否小数 isMax:是否包含最大值
|
// 随机数 isFloat:是否小数 isMax:是否包含最大值
|
||||||
const getRandom = (min, max, isFloat, isMax, pos=2) => {
|
const getRandom = (min, max, isFloat, isMax, pos=2) => {
|
||||||
|
@ -109,5 +144,39 @@ defineExpose({ trigger })
|
||||||
width: 30%;
|
width: 30%;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
.item{
|
||||||
|
display: inline-block;
|
||||||
|
.tip{
|
||||||
|
position: absolute;
|
||||||
|
padding: 3px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: linear-gradient(90deg, #9fe597, #cce581);
|
||||||
|
font-size: 12px;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 65px;
|
||||||
|
transform-origin: right top;
|
||||||
|
span{
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
/* text-overflow: ellipsis; */
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
&::before{
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
z-index: -1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: linear-gradient(45deg, #b2e68d, #bce689);
|
||||||
|
bottom: -3px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -78,7 +78,7 @@ const btnList = [ // 工具栏按钮列表
|
||||||
]
|
]
|
||||||
// === 页面加载完毕 ===
|
// === 页面加载完毕 ===
|
||||||
onMounted(async() => {
|
onMounted(async() => {
|
||||||
// getClassInfo() // 获取课堂详情 ex3
|
getClassInfo() // 获取课堂详情 ex3
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resetStatus() // 开启重置状态-监听
|
resetStatus() // 开启重置状态-监听
|
||||||
}, 200);
|
}, 200);
|
||||||
|
@ -126,10 +126,11 @@ const chatChange = (type, data, ...args) => {
|
||||||
const msgId = (args||[])[0].message_msg_id
|
const msgId = (args||[])[0].message_msg_id
|
||||||
const { msgKey:head, msgcontent:msg, senduserid:sendId, msgType } = data
|
const { msgKey:head, msgcontent:msg, senduserid:sendId, msgType } = data
|
||||||
switch(head) {
|
switch(head) {
|
||||||
case MsgEnum.HEADS.MSG_0001:
|
case MsgEnum.HEADS.MSG_0001: // 点赞
|
||||||
|
case MsgEnum.HEADS.MSG_0002: // 疑惑
|
||||||
// console.log('点赞:', data)
|
// console.log('点赞:', data)
|
||||||
if(msgIds.includes(msgId)) return // 忽略重复-点赞消息
|
if(msgIds.includes(msgId)) return // 忽略重复-点赞消息
|
||||||
upvoteRef.value.trigger() // 触发点赞
|
upvoteRef.value.trigger(data.name) // 触发点赞|疑惑
|
||||||
if (msgIds.length >= 100) msgIds.shift() // 删除第一个
|
if (msgIds.length >= 100) msgIds.shift() // 删除第一个
|
||||||
msgIds.push(msgId) // 添加到数组
|
msgIds.push(msgId) // 添加到数组
|
||||||
break
|
break
|
||||||
|
@ -146,6 +147,7 @@ const setIgnore = (bool) => {ipcMsgSend('tool-sphere:set:ignore', bool)}
|
||||||
// 重置状态: 鼠标|画板
|
// 重置状态: 鼠标|画板
|
||||||
const resetStatus = () => {
|
const resetStatus = () => {
|
||||||
if (toolStore.isToolWin) return // 已经打开过-忽略
|
if (toolStore.isToolWin) return // 已经打开过-忽略
|
||||||
|
ipcMain?.removeHandler('tool-sphere:reset') // 避免已绑定,先移除在绑定
|
||||||
ipcMain?.handle?.('tool-sphere:reset', () => {
|
ipcMain?.handle?.('tool-sphere:reset', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
boardVueRef.value.handleMode(tabActive.value)
|
boardVueRef.value.handleMode(tabActive.value)
|
||||||
|
|
Loading…
Reference in New Issue