mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-07 17:38:55 +08:00
refactor: 四端完成 Options API → script setup + vuex → pinia 迁移
- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup> - 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录) - util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入 - 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md) - 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API - 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
This commit is contained in:
@@ -3,48 +3,42 @@
|
||||
<router-view v-if="showView" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from "vue";
|
||||
import { setRefreshView } from "@/utils/app-bridge";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
data () {
|
||||
return {
|
||||
// 用于点击当前页的router时,刷新当前页
|
||||
showView: true,
|
||||
beforeUnload: '',
|
||||
Handler: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 刷新当前路由方法
|
||||
refreshView () {
|
||||
this.showView = false
|
||||
this.$nextTick(() => (this.showView = true))
|
||||
},
|
||||
beforeunloadHandler () {
|
||||
this.beforeUnload = new Date().getTime();
|
||||
},
|
||||
// 页面关闭后 重置btnHide
|
||||
unloadHandler (e) {
|
||||
this.Handler = new Date().getTime() - this.beforeUnload;
|
||||
if (this.Handler <= 5) {
|
||||
var storage = window.localStorage;
|
||||
storage.clear()
|
||||
localStorage.setItem('btnHide', 1)
|
||||
}
|
||||
},
|
||||
},
|
||||
defineOptions({ name: 'App' });
|
||||
|
||||
mounted () {
|
||||
setRefreshView(this.refreshView.bind(this));
|
||||
window.addEventListener('beforeunload', e => this.beforeunloadHandler(e))
|
||||
window.addEventListener('unload', e => this.unloadHandler(e))
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))
|
||||
window.removeEventListener('unload', e => this.unloadHandler(e))
|
||||
},
|
||||
// 用于点击当前页的router时,刷新当前页
|
||||
const showView = ref(true);
|
||||
let beforeUnload = '';
|
||||
let Handler = '';
|
||||
|
||||
// 刷新当前路由方法
|
||||
function refreshView () {
|
||||
showView.value = false
|
||||
nextTick(() => (showView.value = true))
|
||||
}
|
||||
function beforeunloadHandler () {
|
||||
beforeUnload = new Date().getTime();
|
||||
}
|
||||
// 页面关闭后 重置btnHide
|
||||
function unloadHandler (e) {
|
||||
Handler = new Date().getTime() - beforeUnload;
|
||||
if (Handler <= 5) {
|
||||
var storage = window.localStorage;
|
||||
storage.clear()
|
||||
localStorage.setItem('btnHide', 1)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setRefreshView(refreshView);
|
||||
window.addEventListener('beforeunload', e => beforeunloadHandler(e))
|
||||
window.addEventListener('unload', e => unloadHandler(e))
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('beforeunload', e => beforeunloadHandler(e))
|
||||
window.removeEventListener('unload', e => unloadHandler(e))
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -42,171 +42,175 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { PrismEditor } from "vue-prism-editor";
|
||||
import "vue-prism-editor/dist/prismeditor.min.css";
|
||||
import "prismjs/themes/prism-okaidia.css";
|
||||
export default {
|
||||
name: "TalkCodeBlock",
|
||||
components: {
|
||||
PrismEditor,
|
||||
},
|
||||
props: {
|
||||
loadCode: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
loadLang: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
language: "",
|
||||
code: "",
|
||||
options: [
|
||||
{
|
||||
value: "css",
|
||||
label: "css",
|
||||
},
|
||||
{
|
||||
value: "less",
|
||||
label: "less",
|
||||
},
|
||||
{
|
||||
value: "javascript",
|
||||
label: "javascript",
|
||||
},
|
||||
{
|
||||
value: "json",
|
||||
label: "json",
|
||||
},
|
||||
{
|
||||
value: "bash",
|
||||
label: "bash",
|
||||
},
|
||||
{
|
||||
value: "c",
|
||||
label: "c",
|
||||
},
|
||||
{
|
||||
value: "cil",
|
||||
label: "cil",
|
||||
},
|
||||
{
|
||||
value: "docker",
|
||||
label: "docker",
|
||||
},
|
||||
{
|
||||
value: "git",
|
||||
label: "git",
|
||||
},
|
||||
{
|
||||
value: "go",
|
||||
label: "go",
|
||||
},
|
||||
{
|
||||
value: "java",
|
||||
label: "java",
|
||||
},
|
||||
{
|
||||
value: "lua",
|
||||
label: "lua",
|
||||
},
|
||||
{
|
||||
value: "nginx",
|
||||
label: "nginx",
|
||||
},
|
||||
{
|
||||
value: "objectivec",
|
||||
label: "objectivec",
|
||||
},
|
||||
{
|
||||
value: "php",
|
||||
label: "php",
|
||||
},
|
||||
{
|
||||
value: "python",
|
||||
label: "python",
|
||||
},
|
||||
{
|
||||
value: "ruby",
|
||||
label: "ruby",
|
||||
},
|
||||
{
|
||||
value: "rust",
|
||||
label: "rust",
|
||||
},
|
||||
{
|
||||
value: "sql",
|
||||
label: "sql",
|
||||
},
|
||||
{
|
||||
value: "swift",
|
||||
label: "swift",
|
||||
},
|
||||
{
|
||||
value: "vim",
|
||||
label: "vim",
|
||||
},
|
||||
{
|
||||
value: "visual-basic",
|
||||
label: "visual-basic",
|
||||
},
|
||||
{
|
||||
value: "shell",
|
||||
label: "shell",
|
||||
},
|
||||
],
|
||||
isFullScreen: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
loadCode(value) {
|
||||
this.code = value;
|
||||
},
|
||||
loadLang(value) {
|
||||
this.language = value;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.code = this.loadCode;
|
||||
this.language = this.loadLang;
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (!this.code) {
|
||||
this.$message.error("代码块不能为空...");
|
||||
return false;
|
||||
}
|
||||
import { ElMessage } from "@/utils/message";
|
||||
|
||||
if (this.language == "") {
|
||||
this.$message.error("请选择语言");
|
||||
return false;
|
||||
}
|
||||
defineOptions({ name: "TalkCodeBlock" });
|
||||
|
||||
if (this.code.length > 10000) {
|
||||
this.$message.error("代码字数不能超过10000字!!!");
|
||||
return false;
|
||||
}
|
||||
this.$emit("confirm", {
|
||||
language: this.language,
|
||||
code: this.code,
|
||||
});
|
||||
},
|
||||
close() {
|
||||
this.$emit("close");
|
||||
},
|
||||
codeChanged(code) {
|
||||
this.code = code;
|
||||
},
|
||||
const props = defineProps({
|
||||
loadCode: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
};
|
||||
loadLang: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["confirm", "close"]);
|
||||
|
||||
const language = ref("");
|
||||
const code = ref("");
|
||||
const options = ref([
|
||||
{
|
||||
value: "css",
|
||||
label: "css",
|
||||
},
|
||||
{
|
||||
value: "less",
|
||||
label: "less",
|
||||
},
|
||||
{
|
||||
value: "javascript",
|
||||
label: "javascript",
|
||||
},
|
||||
{
|
||||
value: "json",
|
||||
label: "json",
|
||||
},
|
||||
{
|
||||
value: "bash",
|
||||
label: "bash",
|
||||
},
|
||||
{
|
||||
value: "c",
|
||||
label: "c",
|
||||
},
|
||||
{
|
||||
value: "cil",
|
||||
label: "cil",
|
||||
},
|
||||
{
|
||||
value: "docker",
|
||||
label: "docker",
|
||||
},
|
||||
{
|
||||
value: "git",
|
||||
label: "git",
|
||||
},
|
||||
{
|
||||
value: "go",
|
||||
label: "go",
|
||||
},
|
||||
{
|
||||
value: "java",
|
||||
label: "java",
|
||||
},
|
||||
{
|
||||
value: "lua",
|
||||
label: "lua",
|
||||
},
|
||||
{
|
||||
value: "nginx",
|
||||
label: "nginx",
|
||||
},
|
||||
{
|
||||
value: "objectivec",
|
||||
label: "objectivec",
|
||||
},
|
||||
{
|
||||
value: "php",
|
||||
label: "php",
|
||||
},
|
||||
{
|
||||
value: "python",
|
||||
label: "python",
|
||||
},
|
||||
{
|
||||
value: "ruby",
|
||||
label: "ruby",
|
||||
},
|
||||
{
|
||||
value: "rust",
|
||||
label: "rust",
|
||||
},
|
||||
{
|
||||
value: "sql",
|
||||
label: "sql",
|
||||
},
|
||||
{
|
||||
value: "swift",
|
||||
label: "swift",
|
||||
},
|
||||
{
|
||||
value: "vim",
|
||||
label: "vim",
|
||||
},
|
||||
{
|
||||
value: "visual-basic",
|
||||
label: "visual-basic",
|
||||
},
|
||||
{
|
||||
value: "shell",
|
||||
label: "shell",
|
||||
},
|
||||
]);
|
||||
const isFullScreen = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.loadCode,
|
||||
(value) => {
|
||||
code.value = value;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.loadLang,
|
||||
(value) => {
|
||||
language.value = value;
|
||||
}
|
||||
);
|
||||
|
||||
// created
|
||||
code.value = props.loadCode;
|
||||
language.value = props.loadLang;
|
||||
|
||||
function submit() {
|
||||
if (!code.value) {
|
||||
ElMessage.error("代码块不能为空...");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (language.value == "") {
|
||||
ElMessage.error("请选择语言");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (code.value.length > 10000) {
|
||||
ElMessage.error("代码字数不能超过10000字!!!");
|
||||
return false;
|
||||
}
|
||||
emit("confirm", {
|
||||
language: language.value,
|
||||
code: code.value,
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
emit("close");
|
||||
}
|
||||
|
||||
function codeChanged(val) {
|
||||
code.value = val;
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
|
||||
@@ -77,48 +77,48 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ServeGetForwardRecords } from '@/api/chat'
|
||||
|
||||
export default {
|
||||
name: 'TalkForwardRecord',
|
||||
data() {
|
||||
return {
|
||||
record_id: 0,
|
||||
records: [],
|
||||
loading: false,
|
||||
isShow: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(record_id) {
|
||||
if (record_id !== this.record_id) {
|
||||
this.record_id = record_id
|
||||
this.records = []
|
||||
this.loadRecords()
|
||||
}
|
||||
defineOptions({ name: 'TalkForwardRecord' })
|
||||
|
||||
this.isShow = true
|
||||
},
|
||||
close() {
|
||||
this.isShow = false
|
||||
},
|
||||
loadRecords() {
|
||||
this.loading = true
|
||||
ServeGetForwardRecords({
|
||||
record_id: this.record_id,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
this.records = res.data.rows
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
const record_id = ref(0)
|
||||
const records = ref([])
|
||||
const loading = ref(false)
|
||||
const isShow = ref(false)
|
||||
|
||||
// 由父组件通过 ref 调用(如 ForwardMessage),必须暴露
|
||||
const open = id => {
|
||||
if (id !== record_id.value) {
|
||||
record_id.value = id
|
||||
records.value = []
|
||||
loadRecords()
|
||||
}
|
||||
|
||||
isShow.value = true
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
isShow.value = false
|
||||
}
|
||||
|
||||
const loadRecords = () => {
|
||||
loading.value = true
|
||||
ServeGetForwardRecords({
|
||||
record_id: record_id.value,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
records.value = res.data.rows
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.lum-dialog-mask {
|
||||
|
||||
@@ -211,190 +211,187 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ServeGetContacts } from "@/api/contacts";
|
||||
import { ServeFindTalkRecords } from "@/api/chat";
|
||||
import { formatSize as renderSize, download, imgZoom } from "@/utils/functions";
|
||||
import { ElNotification } from "@/utils/message";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
export default {
|
||||
name: "TalkSearchRecord",
|
||||
props: {
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
title: "",
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreen: false,
|
||||
defineOptions({ name: "TalkSearchRecord" });
|
||||
|
||||
user_id: this.$store.state.user.id,
|
||||
title: "",
|
||||
|
||||
// 侧边栏相关信息
|
||||
broadside: false,
|
||||
contacts: {
|
||||
show: "friends",
|
||||
friends: [],
|
||||
groups: [],
|
||||
},
|
||||
|
||||
query: {
|
||||
const props = defineProps({
|
||||
params: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
msg_type: 0,
|
||||
},
|
||||
|
||||
// 用户聊天记录
|
||||
records: {
|
||||
record_id: 0,
|
||||
items: [],
|
||||
isEmpty: false,
|
||||
loadStatus: 0,
|
||||
},
|
||||
|
||||
showBox: 0,
|
||||
|
||||
tabType: [
|
||||
{ name: "全部", type: 0 },
|
||||
{ name: "文件", type: 2 },
|
||||
{ name: "会话记录", type: 3 },
|
||||
{ name: "代码块", type: 4 },
|
||||
{ name: "群投票", type: 5 },
|
||||
],
|
||||
|
||||
search: {
|
||||
keyword: "", // 关键字查询
|
||||
date: "", // 时间查询
|
||||
page: 1, // 当前分页
|
||||
totalPage: 50, // 总分页
|
||||
items: [], // 数据列表
|
||||
isShowDate: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.title = this.params.title;
|
||||
this.query = {
|
||||
talk_type: this.params.talk_type,
|
||||
receiver_id: this.params.receiver_id,
|
||||
msg_type: 0,
|
||||
};
|
||||
|
||||
this.loadChatRecord(0);
|
||||
},
|
||||
created() {
|
||||
this.loadFriends();
|
||||
},
|
||||
methods: {
|
||||
download,
|
||||
renderSize,
|
||||
|
||||
// 获取图片信息
|
||||
getImgStyle(url) {
|
||||
return imgZoom(url, 200);
|
||||
},
|
||||
|
||||
// 获取会话记录消息名称
|
||||
getForwardTitle(item) {
|
||||
let arr = [...new Set(item.map((v) => v.nickname))];
|
||||
return arr.join("、") + "的会话记录";
|
||||
},
|
||||
|
||||
// 获取好友列表
|
||||
loadFriends() {
|
||||
ServeGetContacts().then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
this.contacts.friends = data.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
type: 1,
|
||||
avatar: item.avatar,
|
||||
name: item.friend_remark ? item.friend_remark : item.nickname,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 左侧联系人菜单点击事件
|
||||
triggerMenuItem(item) {
|
||||
this.title = item.name;
|
||||
this.query.talk_type = item.type;
|
||||
this.query.receiver_id = item.id;
|
||||
this.showBox = 0;
|
||||
|
||||
this.triggerLoadType(0);
|
||||
},
|
||||
|
||||
// 加载历史记录
|
||||
loadChatRecord() {
|
||||
let data = {
|
||||
talk_type: this.query.talk_type,
|
||||
receiver_id: this.query.receiver_id,
|
||||
record_id: this.records.record_id,
|
||||
msg_type: this.query.msg_type,
|
||||
title: "",
|
||||
};
|
||||
|
||||
if (this.records.loadStatus == 1) return;
|
||||
|
||||
this.records.loadStatus = 1;
|
||||
ServeFindTalkRecords(data)
|
||||
.then((res) => {
|
||||
if (res.code != 200) return;
|
||||
|
||||
let records = data.record_id == 0 ? [] : this.records.items;
|
||||
|
||||
records.push(...res.data.rows);
|
||||
|
||||
this.records.items = records;
|
||||
this.records.loadStatus =
|
||||
res.data.rows.length < res.data.limit ? 2 : 0;
|
||||
|
||||
if (this.records.items.length == 0) {
|
||||
this.records.isEmpty = true;
|
||||
} else {
|
||||
this.records.record_id =
|
||||
this.records.items[this.records.items.length - 1].id;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.records.loadStatus = 0;
|
||||
});
|
||||
},
|
||||
|
||||
triggerLoadType(type) {
|
||||
this.records.record_id = 0;
|
||||
this.query.msg_type = type;
|
||||
this.records.isEmpty = false;
|
||||
this.records.items = [];
|
||||
|
||||
this.loadChatRecord();
|
||||
},
|
||||
|
||||
searchText() {
|
||||
if (this.search.keyword == "") {
|
||||
this.showBox = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.$notify.info({
|
||||
title: "消息",
|
||||
message: "查询功能正在开发中...",
|
||||
});
|
||||
},
|
||||
|
||||
triggerBroadside() {
|
||||
this.broadside = !this.broadside;
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const fullscreen = ref(false);
|
||||
|
||||
const user_id = ref(userStore.id);
|
||||
const title = ref("");
|
||||
|
||||
// 侧边栏相关信息
|
||||
const broadside = ref(false);
|
||||
const contacts = reactive({
|
||||
show: "friends",
|
||||
friends: [],
|
||||
groups: [],
|
||||
});
|
||||
|
||||
const query = ref({
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
msg_type: 0,
|
||||
});
|
||||
|
||||
// 用户聊天记录
|
||||
const records = reactive({
|
||||
record_id: 0,
|
||||
items: [],
|
||||
isEmpty: false,
|
||||
loadStatus: 0,
|
||||
});
|
||||
|
||||
const showBox = ref(0);
|
||||
|
||||
const tabType = ref([
|
||||
{ name: "全部", type: 0 },
|
||||
{ name: "文件", type: 2 },
|
||||
{ name: "会话记录", type: 3 },
|
||||
{ name: "代码块", type: 4 },
|
||||
{ name: "群投票", type: 5 },
|
||||
]);
|
||||
|
||||
const search = reactive({
|
||||
keyword: "", // 关键字查询
|
||||
date: "", // 时间查询
|
||||
page: 1, // 当前分页
|
||||
totalPage: 50, // 总分页
|
||||
items: [], // 数据列表
|
||||
isShowDate: false,
|
||||
});
|
||||
|
||||
// 获取图片信息
|
||||
function getImgStyle(url) {
|
||||
return imgZoom(url, 200);
|
||||
}
|
||||
|
||||
// 获取会话记录消息名称
|
||||
function getForwardTitle(item) {
|
||||
let arr = [...new Set(item.map((v) => v.nickname))];
|
||||
return arr.join("、") + "的会话记录";
|
||||
}
|
||||
|
||||
// 获取好友列表
|
||||
function loadFriends() {
|
||||
ServeGetContacts().then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
contacts.friends = data.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
type: 1,
|
||||
avatar: item.avatar,
|
||||
name: item.friend_remark ? item.friend_remark : item.nickname,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 左侧联系人菜单点击事件
|
||||
function triggerMenuItem(item) {
|
||||
title.value = item.name;
|
||||
query.value.talk_type = item.type;
|
||||
query.value.receiver_id = item.id;
|
||||
showBox.value = 0;
|
||||
|
||||
triggerLoadType(0);
|
||||
}
|
||||
|
||||
// 加载历史记录
|
||||
function loadChatRecord() {
|
||||
let data = {
|
||||
talk_type: query.value.talk_type,
|
||||
receiver_id: query.value.receiver_id,
|
||||
record_id: records.record_id,
|
||||
msg_type: query.value.msg_type,
|
||||
};
|
||||
|
||||
if (records.loadStatus == 1) return;
|
||||
|
||||
records.loadStatus = 1;
|
||||
ServeFindTalkRecords(data)
|
||||
.then((res) => {
|
||||
if (res.code != 200) return;
|
||||
|
||||
let items = data.record_id == 0 ? [] : records.items;
|
||||
|
||||
items.push(...res.data.rows);
|
||||
|
||||
records.items = items;
|
||||
records.loadStatus = res.data.rows.length < res.data.limit ? 2 : 0;
|
||||
|
||||
if (records.items.length == 0) {
|
||||
records.isEmpty = true;
|
||||
} else {
|
||||
records.record_id = records.items[records.items.length - 1].id;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
records.loadStatus = 0;
|
||||
});
|
||||
}
|
||||
|
||||
function triggerLoadType(type) {
|
||||
records.record_id = 0;
|
||||
query.value.msg_type = type;
|
||||
records.isEmpty = false;
|
||||
records.items = [];
|
||||
|
||||
loadChatRecord();
|
||||
}
|
||||
|
||||
function searchText() {
|
||||
if (search.keyword == "") {
|
||||
showBox.value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
ElNotification.info({
|
||||
title: "消息",
|
||||
message: "查询功能正在开发中...",
|
||||
});
|
||||
}
|
||||
|
||||
function triggerBroadside() {
|
||||
broadside.value = !broadside.value;
|
||||
}
|
||||
|
||||
loadFriends();
|
||||
|
||||
onMounted(() => {
|
||||
title.value = props.params.title;
|
||||
query.value = {
|
||||
talk_type: props.params.talk_type,
|
||||
receiver_id: props.params.receiver_id,
|
||||
msg_type: 0,
|
||||
};
|
||||
|
||||
loadChatRecord(0);
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
:deep(.el-scrollbar__wrap ) {
|
||||
|
||||
@@ -27,7 +27,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
defineOptions({ name: 'AudioMessage' });
|
||||
|
||||
defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
function formatSeconds(value) {
|
||||
var theTime = parseInt(value) // 秒
|
||||
var theTime1 = 0 // 分
|
||||
@@ -59,64 +70,47 @@ function formatSeconds(value) {
|
||||
return result
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'AudioMessage',
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
isPlay: false,
|
||||
duration: 0,
|
||||
currentTime: 0,
|
||||
progress: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getTotalDuration() {
|
||||
return formatSeconds(this.duration)
|
||||
},
|
||||
getCurrDuration() {
|
||||
return formatSeconds(this.currentTime)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toPlay() {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
const loading = ref(true)
|
||||
const isPlay = ref(false)
|
||||
const duration = ref(0)
|
||||
const currentTime = ref(0)
|
||||
const progress = ref(0)
|
||||
|
||||
let audio = this.$refs.audio
|
||||
if (this.isPlay) {
|
||||
audio.pause()
|
||||
} else {
|
||||
audio.play()
|
||||
}
|
||||
this.isPlay = !this.isPlay
|
||||
},
|
||||
const audio = ref(null)
|
||||
|
||||
// 当目前的播放位置已更改时
|
||||
timeupdate() {
|
||||
let audio = this.$refs.audio
|
||||
this.currentTime = audio.currentTime
|
||||
this.progress = (audio.currentTime / audio.duration) * 100
|
||||
},
|
||||
const getTotalDuration = computed(() => formatSeconds(duration.value))
|
||||
const getCurrDuration = computed(() => formatSeconds(currentTime.value))
|
||||
|
||||
// 当浏览器可以播放音频/视频时
|
||||
canplay() {
|
||||
this.duration = this.$refs.audio.duration
|
||||
this.loading = false
|
||||
},
|
||||
function toPlay() {
|
||||
if (loading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// 当目前的播放列表已结束时
|
||||
ended() {
|
||||
this.isPlay = false
|
||||
},
|
||||
},
|
||||
let audioEl = audio.value
|
||||
if (isPlay.value) {
|
||||
audioEl.pause()
|
||||
} else {
|
||||
audioEl.play()
|
||||
}
|
||||
isPlay.value = !isPlay.value
|
||||
}
|
||||
|
||||
// 当目前的播放位置已更改时
|
||||
function timeupdate() {
|
||||
let audioEl = audio.value
|
||||
currentTime.value = audioEl.currentTime
|
||||
progress.value = (audioEl.currentTime / audioEl.duration) * 100
|
||||
}
|
||||
|
||||
// 当浏览器可以播放音频/视频时
|
||||
function canplay() {
|
||||
duration.value = audio.value.duration
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 当目前的播放列表已结束时
|
||||
function ended() {
|
||||
isPlay.value = false
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -20,44 +20,40 @@
|
||||
<pre class="lum-scrollbar" v-html="formatCode(code, lang)" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import Prism from 'prismjs'
|
||||
import 'prismjs/themes/prism-okaidia.css'
|
||||
|
||||
export default {
|
||||
name: 'CodeMessage',
|
||||
props: {
|
||||
code: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
lang: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
maxwidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
defineOptions({ name: 'CodeMessage' })
|
||||
|
||||
const props = defineProps({
|
||||
code: {
|
||||
type: [String, Number],
|
||||
default: '',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fullscreen: false,
|
||||
lineNumber: 0,
|
||||
}
|
||||
lang: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
created() {
|
||||
this.lineNumber = this.code.split(/\n/).length
|
||||
},
|
||||
methods: {
|
||||
formatCode(code, lang) {
|
||||
try {
|
||||
return Prism.highlight(code, Prism.languages[lang], lang) + '<br/>'
|
||||
} catch (error) {
|
||||
return code
|
||||
}
|
||||
},
|
||||
maxwidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const fullscreen = ref(false)
|
||||
const lineNumber = ref(0)
|
||||
|
||||
// created
|
||||
lineNumber.value = props.code.split(/\n/).length
|
||||
|
||||
function formatCode(code, lang) {
|
||||
try {
|
||||
return Prism.highlight(code, Prism.languages[lang], lang) + '<br/>'
|
||||
} catch (error) {
|
||||
return code
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -16,39 +16,36 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { formatSize, download } from '@/utils/functions'
|
||||
export default {
|
||||
name: 'FileMessage',
|
||||
props: {
|
||||
file: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
|
||||
defineOptions({ name: 'FileMessage' })
|
||||
|
||||
const props = defineProps({
|
||||
file: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
file_id: 0,
|
||||
ext: '',
|
||||
fileName: '',
|
||||
fileSize: '',
|
||||
}
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
created() {
|
||||
this.file_id = this.file.id
|
||||
this.ext = this.file.file_suffix.toUpperCase()
|
||||
this.fileName = this.file.original_name
|
||||
this.fileSize = formatSize(this.file.file_size)
|
||||
},
|
||||
methods: {
|
||||
download,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const file_id = ref(0)
|
||||
const ext = ref('')
|
||||
const fileName = ref('')
|
||||
const fileSize = ref('')
|
||||
|
||||
// 原 created 钩子
|
||||
file_id.value = props.file.id
|
||||
ext.value = props.file.file_suffix.toUpperCase()
|
||||
fileName.value = props.file.original_name
|
||||
fileSize.value = formatSize(props.file.file_size)
|
||||
|
||||
// download 直接从 @/utils/functions 导入,模板中照用
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.file-message {
|
||||
|
||||
@@ -17,48 +17,44 @@
|
||||
<talk-forward-record ref="forwardRecordsRef" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import TalkForwardRecord from '@/components/chat/TalkForwardRecord'
|
||||
export default {
|
||||
name: 'ForwardMessage',
|
||||
components: {
|
||||
TalkForwardRecord,
|
||||
},
|
||||
props: {
|
||||
forward: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
records: [],
|
||||
num: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
catForwardRecords() {
|
||||
this.$refs.forwardRecordsRef.open(this.record_id)
|
||||
},
|
||||
getForwardTitle(list) {
|
||||
let arr = [...new Set(list.map(v => v.nickname))]
|
||||
return arr.join('、') + '的会话记录'
|
||||
},
|
||||
},
|
||||
created() {
|
||||
let forward = this.forward
|
||||
|
||||
this.num = forward.num
|
||||
this.records = forward.list
|
||||
this.title = this.getForwardTitle(this.records)
|
||||
defineOptions({ name: 'ForwardMessage' })
|
||||
|
||||
const props = defineProps({
|
||||
forward: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
})
|
||||
|
||||
const forwardRecordsRef = ref(null)
|
||||
|
||||
const title = ref('')
|
||||
const records = ref([])
|
||||
const num = ref(0)
|
||||
|
||||
function catForwardRecords() {
|
||||
forwardRecordsRef.value.open(props.record_id)
|
||||
}
|
||||
|
||||
function getForwardTitle(list) {
|
||||
let arr = [...new Set(list.map(v => v.nickname))]
|
||||
return arr.join('、') + '的会话记录'
|
||||
}
|
||||
|
||||
let forward = props.forward
|
||||
|
||||
num.value = forward.num
|
||||
records.value = forward.list
|
||||
title.value = getForwardTitle(records.value)
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
/* 会话记录消息 */
|
||||
|
||||
@@ -18,33 +18,30 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FriendApplyMessage',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
avatar:
|
||||
'http://im-img.gzydong.club/media/images/avatar/20210602/60b6f03598ed0104301.png',
|
||||
nickname: '独特态度',
|
||||
datetime: '05/09 12:13 分',
|
||||
remarks: '编辑个签,展示我的独特态度 展示我的独特态度。',
|
||||
apply_id: 0,
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
handle(type) {
|
||||
alert(type)
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineOptions({ name: 'FriendApplyMessage' })
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const avatar = ref(
|
||||
'http://im-img.gzydong.club/media/images/avatar/20210602/60b6f03598ed0104301.png'
|
||||
)
|
||||
const nickname = ref('独特态度')
|
||||
const datetime = ref('05/09 12:13 分')
|
||||
const remarks = ref('编辑个签,展示我的独特态度 展示我的独特态度。')
|
||||
const apply_id = ref(0)
|
||||
|
||||
function handle(type) {
|
||||
alert(type)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -16,21 +16,20 @@
|
||||
</el-image>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { imgZoom } from '@/utils/functions'
|
||||
export default {
|
||||
name: 'ImageMessage',
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getImgStyle(url) {
|
||||
return imgZoom(url, 200)
|
||||
},
|
||||
|
||||
defineOptions({ name: 'ImageMessage' })
|
||||
|
||||
defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
function getImgStyle(url) {
|
||||
return imgZoom(url, 200)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -20,20 +20,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'InviteMessage',
|
||||
props: {
|
||||
invite: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toUser(user_id) {
|
||||
this.$emit('cat', user_id)
|
||||
},
|
||||
<script setup>
|
||||
defineOptions({ name: 'InviteMessage' })
|
||||
|
||||
defineProps({
|
||||
invite: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['cat'])
|
||||
|
||||
function toUser(user_id) {
|
||||
emit('cat', user_id)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -10,76 +10,72 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { parseTime } from '@/utils/functions'
|
||||
|
||||
export default {
|
||||
name: 'LoginMessage',
|
||||
props: {
|
||||
detail: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
datetime: '',
|
||||
ip: '',
|
||||
address: '',
|
||||
platform: '',
|
||||
reason: '常用设备登录',
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.ip = this.detail.ip
|
||||
this.datetime = parseTime(
|
||||
this.detail.created_at,
|
||||
'{y}年{m}月{d}日 {h}:{i}:{s}'
|
||||
)
|
||||
this.address = this.detail.address
|
||||
this.reason = this.detail.reason
|
||||
defineOptions({ name: 'LoginMessage' })
|
||||
|
||||
this.platform =
|
||||
this.getExploreName(this.detail.agent) +
|
||||
' / ' +
|
||||
this.getExploreOs(this.detail.agent)
|
||||
const props = defineProps({
|
||||
detail: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
methods: {
|
||||
getExploreName(userAgent = '') {
|
||||
if (userAgent.indexOf('Opera') > -1 || userAgent.indexOf('OPR') > -1) {
|
||||
return 'Opera'
|
||||
} else if (
|
||||
userAgent.indexOf('compatible') > -1 &&
|
||||
userAgent.indexOf('MSIE') > -1
|
||||
) {
|
||||
return 'IE'
|
||||
} else if (userAgent.indexOf('Edge') > -1) {
|
||||
return 'Edge'
|
||||
} else if (userAgent.indexOf('Firefox') > -1) {
|
||||
return 'Firefox'
|
||||
} else if (
|
||||
userAgent.indexOf('Safari') > -1 &&
|
||||
userAgent.indexOf('Chrome') == -1
|
||||
) {
|
||||
return 'Safari'
|
||||
} else if (
|
||||
userAgent.indexOf('Chrome') > -1 &&
|
||||
userAgent.indexOf('Safari') > -1
|
||||
) {
|
||||
return 'Chrome'
|
||||
} else {
|
||||
return 'Unkonwn'
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
getExploreOs(userAgent = '') {
|
||||
if (userAgent.indexOf('Mac OS') > -1) {
|
||||
return 'Mac OS'
|
||||
} else {
|
||||
return 'Windows'
|
||||
}
|
||||
},
|
||||
},
|
||||
const datetime = ref('')
|
||||
const ip = ref('')
|
||||
const address = ref('')
|
||||
const platform = ref('')
|
||||
const reason = ref('常用设备登录')
|
||||
|
||||
// 原 created 生命周期逻辑,setup 顶层直接执行
|
||||
ip.value = props.detail.ip
|
||||
datetime.value = parseTime(
|
||||
props.detail.created_at,
|
||||
'{y}年{m}月{d}日 {h}:{i}:{s}'
|
||||
)
|
||||
address.value = props.detail.address
|
||||
reason.value = props.detail.reason
|
||||
|
||||
platform.value =
|
||||
getExploreName(props.detail.agent) +
|
||||
' / ' +
|
||||
getExploreOs(props.detail.agent)
|
||||
|
||||
function getExploreName(userAgent = '') {
|
||||
if (userAgent.indexOf('Opera') > -1 || userAgent.indexOf('OPR') > -1) {
|
||||
return 'Opera'
|
||||
} else if (
|
||||
userAgent.indexOf('compatible') > -1 &&
|
||||
userAgent.indexOf('MSIE') > -1
|
||||
) {
|
||||
return 'IE'
|
||||
} else if (userAgent.indexOf('Edge') > -1) {
|
||||
return 'Edge'
|
||||
} else if (userAgent.indexOf('Firefox') > -1) {
|
||||
return 'Firefox'
|
||||
} else if (
|
||||
userAgent.indexOf('Safari') > -1 &&
|
||||
userAgent.indexOf('Chrome') == -1
|
||||
) {
|
||||
return 'Safari'
|
||||
} else if (
|
||||
userAgent.indexOf('Chrome') > -1 &&
|
||||
userAgent.indexOf('Safari') > -1
|
||||
) {
|
||||
return 'Chrome'
|
||||
} else {
|
||||
return 'Unkonwn'
|
||||
}
|
||||
}
|
||||
|
||||
function getExploreOs(userAgent = '') {
|
||||
if (userAgent.indexOf('Mac OS') > -1) {
|
||||
return 'Mac OS'
|
||||
} else {
|
||||
return 'Windows'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -2,15 +2,10 @@
|
||||
<div class="reply-message">这是回复的消息[预留]</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script setup>
|
||||
defineOptions({
|
||||
name: 'ReplyMessage',
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
created() {},
|
||||
methods: {},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.reply-message {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="revoke-message">
|
||||
<div class="content">
|
||||
<span v-if="$store.state.user.id == item.user_id">
|
||||
<span v-if="userStore.id == item.user_id">
|
||||
你撤回了一条消息 | {{ sendTime(item.created_at) }}
|
||||
</span>
|
||||
<span v-else-if="item.talk_type == 1">
|
||||
@@ -13,20 +13,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { formatTime as sendTime } from "@/utils/functions";
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: "RevokeMessage",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
});
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
methods: {
|
||||
sendTime,
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.revoke-message {
|
||||
|
||||
@@ -3,18 +3,14 @@
|
||||
<div class="content">{{ content }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { formatTime as sendTime } from '@/utils/functions'
|
||||
|
||||
export default {
|
||||
name: 'SystemTextMessage',
|
||||
props: {
|
||||
content: String,
|
||||
},
|
||||
methods: {
|
||||
sendTime,
|
||||
},
|
||||
}
|
||||
defineOptions({ name: 'SystemTextMessage' })
|
||||
|
||||
defineProps({
|
||||
content: String,
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.system-text-message {
|
||||
|
||||
@@ -8,44 +8,42 @@
|
||||
<pre v-html="html" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { textReplaceLink } from "@/utils/functions";
|
||||
import { textReplaceEmoji } from "@/utils/emojis";
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: "TextMessage",
|
||||
props: {
|
||||
content: {
|
||||
type: [String, Number],
|
||||
default: "",
|
||||
},
|
||||
float: {
|
||||
type: String,
|
||||
default: "left",
|
||||
},
|
||||
fullWidth: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
html: "",
|
||||
};
|
||||
},
|
||||
created () {
|
||||
const text = textReplaceLink(
|
||||
this.content,
|
||||
this.float == "right" ? "#ffffff" : "rgb(9 149 208)"
|
||||
);
|
||||
});
|
||||
|
||||
this.html = textReplaceEmoji(text);
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: [String, Number],
|
||||
default: "",
|
||||
},
|
||||
};
|
||||
float: {
|
||||
type: String,
|
||||
default: "left",
|
||||
},
|
||||
fullWidth: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const html = ref("");
|
||||
|
||||
const text = textReplaceLink(
|
||||
props.content,
|
||||
props.float == "right" ? "#ffffff" : "rgb(9 149 208)"
|
||||
);
|
||||
|
||||
html.value = textReplaceEmoji(text);
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@bg-left-color: #f5f5f5;
|
||||
|
||||
@@ -2,18 +2,7 @@
|
||||
<!-- 用户卡片消息 - 预留 -->
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UserCardMessage',
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
methods: {},
|
||||
created() {},
|
||||
}
|
||||
<script setup>
|
||||
defineOptions({ name: 'UserCardMessage' })
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -4,15 +4,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'VideoMessage',
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {},
|
||||
created() {},
|
||||
}
|
||||
<script setup>
|
||||
defineOptions({ name: 'VideoMessage' })
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -20,27 +20,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'VisitCardMessage',
|
||||
data() {
|
||||
return {
|
||||
userId: 0,
|
||||
friendId: 0,
|
||||
avatar:
|
||||
'http://im-serve0.gzydong.club/static/image/sys-head/2019012107542668696.jpg',
|
||||
sign:
|
||||
'这个社会,是赢家通吃,输者一无所有,社会,永远都是只以成败论英雄。',
|
||||
nickname:
|
||||
'氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳',
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
openVisitCard(user_id) {
|
||||
this.$emit('openVisitCard', user_id)
|
||||
},
|
||||
},
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
defineOptions({ name: 'VisitCardMessage' });
|
||||
|
||||
const emit = defineEmits(['openVisitCard']);
|
||||
|
||||
const userId = ref(0);
|
||||
const friendId = ref(0);
|
||||
const avatar = ref(
|
||||
'http://im-serve0.gzydong.club/static/image/sys-head/2019012107542668696.jpg'
|
||||
);
|
||||
const sign = ref(
|
||||
'这个社会,是赢家通吃,输者一无所有,社会,永远都是只以成败论英雄。'
|
||||
);
|
||||
const nickname = ref(
|
||||
'氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳氨基酸纳'
|
||||
);
|
||||
|
||||
function openVisitCard(user_id) {
|
||||
emit('openVisitCard', user_id)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -2,15 +2,9 @@
|
||||
<div class="voice-message"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script setup>
|
||||
defineOptions({
|
||||
name: 'VoiceMessage',
|
||||
components: {},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {},
|
||||
created() {},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -59,127 +59,128 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { ServeConfirmVoteHandle } from "@/api/chat";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
export default {
|
||||
name: "VoteMessage",
|
||||
props: {
|
||||
vote: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
answer_mode: 0,
|
||||
title: "啊谁叫你打开你卡沙发那,那就是看、卡收纳是你",
|
||||
radio_value: "",
|
||||
options: [],
|
||||
is_vote: false,
|
||||
answer_num: 0,
|
||||
answered_num: 0,
|
||||
refresh: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isUserVote() {
|
||||
return this.options.some((iten) => {
|
||||
return iten.is_checked;
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
let user_id = this.$store.state.user.id;
|
||||
let { detail, statistics, vote_users } = this.vote;
|
||||
defineOptions({ name: "VoteMessage" });
|
||||
|
||||
this.answer_mode = detail.answer_mode;
|
||||
this.answer_num = detail.answer_num;
|
||||
this.answered_num = detail.answered_num;
|
||||
const props = defineProps({
|
||||
vote: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
record_id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
detail.answer_option.forEach((item) => {
|
||||
this.options.push({
|
||||
value: item.key,
|
||||
text: item.value,
|
||||
is_checked: false,
|
||||
num: 0,
|
||||
progress: "00.0",
|
||||
});
|
||||
const userStore = useUserStore();
|
||||
|
||||
const answer_mode = ref(0);
|
||||
const title = ref("啊谁叫你打开你卡沙发那,那就是看、卡收纳是你");
|
||||
const radio_value = ref("");
|
||||
const options = ref([]);
|
||||
const is_vote = ref(false);
|
||||
const answer_num = ref(0);
|
||||
const answered_num = ref(0);
|
||||
const refresh = ref(false);
|
||||
|
||||
const isUserVote = computed(() => {
|
||||
return options.value.some((iten) => {
|
||||
return iten.is_checked;
|
||||
});
|
||||
});
|
||||
|
||||
function loadRefresh() {
|
||||
refresh.value = true;
|
||||
|
||||
setTimeout(() => {
|
||||
refresh.value = false;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function updateStatistics(data) {
|
||||
let count = data.count;
|
||||
options.value.forEach((option) => {
|
||||
option.num = data.options[option.value];
|
||||
|
||||
if (count > 0) {
|
||||
option.progress = (data.options[option.value] / count) * 100;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toSelect(option, index) {
|
||||
if (answer_mode.value == 0) {
|
||||
options.value.forEach((option) => {
|
||||
option.is_checked = false;
|
||||
});
|
||||
}
|
||||
|
||||
this.is_vote = vote_users.some((value) => {
|
||||
return value == user_id;
|
||||
options.value[index].is_checked = !option.is_checked;
|
||||
}
|
||||
|
||||
function toSelect2(option) {
|
||||
if (answer_mode.value == 0) {
|
||||
options.value.forEach((item) => {
|
||||
if (option.value == item.value) {
|
||||
item.is_checked = option.is_checked;
|
||||
} else {
|
||||
item.is_checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.updateStatistics(statistics);
|
||||
},
|
||||
methods: {
|
||||
loadRefresh() {
|
||||
this.refresh = true;
|
||||
function toVote() {
|
||||
if (isUserVote.value == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.refresh = false;
|
||||
}, 500);
|
||||
},
|
||||
updateStatistics(data) {
|
||||
let count = data.count;
|
||||
this.options.forEach((option) => {
|
||||
option.num = data.options[option.value];
|
||||
let items = [];
|
||||
options.value.forEach((item) => {
|
||||
if (item.is_checked) {
|
||||
items.push(item.value);
|
||||
}
|
||||
});
|
||||
|
||||
if (count > 0) {
|
||||
option.progress = (data.options[option.value] / count) * 100;
|
||||
}
|
||||
});
|
||||
},
|
||||
ServeConfirmVoteHandle({
|
||||
record_id: props.record_id,
|
||||
options: items.join(","),
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
is_vote.value = true;
|
||||
updateStatistics(res.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toSelect(option, index) {
|
||||
if (this.answer_mode == 0) {
|
||||
this.options.forEach((option) => {
|
||||
option.is_checked = false;
|
||||
});
|
||||
}
|
||||
// 原 created() 生命周期逻辑
|
||||
let user_id = userStore.id;
|
||||
let { detail, statistics, vote_users } = props.vote;
|
||||
|
||||
this.options[index].is_checked = !option.is_checked;
|
||||
},
|
||||
toSelect2(option) {
|
||||
if (this.answer_mode == 0) {
|
||||
this.options.forEach((item) => {
|
||||
if (option.value == item.value) {
|
||||
item.is_checked = option.is_checked;
|
||||
} else {
|
||||
item.is_checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
toVote() {
|
||||
if (this.isUserVote == false) {
|
||||
return false;
|
||||
}
|
||||
answer_mode.value = detail.answer_mode;
|
||||
answer_num.value = detail.answer_num;
|
||||
answered_num.value = detail.answered_num;
|
||||
|
||||
let items = [];
|
||||
this.options.forEach((item) => {
|
||||
if (item.is_checked) {
|
||||
items.push(item.value);
|
||||
}
|
||||
});
|
||||
detail.answer_option.forEach((item) => {
|
||||
options.value.push({
|
||||
value: item.key,
|
||||
text: item.value,
|
||||
is_checked: false,
|
||||
num: 0,
|
||||
progress: "00.0",
|
||||
});
|
||||
});
|
||||
|
||||
ServeConfirmVoteHandle({
|
||||
record_id: this.record_id,
|
||||
options: items.join(","),
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.is_vote = true;
|
||||
this.updateStatistics(res.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
is_vote.value = vote_users.some((value) => {
|
||||
return value == user_id;
|
||||
});
|
||||
|
||||
updateStatistics(statistics);
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.vote-message {
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import {
|
||||
ServeGetStoreDetail,
|
||||
ServeGetFootPrint,
|
||||
@@ -29,255 +31,258 @@ import StoreDetail from "@/components/chat/panel/template/storeDetail.vue";
|
||||
import FootPrint from "@/components/chat/panel/template/footPrint.vue";
|
||||
import GoodsLink from "@/components/chat/panel/template/goodsLink.vue";
|
||||
import SocketInstance from "@/im-server/socket-instance";
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { isBuyerImMode } from "@/utils/im-mode";
|
||||
// 与 computed 属性同名,改用别名导入
|
||||
import { isBuyerImMode as isBuyerImModeFn } from "@/utils/im-mode";
|
||||
|
||||
const SIDE_REQUEST_OPTIONS = { skipAuthDialog: true };
|
||||
|
||||
export default {
|
||||
components: {
|
||||
StoreDetail,
|
||||
FootPrint,
|
||||
GoodsLink,
|
||||
const props = defineProps({
|
||||
toUser: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
props: {
|
||||
toUser: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
goodsParams: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["talkItems"]),
|
||||
...mapState({
|
||||
index_name: (state) => state.dialogue.index_name,
|
||||
}),
|
||||
isBuyerImMode() {
|
||||
return isBuyerImMode(this.$route);
|
||||
},
|
||||
goodsParams: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
watch: {
|
||||
toUser() {
|
||||
this.syncStoreFlagCache();
|
||||
this.resetSidePanelData();
|
||||
if (this.toUser.storeFlag) {
|
||||
this.getStoreDetail();
|
||||
}
|
||||
this.getFootPrint();
|
||||
if (this.goodsParams && this.toUser.storeFlag) {
|
||||
this.getGoodsDetail();
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "history",
|
||||
storeInfo: {},
|
||||
memberInfo: {},
|
||||
footPrintParams: {
|
||||
pageSize: 20,
|
||||
pageNumber: 1,
|
||||
memberId: "",
|
||||
storeId: "",
|
||||
},
|
||||
goodsDetail: {},
|
||||
footPrintList: [],
|
||||
orderPrintList: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.syncStoreFlagCache();
|
||||
if (this.toUser.storeFlag) {
|
||||
this.getStoreDetail();
|
||||
});
|
||||
|
||||
const talkStore = useTalkStore();
|
||||
const dialogueStore = useDialogueStore();
|
||||
const route = useRoute();
|
||||
|
||||
const activeName = ref("history");
|
||||
const storeInfo = ref({});
|
||||
const memberInfo = ref({});
|
||||
const footPrintParams = reactive({
|
||||
pageSize: 20,
|
||||
pageNumber: 1,
|
||||
memberId: "",
|
||||
storeId: "",
|
||||
});
|
||||
const goodsDetail = ref({});
|
||||
const footPrintList = ref([]);
|
||||
const orderPrintList = ref([]);
|
||||
|
||||
const talkItems = computed(() => talkStore.talkItems);
|
||||
const index_name = computed(() => dialogueStore.index_name);
|
||||
const isBuyerImMode = computed(() => isBuyerImModeFn(route));
|
||||
|
||||
watch(
|
||||
() => props.toUser,
|
||||
() => {
|
||||
syncStoreFlagCache();
|
||||
resetSidePanelData();
|
||||
if (props.toUser.storeFlag) {
|
||||
getStoreDetail();
|
||||
}
|
||||
this.getFootPrint();
|
||||
if (this.goodsParams && this.toUser.storeFlag) {
|
||||
this.getGoodsDetail();
|
||||
getFootPrint();
|
||||
if (props.goodsParams && props.toUser.storeFlag) {
|
||||
getGoodsDetail();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
syncStoreFlagCache() {
|
||||
localStorage.setItem(
|
||||
"storeFlag",
|
||||
this.isBuyerImMode ? "true" : "false"
|
||||
);
|
||||
},
|
||||
resetSidePanelData() {
|
||||
this.footPrintList = [];
|
||||
this.orderPrintList = [];
|
||||
this.footPrintParams.pageNumber = 1;
|
||||
},
|
||||
getStoreDetail() {
|
||||
ServeGetStoreDetail(this.toUser.userId, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.storeInfo = res.result;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
loadMoreFootPrint() {
|
||||
this.footPrintParams.pageNumber++;
|
||||
this.getFootPrint();
|
||||
},
|
||||
handleClick() {},
|
||||
getGoodsDetail() {
|
||||
if (!this.toUser.storeFlag) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
syncStoreFlagCache();
|
||||
if (props.toUser.storeFlag) {
|
||||
getStoreDetail();
|
||||
}
|
||||
getFootPrint();
|
||||
if (props.goodsParams && props.toUser.storeFlag) {
|
||||
getGoodsDetail();
|
||||
}
|
||||
});
|
||||
|
||||
function syncStoreFlagCache() {
|
||||
localStorage.setItem(
|
||||
"storeFlag",
|
||||
isBuyerImMode.value ? "true" : "false"
|
||||
);
|
||||
}
|
||||
|
||||
function resetSidePanelData() {
|
||||
footPrintList.value = [];
|
||||
orderPrintList.value = [];
|
||||
footPrintParams.pageNumber = 1;
|
||||
}
|
||||
|
||||
function getStoreDetail() {
|
||||
ServeGetStoreDetail(props.toUser.userId, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
storeInfo.value = res.result;
|
||||
}
|
||||
if (!this.goodsParams || !this.goodsParams.goodsId) {
|
||||
return;
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function loadMoreFootPrint() {
|
||||
footPrintParams.pageNumber++;
|
||||
getFootPrint();
|
||||
}
|
||||
|
||||
function handleClick() {}
|
||||
|
||||
function getGoodsDetail() {
|
||||
if (!props.toUser.storeFlag) {
|
||||
return;
|
||||
}
|
||||
if (!props.goodsParams || !props.goodsParams.goodsId) {
|
||||
return;
|
||||
}
|
||||
ServeGetGoodsDetail(props.goodsParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
goodsDetail.value = res.result.data;
|
||||
}
|
||||
ServeGetGoodsDetail(this.goodsParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res.success) {
|
||||
this.goodsDetail = res.result.data;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
normalizeFootPrintRecords(records = []) {
|
||||
const goodsId = this.goodsParams?.goodsId;
|
||||
return records
|
||||
.filter((item) => item != null)
|
||||
.filter((item) => !goodsId || item.goodsId !== goodsId)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
btnHide: localStorage.getItem(item.goodsId) ? 0 : 1,
|
||||
}));
|
||||
},
|
||||
normalizeOrderRecords(records = []) {
|
||||
return records.map((item) => ({
|
||||
...item,
|
||||
btnHide: 1,
|
||||
}));
|
||||
},
|
||||
getFootPrint() {
|
||||
if (!getToken()) {
|
||||
return;
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
function normalizeFootPrintRecords(records = []) {
|
||||
const goodsId = props.goodsParams?.goodsId;
|
||||
return records
|
||||
.filter((item) => item != null)
|
||||
.filter((item) => !goodsId || item.goodsId !== goodsId)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
btnHide: localStorage.getItem(item.goodsId) ? 0 : 1,
|
||||
}));
|
||||
}
|
||||
|
||||
function normalizeOrderRecords(records = []) {
|
||||
return records.map((item) => ({
|
||||
...item,
|
||||
btnHide: 1,
|
||||
}));
|
||||
}
|
||||
|
||||
function getFootPrint() {
|
||||
if (!getToken()) {
|
||||
return;
|
||||
}
|
||||
if (!props.toUser?.userId || !props.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBuyerImMode.value) {
|
||||
footPrintParams.memberId = props.id;
|
||||
footPrintParams.storeId = props.toUser.userId;
|
||||
fetchBuyerSideData();
|
||||
} else {
|
||||
footPrintParams.memberId = props.toUser.userId;
|
||||
footPrintParams.storeId = props.id;
|
||||
fetchStoreSideData();
|
||||
}
|
||||
}
|
||||
|
||||
function fetchBuyerSideData() {
|
||||
ServeGetFootPrint(footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.result?.records) {
|
||||
footPrintList.value.push(
|
||||
...normalizeFootPrintRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
if (!this.toUser?.userId || !this.id) {
|
||||
return;
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
ServeGetOrderPrint(footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.code === 200 && res?.result?.records) {
|
||||
orderPrintList.value.push(
|
||||
...normalizeOrderRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
if (this.isBuyerImMode) {
|
||||
this.footPrintParams.memberId = this.id;
|
||||
this.footPrintParams.storeId = this.toUser.userId;
|
||||
this.fetchBuyerSideData();
|
||||
} else {
|
||||
this.footPrintParams.memberId = this.toUser.userId;
|
||||
this.footPrintParams.storeId = this.id;
|
||||
this.fetchStoreSideData();
|
||||
function fetchStoreSideData() {
|
||||
ServeStoreGetFootPrint(footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.result?.records) {
|
||||
footPrintList.value.push(
|
||||
...normalizeFootPrintRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
},
|
||||
fetchBuyerSideData() {
|
||||
ServeGetFootPrint(this.footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.result?.records) {
|
||||
this.footPrintList.push(
|
||||
...this.normalizeFootPrintRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
ServeGetOrderPrint(this.footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.code === 200 && res?.result?.records) {
|
||||
this.orderPrintList.push(
|
||||
...this.normalizeOrderRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
fetchStoreSideData() {
|
||||
ServeStoreGetFootPrint(this.footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.result?.records) {
|
||||
this.footPrintList.push(
|
||||
...this.normalizeFootPrintRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
ServeStoreGetOrderPrint(this.footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.code === 200 && res?.result?.records) {
|
||||
this.orderPrintList.push(
|
||||
...this.normalizeOrderRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
submitSendMessage(record, context, messageType) {
|
||||
SocketInstance.emit("event_talk", record);
|
||||
this.$store.commit("UPDATE_TALK_ITEM", {
|
||||
index_name: this.index_name,
|
||||
draft_text: "",
|
||||
});
|
||||
const insterChat = {
|
||||
createTime: this.formateDateAndTimeToString(new Date()),
|
||||
fromUser: this.id,
|
||||
toUser: record.to,
|
||||
isRead: false,
|
||||
messageType: messageType,
|
||||
text: context,
|
||||
float: "right",
|
||||
};
|
||||
|
||||
this.$store.commit("PUSH_DIALOGUE", insterChat);
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
let isBottom =
|
||||
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||
|
||||
if (isBottom || record.to == this.id) {
|
||||
this.$nextTick(() => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
} else {
|
||||
this.$store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||
content: context,
|
||||
nickname: record.name,
|
||||
});
|
||||
ServeStoreGetOrderPrint(footPrintParams, SIDE_REQUEST_OPTIONS)
|
||||
.then((res) => {
|
||||
if (res?.code === 200 && res?.result?.records) {
|
||||
orderPrintList.value.push(
|
||||
...normalizeOrderRecords(res.result.records)
|
||||
);
|
||||
}
|
||||
},
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
formateDateAndTimeToString(date) {
|
||||
var hours = date.getHours();
|
||||
var mins = date.getMinutes();
|
||||
var secs = date.getSeconds();
|
||||
var msecs = date.getMilliseconds();
|
||||
if (hours < 10) hours = "0" + hours;
|
||||
if (mins < 10) mins = "0" + mins;
|
||||
if (secs < 10) secs = "0" + secs;
|
||||
if (msecs < 10) secs = "0" + msecs;
|
||||
return (
|
||||
this.formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||
);
|
||||
},
|
||||
function submitSendMessage(record, context, messageType) {
|
||||
SocketInstance.emit("event_talk", record);
|
||||
talkStore.UPDATE_TALK_ITEM({
|
||||
index_name: index_name.value,
|
||||
draft_text: "",
|
||||
});
|
||||
const insterChat = {
|
||||
createTime: formateDateAndTimeToString(new Date()),
|
||||
fromUser: props.id,
|
||||
toUser: record.to,
|
||||
isRead: false,
|
||||
messageType: messageType,
|
||||
text: context,
|
||||
float: "right",
|
||||
};
|
||||
|
||||
formatDateToString(date) {
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
if (month < 10) month = "0" + month;
|
||||
if (day < 10) day = "0" + day;
|
||||
return year + "-" + month + "-" + day;
|
||||
},
|
||||
},
|
||||
};
|
||||
dialogueStore.PUSH_DIALOGUE(insterChat);
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
let isBottom =
|
||||
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||
|
||||
if (isBottom || record.to == props.id) {
|
||||
nextTick(() => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
} else {
|
||||
talkStore.SET_TLAK_UNREAD_MESSAGE({
|
||||
content: context,
|
||||
nickname: record.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formateDateAndTimeToString(date) {
|
||||
var hours = date.getHours();
|
||||
var mins = date.getMinutes();
|
||||
var secs = date.getSeconds();
|
||||
var msecs = date.getMilliseconds();
|
||||
if (hours < 10) hours = "0" + hours;
|
||||
if (mins < 10) mins = "0" + mins;
|
||||
if (secs < 10) secs = "0" + secs;
|
||||
if (msecs < 10) secs = "0" + msecs;
|
||||
return (
|
||||
formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||
);
|
||||
}
|
||||
|
||||
function formatDateToString(date) {
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
if (month < 10) month = "0" + month;
|
||||
if (day < 10) day = "0" + day;
|
||||
return year + "-" + month + "-" + day;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -39,75 +39,89 @@
|
||||
</div>
|
||||
</el-header>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
params: 0,
|
||||
nickname: '',
|
||||
}
|
||||
},
|
||||
},
|
||||
online: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
keyboard: {
|
||||
type: [Boolean, Number],
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
params: {
|
||||
<script setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
params: 0,
|
||||
nickname: '',
|
||||
},
|
||||
isOnline: false,
|
||||
isKeyboard: false,
|
||||
groupNum: 0,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.setParamsData(this.data)
|
||||
this.setOnlineStatus(this.online)
|
||||
},
|
||||
watch: {
|
||||
data(value) {
|
||||
this.setParamsData(value)
|
||||
},
|
||||
online(value) {
|
||||
this.setOnlineStatus(value)
|
||||
},
|
||||
keyboard(value) {
|
||||
this.isKeyboard = value
|
||||
setTimeout(() => {
|
||||
this.isKeyboard = false
|
||||
}, 2000)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setOnlineStatus(value) {
|
||||
this.isOnline = value
|
||||
},
|
||||
setParamsData(object) {
|
||||
Object.assign(this.params, object)
|
||||
},
|
||||
setGroupNum(value) {
|
||||
this.groupNum = value
|
||||
},
|
||||
triggerEvent(event_name) {
|
||||
this.$emit('event', event_name)
|
||||
},
|
||||
online: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
keyboard: {
|
||||
type: [Boolean, Number],
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['event'])
|
||||
|
||||
const params = reactive({
|
||||
talk_type: 0,
|
||||
receiver_id: 0,
|
||||
params: 0,
|
||||
nickname: '',
|
||||
})
|
||||
const isOnline = ref(false)
|
||||
const isKeyboard = ref(false)
|
||||
const groupNum = ref(0)
|
||||
|
||||
// created 钩子
|
||||
setParamsData(props.data)
|
||||
setOnlineStatus(props.online)
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(value) => {
|
||||
setParamsData(value)
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.online,
|
||||
(value) => {
|
||||
setOnlineStatus(value)
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.keyboard,
|
||||
(value) => {
|
||||
isKeyboard.value = value
|
||||
setTimeout(() => {
|
||||
isKeyboard.value = false
|
||||
}, 2000)
|
||||
}
|
||||
)
|
||||
|
||||
function setOnlineStatus(value) {
|
||||
isOnline.value = value
|
||||
}
|
||||
|
||||
function setParamsData(object) {
|
||||
Object.assign(params, object)
|
||||
}
|
||||
|
||||
function setGroupNum(value) {
|
||||
groupNum.value = value
|
||||
}
|
||||
|
||||
function triggerEvent(event_name) {
|
||||
emit('event', event_name)
|
||||
}
|
||||
|
||||
// 父组件 TalkPanel 通过 $refs.panelHeader.setGroupNum() 访问
|
||||
defineExpose({ setGroupNum })
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
#panel-header {
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
default: 0,
|
||||
},
|
||||
<script setup>
|
||||
defineProps({
|
||||
value: {
|
||||
default: 0,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
defineEmits(["event"]);
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.multi-select {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -76,116 +76,115 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
noMoreList:{
|
||||
'goods':{title:'暂无最近浏览',value:false},
|
||||
'orders':{title:'暂无订单信息',value:false},
|
||||
},
|
||||
activeName: 'goods',
|
||||
btnHide: undefined,
|
||||
hide: true,
|
||||
col: {
|
||||
CANCELLED: 'danger',
|
||||
PAID: 'danger',
|
||||
TAKE: '',
|
||||
COMPLETED: 'success',
|
||||
DELIVERED: 'danger',
|
||||
UNDELIVERED: 'warning',
|
||||
UNPAID: '',
|
||||
STAY_PICKED_UP: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["talkItems"]),
|
||||
...mapState({
|
||||
id: (state) => state.user.id,
|
||||
toUser: (state) => state.user.toUser,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
//跳转订单列表
|
||||
const talkStore = useTalkStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
scrollBottom (e) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.srcElement
|
||||
if (scrollTop + clientHeight >= scrollHeight) {
|
||||
this.$emit('loadMore')
|
||||
}
|
||||
},
|
||||
loadMore () {
|
||||
const emit = defineEmits(["loadMore", "sendMessage"]);
|
||||
|
||||
},
|
||||
// 发送消息回调事件
|
||||
submitSendGoodsMessage (item) {
|
||||
const context = {
|
||||
id: item.id,
|
||||
goodsId: item.goodsId,
|
||||
thumbnail: item.thumbnail,
|
||||
price: item.price,
|
||||
goodsName: item.goodsName
|
||||
}
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: this.toUser.userId,
|
||||
from: this.id,
|
||||
message_type: "GOODS",
|
||||
context: context,
|
||||
talk_id: this.toUser.id,
|
||||
};
|
||||
this.$emit('sendMessage', record, context, 'GOODS');
|
||||
localStorage.setItem(item.goodsId, 0)
|
||||
item.btnHide = 0
|
||||
},
|
||||
// 发送订单列表
|
||||
submitSendOrderMessage (item, index) {
|
||||
console.log(item, 'item');
|
||||
|
||||
const context = {
|
||||
sn: item.sn,
|
||||
groupImages: item.groupImages,
|
||||
paymentTime: item.paymentTime,
|
||||
groupName: item.groupName,
|
||||
flowPrice: item.flowPrice,
|
||||
orderItems:item.orderItems,
|
||||
orderStatus: item.orderStatus
|
||||
}
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: this.toUser.userId,
|
||||
from: this.id,
|
||||
message_type: "ORDER",
|
||||
context: context,
|
||||
talk_id: this.toUser.id,
|
||||
};
|
||||
this.$emit('sendMessage', record, context, 'ORDER');
|
||||
localStorage.setItem(item.goodsId, 0)
|
||||
item.btnHide = 0
|
||||
},
|
||||
handleClick (tab, event) {
|
||||
|
||||
}
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
orderList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
orderList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
mounted () {
|
||||
// state.user.toUser
|
||||
// console.log(this.orderList, ' this.$store.state.user.toUser this.$store.state.user.toUser this.$store.state.user.toUser');
|
||||
this.btnHide = localStorage.getItem('btnHide')
|
||||
});
|
||||
|
||||
const noMoreList = ref({
|
||||
'goods': { title: '暂无最近浏览', value: false },
|
||||
'orders': { title: '暂无订单信息', value: false },
|
||||
});
|
||||
const activeName = ref('goods');
|
||||
const btnHide = ref(undefined);
|
||||
const hide = ref(true);
|
||||
const col = ref({
|
||||
CANCELLED: 'danger',
|
||||
PAID: 'danger',
|
||||
TAKE: '',
|
||||
COMPLETED: 'success',
|
||||
DELIVERED: 'danger',
|
||||
UNDELIVERED: 'warning',
|
||||
UNPAID: '',
|
||||
STAY_PICKED_UP: ''
|
||||
});
|
||||
|
||||
const talkItems = computed(() => talkStore.talkItems);
|
||||
const id = computed(() => userStore.id);
|
||||
const toUser = computed(() => userStore.toUser);
|
||||
|
||||
//跳转订单列表
|
||||
|
||||
function scrollBottom (e) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.srcElement
|
||||
if (scrollTop + clientHeight >= scrollHeight) {
|
||||
emit('loadMore')
|
||||
}
|
||||
}
|
||||
function loadMore () {
|
||||
|
||||
}
|
||||
// 发送消息回调事件
|
||||
function submitSendGoodsMessage (item) {
|
||||
const context = {
|
||||
id: item.id,
|
||||
goodsId: item.goodsId,
|
||||
thumbnail: item.thumbnail,
|
||||
price: item.price,
|
||||
goodsName: item.goodsName
|
||||
}
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: toUser.value.userId,
|
||||
from: id.value,
|
||||
message_type: "GOODS",
|
||||
context: context,
|
||||
talk_id: toUser.value.id,
|
||||
};
|
||||
emit('sendMessage', record, context, 'GOODS');
|
||||
localStorage.setItem(item.goodsId, 0)
|
||||
item.btnHide = 0
|
||||
}
|
||||
// 发送订单列表
|
||||
function submitSendOrderMessage (item, index) {
|
||||
console.log(item, 'item');
|
||||
|
||||
const context = {
|
||||
sn: item.sn,
|
||||
groupImages: item.groupImages,
|
||||
paymentTime: item.paymentTime,
|
||||
groupName: item.groupName,
|
||||
flowPrice: item.flowPrice,
|
||||
orderItems:item.orderItems,
|
||||
orderStatus: item.orderStatus
|
||||
}
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: toUser.value.userId,
|
||||
from: id.value,
|
||||
message_type: "ORDER",
|
||||
context: context,
|
||||
talk_id: toUser.value.id,
|
||||
};
|
||||
emit('sendMessage', record, context, 'ORDER');
|
||||
localStorage.setItem(item.goodsId, 0)
|
||||
item.btnHide = 0
|
||||
}
|
||||
function handleClick (tab, event) {
|
||||
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// state.user.toUser
|
||||
// console.log(this.orderList, ' this.$store.state.user.toUser this.$store.state.user.toUser this.$store.state.user.toUser');
|
||||
btnHide.value = localStorage.getItem('btnHide')
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -19,125 +19,124 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
<script setup>
|
||||
import { computed, onMounted, nextTick, ref } from "vue";
|
||||
import SocketInstance from "@/im-server/socket-instance";
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
btnHide: undefined,
|
||||
hide: true
|
||||
}
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const dialogueStore = useDialogueStore();
|
||||
const talkStore = useTalkStore();
|
||||
|
||||
const props = defineProps({
|
||||
goodsDetail: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["talkItems"]),
|
||||
...mapState({
|
||||
id: (state) => state.user.id,
|
||||
index_name: (state) => state.dialogue.index_name,
|
||||
toUser: (state) => state.user.toUser,
|
||||
}),
|
||||
},
|
||||
mounted () {
|
||||
console.log(this.goodsDetail)
|
||||
this.btnHide = localStorage.getItem('btnHide')
|
||||
},
|
||||
methods: {
|
||||
toGoods () {
|
||||
alert("toGoods")
|
||||
},
|
||||
toMessage () {
|
||||
alert(JSON.stringify(this.toUser))
|
||||
alert("toMessage")
|
||||
},
|
||||
// 回车键发送消息回调事件
|
||||
submitSendMessage () {
|
||||
console.log("发送");
|
||||
const context = this.goodsDetail
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: this.toUser.userId,
|
||||
from: this.id,
|
||||
message_type: "GOODS",
|
||||
context: context,
|
||||
talk_id: this.toUser.id,
|
||||
};
|
||||
SocketInstance.emit("event_talk", record);
|
||||
});
|
||||
|
||||
this.$store.commit("UPDATE_TALK_ITEM", {
|
||||
index_name: this.index_name,
|
||||
draft_text: "",
|
||||
});
|
||||
const btnHide = ref(undefined);
|
||||
const hide = ref(true);
|
||||
|
||||
const talkItems = computed(() => talkStore.talkItems);
|
||||
const id = computed(() => userStore.id);
|
||||
const index_name = computed(() => dialogueStore.index_name);
|
||||
const toUser = computed(() => userStore.toUser);
|
||||
|
||||
onMounted(() => {
|
||||
console.log(props.goodsDetail)
|
||||
btnHide.value = localStorage.getItem('btnHide')
|
||||
});
|
||||
|
||||
function toGoods () {
|
||||
alert("toGoods")
|
||||
}
|
||||
function toMessage () {
|
||||
alert(JSON.stringify(toUser.value))
|
||||
alert("toMessage")
|
||||
}
|
||||
// 回车键发送消息回调事件
|
||||
function submitSendMessage () {
|
||||
console.log("发送");
|
||||
const context = props.goodsDetail
|
||||
const record = {
|
||||
operation_type: "MESSAGE",
|
||||
to: toUser.value.userId,
|
||||
from: id.value,
|
||||
message_type: "GOODS",
|
||||
context: context,
|
||||
talk_id: toUser.value.id,
|
||||
};
|
||||
SocketInstance.emit("event_talk", record);
|
||||
|
||||
talkStore.UPDATE_TALK_ITEM({
|
||||
index_name: index_name.value,
|
||||
draft_text: "",
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
const insterChat = {
|
||||
createTime: this.formateDateAndTimeToString(new Date()),
|
||||
fromUser: this.id,
|
||||
toUser: record.to,
|
||||
isRead: false,
|
||||
messageType: "GOODS",
|
||||
text: context,
|
||||
float: "right",
|
||||
};
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
const insterChat = {
|
||||
createTime: formateDateAndTimeToString(new Date()),
|
||||
fromUser: id.value,
|
||||
toUser: record.to,
|
||||
isRead: false,
|
||||
messageType: "GOODS",
|
||||
text: context,
|
||||
float: "right",
|
||||
};
|
||||
|
||||
console.log("insterChat", insterChat);
|
||||
// console.log("插入对话记录",'')
|
||||
// 插入对话记录
|
||||
this.$store.commit("PUSH_DIALOGUE", insterChat);
|
||||
// 获取聊天面板元素节点
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
// 判断的滚动条是否在底部
|
||||
let isBottom =
|
||||
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||
console.log("insterChat", insterChat);
|
||||
// console.log("插入对话记录",'')
|
||||
// 插入对话记录
|
||||
dialogueStore.PUSH_DIALOGUE(insterChat);
|
||||
// 获取聊天面板元素节点
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
// 判断的滚动条是否在底部
|
||||
let isBottom =
|
||||
Math.ceil(el.scrollTop) + el.clientHeight >= el.scrollHeight;
|
||||
|
||||
if (isBottom || record.to == this.id) {
|
||||
this.$nextTick(() => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
} else {
|
||||
this.$store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||
content: content,
|
||||
nickname: record.name,
|
||||
});
|
||||
}
|
||||
// 发送后隐藏按钮 0:隐藏 1:显示
|
||||
localStorage.setItem('btnHide', 0)
|
||||
this.hide = false
|
||||
},
|
||||
|
||||
formateDateAndTimeToString (date) {
|
||||
var hours = date.getHours();
|
||||
var mins = date.getMinutes();
|
||||
var secs = date.getSeconds();
|
||||
var msecs = date.getMilliseconds();
|
||||
if (hours < 10) hours = "0" + hours;
|
||||
if (mins < 10) mins = "0" + mins;
|
||||
if (secs < 10) secs = "0" + secs;
|
||||
if (msecs < 10) secs = "0" + msecs;
|
||||
return (
|
||||
this.formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||
);
|
||||
},
|
||||
|
||||
formatDateToString (date) {
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
if (month < 10) month = "0" + month;
|
||||
if (day < 10) day = "0" + day;
|
||||
return year + "-" + month + "-" + day;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
goodsDetail: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
if (isBottom || record.to == id.value) {
|
||||
nextTick(() => {
|
||||
el.scrollTop = el.scrollHeight;
|
||||
});
|
||||
} else {
|
||||
talkStore.SET_TLAK_UNREAD_MESSAGE({
|
||||
content: content,
|
||||
nickname: record.name,
|
||||
});
|
||||
}
|
||||
// 发送后隐藏按钮 0:隐藏 1:显示
|
||||
localStorage.setItem('btnHide', 0)
|
||||
hide.value = false
|
||||
}
|
||||
|
||||
function formateDateAndTimeToString (date) {
|
||||
var hours = date.getHours();
|
||||
var mins = date.getMinutes();
|
||||
var secs = date.getSeconds();
|
||||
var msecs = date.getMilliseconds();
|
||||
if (hours < 10) hours = "0" + hours;
|
||||
if (mins < 10) mins = "0" + mins;
|
||||
if (secs < 10) secs = "0" + secs;
|
||||
if (msecs < 10) secs = "0" + msecs;
|
||||
return (
|
||||
formatDateToString(date) + " " + hours + ":" + mins + ":" + secs
|
||||
);
|
||||
}
|
||||
|
||||
function formatDateToString (date) {
|
||||
var year = date.getFullYear();
|
||||
var month = date.getMonth() + 1;
|
||||
var day = date.getDate();
|
||||
if (month < 10) month = "0" + month;
|
||||
if (day < 10) day = "0" + day;
|
||||
return year + "-" + month + "-" + day;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -34,24 +34,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
value: null,
|
||||
colors: ['#99A9BF', '#F7BA2A', '#FF9900']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
props: {
|
||||
storeInfo: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
defineProps({
|
||||
storeInfo: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const value = ref(null);
|
||||
const colors = ref(['#99A9BF', '#F7BA2A', '#FF9900']);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
</el-container>
|
||||
|
||||
<!-- 图片查看器 -->
|
||||
<MeEditorImageView ref="imageViewer" v-model:show="imageViewer.isShow" :file="imageViewer.file"
|
||||
<MeEditorImageView ref="imageViewerRef" v-model:show="imageViewer.isShow" :file="imageViewer.file"
|
||||
@confirm="confirmUploadImage" />
|
||||
|
||||
<MeEditorRecorder v-if="recorder" @close="recorder = false" />
|
||||
@@ -91,13 +91,14 @@
|
||||
|
||||
<MeEditorVote v-if="vote.isShow" @close="
|
||||
() => {
|
||||
this.vote.isShow = false;
|
||||
vote.isShow = false;
|
||||
}
|
||||
" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, reactive, ref, watch } from "vue";
|
||||
import MeEditorEmoticon from "./MeEditorEmoticon";
|
||||
import MeEditorFileManage from "./MeEditorFileManage";
|
||||
import MeEditorImageView from "./MeEditorImageView";
|
||||
@@ -106,6 +107,8 @@ import MeEditorVote from "./MeEditorVote";
|
||||
import TalkCodeBlock from "@/components/chat/TalkCodeBlock";
|
||||
import { getPasteImgs, getDragPasteImg } from "@/utils/editor";
|
||||
import { findTalk } from "@/utils/talk";
|
||||
import { ElNotification } from "@/utils/message";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
|
||||
import {
|
||||
ServeSendTalkCodeBlock,
|
||||
@@ -113,233 +116,225 @@ import {
|
||||
ServeSendEmoticon,
|
||||
} from "@/api/chat";
|
||||
|
||||
export default {
|
||||
name: "MeEditor",
|
||||
components: {
|
||||
MeEditorEmoticon,
|
||||
MeEditorFileManage,
|
||||
MeEditorImageView,
|
||||
TalkCodeBlock,
|
||||
MeEditorRecorder,
|
||||
MeEditorVote,
|
||||
},
|
||||
computed: {
|
||||
talkUser () {
|
||||
return this.$store.state.dialogue.index_name;
|
||||
},
|
||||
isGroupTalk () {
|
||||
return this.$store.state.dialogue.talk_type == 2;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
talkUser (n_index_name) {
|
||||
this.$refs.fileManageRef?.clear();
|
||||
this.editorText = this.getDraftText(n_index_name);
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// 当前编辑的内容
|
||||
editorText: "",
|
||||
defineOptions({ name: "MeEditor" });
|
||||
|
||||
// 图片查看器相关信息
|
||||
imageViewer: {
|
||||
isShow: false,
|
||||
file: null,
|
||||
},
|
||||
const emit = defineEmits(["keyboard-event", "send"]);
|
||||
|
||||
codeBlock: {
|
||||
isShow: false,
|
||||
editMode: true,
|
||||
},
|
||||
const dialogueStore = useDialogueStore();
|
||||
|
||||
filesManager: {
|
||||
isShow: false,
|
||||
},
|
||||
const popoverEmoticon = ref(null);
|
||||
const restFile = ref(null);
|
||||
const restFile2 = ref(null);
|
||||
const textarea = ref(null);
|
||||
// 模板 ref 原名 imageViewer,与下方 imageViewer 数据同名,改名避免互相覆盖
|
||||
const imageViewerRef = ref(null);
|
||||
const fileManageRef = ref(null);
|
||||
|
||||
vote: {
|
||||
isShow: false,
|
||||
},
|
||||
const talkUser = computed(() => dialogueStore.index_name);
|
||||
const isGroupTalk = computed(() => dialogueStore.talk_type == 2);
|
||||
|
||||
// 录音器
|
||||
recorder: false,
|
||||
// 当前编辑的内容
|
||||
const editorText = ref("");
|
||||
|
||||
// 上次发送消息的时间
|
||||
sendtime: 0,
|
||||
// 图片查看器相关信息
|
||||
const imageViewer = reactive({
|
||||
isShow: false,
|
||||
file: null,
|
||||
});
|
||||
|
||||
// 发送间隔时间(默认1秒)
|
||||
interval: 1000,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 读取对话编辑草稿信息 并赋值给当前富文本
|
||||
getDraftText (index_name) {
|
||||
return findTalk(index_name)?.draft_text || "";
|
||||
},
|
||||
const codeBlock = reactive({
|
||||
isShow: false,
|
||||
editMode: true,
|
||||
});
|
||||
|
||||
//复制粘贴图片回调方法
|
||||
pasteImage (e) {
|
||||
let files = getPasteImgs(e);
|
||||
if (files.length == 0) return;
|
||||
const filesManager = reactive({
|
||||
isShow: false,
|
||||
});
|
||||
|
||||
this.openImageViewer(files[0]);
|
||||
},
|
||||
const vote = reactive({
|
||||
isShow: false,
|
||||
});
|
||||
|
||||
//拖拽上传图片回调方法
|
||||
dragPasteImage (e) {
|
||||
let files = getDragPasteImg(e);
|
||||
if (files.length == 0) return;
|
||||
// 录音器
|
||||
const recorder = ref(false);
|
||||
|
||||
this.openImageViewer(files[0]);
|
||||
},
|
||||
// 上次发送消息的时间
|
||||
const sendtime = ref(0);
|
||||
|
||||
inputEvent (e) {
|
||||
this.$emit("keyboard-event", e.target.value);
|
||||
},
|
||||
// 发送间隔时间(默认1秒)
|
||||
const interval = ref(1000);
|
||||
|
||||
// 键盘按下监听事件
|
||||
keydownEvent (e) {
|
||||
if (e.keyCode == 13 && this.editorText == "") {
|
||||
watch(talkUser, (n_index_name) => {
|
||||
fileManageRef.value?.clear();
|
||||
editorText.value = getDraftText(n_index_name);
|
||||
});
|
||||
|
||||
// 读取对话编辑草稿信息 并赋值给当前富文本
|
||||
function getDraftText(index_name) {
|
||||
return findTalk(index_name)?.draft_text || "";
|
||||
}
|
||||
|
||||
//复制粘贴图片回调方法
|
||||
function pasteImage(e) {
|
||||
let files = getPasteImgs(e);
|
||||
if (files.length == 0) return;
|
||||
|
||||
openImageViewer(files[0]);
|
||||
}
|
||||
|
||||
//拖拽上传图片回调方法
|
||||
function dragPasteImage(e) {
|
||||
let files = getDragPasteImg(e);
|
||||
if (files.length == 0) return;
|
||||
|
||||
openImageViewer(files[0]);
|
||||
}
|
||||
|
||||
function inputEvent(e) {
|
||||
emit("keyboard-event", e.target.value);
|
||||
}
|
||||
|
||||
// 键盘按下监听事件
|
||||
function keydownEvent(e) {
|
||||
if (e.keyCode == 13 && editorText.value == "") {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// 回车发送消息
|
||||
if (e.keyCode == 13 && e.shiftKey == false && editorText.value != "") {
|
||||
let currentTime = new Date().getTime();
|
||||
|
||||
if (sendtime.value > 0) {
|
||||
// 判断 1秒内只能发送一条消息
|
||||
if (currentTime - sendtime.value < interval.value) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// 回车发送消息
|
||||
if (e.keyCode == 13 && e.shiftKey == false && this.editorText != "") {
|
||||
let currentTime = new Date().getTime();
|
||||
|
||||
if (this.sendtime > 0) {
|
||||
// 判断 1秒内只能发送一条消息
|
||||
if (currentTime - this.sendtime < this.interval) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit("send", this.editorText);
|
||||
this.editorText = "";
|
||||
this.sendtime = currentTime;
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
// 选择图片文件后回调方法
|
||||
uploadImageChange (e) {
|
||||
this.openImageViewer(e.target.files[0]);
|
||||
this.$refs.restFile.value = null;
|
||||
},
|
||||
|
||||
// 选择文件回调事件
|
||||
uploadFileChange (e) {
|
||||
let maxsize = 100 * 1024 * 1024;
|
||||
if (e.target.files.length == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let file = e.target.files[0];
|
||||
if (/\.(gif|jpg|jpeg|png|webp|GIF|JPG|PNG|WEBP)$/.test(file.name)) {
|
||||
this.openImageViewer(file);
|
||||
return;
|
||||
}
|
||||
emit("send", editorText.value);
|
||||
editorText.value = "";
|
||||
sendtime.value = currentTime;
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
if (file.size > maxsize) {
|
||||
this.$notify.info({
|
||||
title: "消息",
|
||||
message: "上传文件不能大于100M",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 选择图片文件后回调方法
|
||||
function uploadImageChange(e) {
|
||||
openImageViewer(e.target.files[0]);
|
||||
restFile.value.value = null;
|
||||
}
|
||||
|
||||
this.filesManager.isShow = true;
|
||||
this.$refs.restFile2.value = null;
|
||||
this.$refs.fileManageRef?.upload(file);
|
||||
},
|
||||
// 选择文件回调事件
|
||||
function uploadFileChange(e) {
|
||||
let maxsize = 100 * 1024 * 1024;
|
||||
if (e.target.files.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 打开图片查看器
|
||||
openImageViewer (file) {
|
||||
this.imageViewer.isShow = true;
|
||||
this.imageViewer.file = file;
|
||||
},
|
||||
let file = e.target.files[0];
|
||||
if (/\.(gif|jpg|jpeg|png|webp|GIF|JPG|PNG|WEBP)$/.test(file.name)) {
|
||||
openImageViewer(file);
|
||||
return;
|
||||
}
|
||||
|
||||
// 代码块编辑器确认完成回调事件
|
||||
confirmCodeBlock (data) {
|
||||
const { talk_type, receiver_id } = this.$store.state.dialogue;
|
||||
ServeSendTalkCodeBlock({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
code: data.code,
|
||||
lang: data.language,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.codeBlock.isShow = false;
|
||||
} else {
|
||||
this.$notify({
|
||||
title: "友情提示",
|
||||
message: res.message,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
if (file.size > maxsize) {
|
||||
ElNotification.info({
|
||||
title: "消息",
|
||||
message: "上传文件不能大于100M",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
filesManager.isShow = true;
|
||||
restFile2.value.value = null;
|
||||
fileManageRef.value?.upload(file);
|
||||
}
|
||||
|
||||
// 打开图片查看器
|
||||
function openImageViewer(file) {
|
||||
imageViewer.isShow = true;
|
||||
imageViewer.file = file;
|
||||
}
|
||||
|
||||
// 代码块编辑器确认完成回调事件
|
||||
function confirmCodeBlock(data) {
|
||||
const { talk_type, receiver_id } = dialogueStore;
|
||||
ServeSendTalkCodeBlock({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
code: data.code,
|
||||
lang: data.language,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
codeBlock.isShow = false;
|
||||
} else {
|
||||
ElNotification({
|
||||
title: "友情提示",
|
||||
message: res.message,
|
||||
type: "warning",
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 确认上传图片消息回调事件
|
||||
confirmUploadImage () {
|
||||
let fileData = new FormData();
|
||||
fileData.append("file", this.imageViewer.file);
|
||||
// 确认上传图片消息回调事件
|
||||
function confirmUploadImage() {
|
||||
let fileData = new FormData();
|
||||
fileData.append("file", imageViewer.file);
|
||||
|
||||
let ref = this.$refs.imageViewer;
|
||||
let imageView = imageViewerRef.value;
|
||||
|
||||
ServeSendTalkImage(fileData)
|
||||
.then((res) => {
|
||||
ref.loading = false;
|
||||
if (res.code == 200) {
|
||||
ref.closeBox();
|
||||
} else {
|
||||
this.$notify({
|
||||
title: "友情提示",
|
||||
message: res.message,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
ref.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
// 选中表情包回调事件
|
||||
selecteEmoticon (data) {
|
||||
if (data.type == 1) {
|
||||
let value = this.editorText;
|
||||
let el = this.$refs.textarea;
|
||||
let startPos = el.selectionStart;
|
||||
let endPos = el.selectionEnd;
|
||||
let newValue =
|
||||
value.substring(0, startPos) +
|
||||
data.value +
|
||||
value.substring(endPos, value.length);
|
||||
|
||||
this.editorText = newValue;
|
||||
|
||||
if (el.setSelectionRange) {
|
||||
setTimeout(() => {
|
||||
let index = startPos + data.value.length;
|
||||
el.setSelectionRange(index, index);
|
||||
el.focus();
|
||||
}, 0);
|
||||
}
|
||||
ServeSendTalkImage(fileData)
|
||||
.then((res) => {
|
||||
imageView.loading = false;
|
||||
if (res.code == 200) {
|
||||
imageView.closeBox();
|
||||
} else {
|
||||
const { talk_type, receiver_id } = this.$store.state.dialogue;
|
||||
ServeSendEmoticon({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
emoticon_id: data.value,
|
||||
ElNotification({
|
||||
title: "友情提示",
|
||||
message: res.message,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
imageView.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
this.$refs.popoverEmoticon.hide();
|
||||
},
|
||||
},
|
||||
};
|
||||
// 选中表情包回调事件
|
||||
function selecteEmoticon(data) {
|
||||
if (data.type == 1) {
|
||||
let value = editorText.value;
|
||||
let el = textarea.value;
|
||||
let startPos = el.selectionStart;
|
||||
let endPos = el.selectionEnd;
|
||||
let newValue =
|
||||
value.substring(0, startPos) +
|
||||
data.value +
|
||||
value.substring(endPos, value.length);
|
||||
|
||||
editorText.value = newValue;
|
||||
|
||||
if (el.setSelectionRange) {
|
||||
setTimeout(() => {
|
||||
let index = startPos + data.value.length;
|
||||
el.setSelectionRange(index, index);
|
||||
el.focus();
|
||||
}, 0);
|
||||
}
|
||||
} else {
|
||||
const { talk_type, receiver_id } = dialogueStore;
|
||||
ServeSendEmoticon({
|
||||
talk_type,
|
||||
receiver_id,
|
||||
emoticon_id: data.value,
|
||||
});
|
||||
}
|
||||
|
||||
popoverEmoticon.value.hide();
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.editor-container {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<div
|
||||
v-if="item.emoticon_id == 0"
|
||||
class="emoji-item custom-emoji"
|
||||
@click="$refs.fileCustomEmoji.click()"
|
||||
@click="fileCustomEmoji.click()"
|
||||
>
|
||||
<legacy-el-icon name="el-icon-picture" />
|
||||
<span>自定义</span>
|
||||
@@ -93,96 +93,91 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import MeEditorSystemEmoticon from "@/components/editor/MeEditorSystemEmoticon";
|
||||
import { emojiList as emoji } from "@/utils/emojis";
|
||||
import { mapState } from "vuex";
|
||||
import { useEmoticonStore } from "@/stores/emoticon";
|
||||
|
||||
export default {
|
||||
name: "MeEditorEmoticon",
|
||||
components: {
|
||||
MeEditorSystemEmoticon,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
emojiItem: (state) => state.emoticon.items,
|
||||
}),
|
||||
showItems() {
|
||||
let start = (this.page - 1) * this.pageSize;
|
||||
let end = start + this.pageSize;
|
||||
return this.emojiItem.slice(start, end);
|
||||
},
|
||||
pageTotal() {
|
||||
return this.emojiItem.length / this.pageSize;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
emoji,
|
||||
defineOptions({ name: "MeEditorEmoticon" });
|
||||
|
||||
// 系统表情包套弹出窗
|
||||
systemEmojiBox: false,
|
||||
const emit = defineEmits(["selected"]);
|
||||
|
||||
showEmoticonId: -1,
|
||||
showTitle: "QQ表情/符号表情",
|
||||
const emoticonStore = useEmoticonStore();
|
||||
|
||||
page: 1,
|
||||
pageSize: 13,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$store.commit("LOAD_USER_EMOTICON");
|
||||
},
|
||||
methods: {
|
||||
// 表情包导航翻页
|
||||
turnPage(type) {
|
||||
if (type == 1) {
|
||||
if (this.page == 1) return false;
|
||||
this.page--;
|
||||
} else {
|
||||
if (this.page >= this.pageTotal) return false;
|
||||
this.page++;
|
||||
}
|
||||
},
|
||||
const fileCustomEmoji = ref(null);
|
||||
|
||||
// 点击表情包导航
|
||||
triggerItem(item) {
|
||||
this.showEmoticonId = item.emoticon_id;
|
||||
this.showTitle = item.name;
|
||||
},
|
||||
// 系统表情包套弹出窗
|
||||
const systemEmojiBox = ref(false);
|
||||
|
||||
// 选中表情
|
||||
clickEmoticon(emoji) {
|
||||
this.callback({
|
||||
type: 1,
|
||||
value: emoji,
|
||||
});
|
||||
},
|
||||
const showEmoticonId = ref(-1);
|
||||
const showTitle = ref("QQ表情/符号表情");
|
||||
|
||||
// 发送图片表情包
|
||||
clickImageEmoticon(item) {
|
||||
this.callback({
|
||||
type: 2,
|
||||
value: item.media_id,
|
||||
});
|
||||
},
|
||||
const page = ref(1);
|
||||
const pageSize = ref(13);
|
||||
|
||||
callback(data) {
|
||||
this.$emit("selected", data);
|
||||
},
|
||||
const emojiItem = computed(() => emoticonStore.items);
|
||||
|
||||
// 自定义上传表情
|
||||
customUploadEmoji(e) {
|
||||
if (e.target.files.length == 0) {
|
||||
return false;
|
||||
}
|
||||
const showItems = computed(() => {
|
||||
let start = (page.value - 1) * pageSize.value;
|
||||
let end = start + pageSize.value;
|
||||
return emojiItem.value.slice(start, end);
|
||||
});
|
||||
|
||||
this.$store.commit("UPLOAD_USER_EMOTICON", {
|
||||
file: e.target.files[0],
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
const pageTotal = computed(() => {
|
||||
return emojiItem.value.length / pageSize.value;
|
||||
});
|
||||
|
||||
// 原 created 钩子
|
||||
emoticonStore.LOAD_USER_EMOTICON();
|
||||
|
||||
// 表情包导航翻页
|
||||
function turnPage(type) {
|
||||
if (type == 1) {
|
||||
if (page.value == 1) return false;
|
||||
page.value--;
|
||||
} else {
|
||||
if (page.value >= pageTotal.value) return false;
|
||||
page.value++;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击表情包导航
|
||||
function triggerItem(item) {
|
||||
showEmoticonId.value = item.emoticon_id;
|
||||
showTitle.value = item.name;
|
||||
}
|
||||
|
||||
// 选中表情
|
||||
function clickEmoticon(emoji) {
|
||||
callback({
|
||||
type: 1,
|
||||
value: emoji,
|
||||
});
|
||||
}
|
||||
|
||||
// 发送图片表情包
|
||||
function clickImageEmoticon(item) {
|
||||
callback({
|
||||
type: 2,
|
||||
value: item.media_id,
|
||||
});
|
||||
}
|
||||
|
||||
function callback(data) {
|
||||
emit("selected", data);
|
||||
}
|
||||
|
||||
// 自定义上传表情
|
||||
function customUploadEmoji(e) {
|
||||
if (e.target.files.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
emoticonStore.UPLOAD_USER_EMOTICON({
|
||||
file: e.target.files[0],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
|
||||
@@ -77,179 +77,180 @@
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { useDialogueStore } from '@/stores/dialogue'
|
||||
import { SvgNotData } from '@/core/icons'
|
||||
import { ServeFindFileSplitInfo, ServeFileSubareaUpload } from '@/api/upload'
|
||||
import { formatSize, getFileExt, parseTime } from '@/utils/functions'
|
||||
import { ServeSendTalkFile } from '@/api/chat'
|
||||
|
||||
export default {
|
||||
name: 'MeEditorFileManage',
|
||||
emits: ['close', 'update:show'],
|
||||
props: {
|
||||
show: Boolean,
|
||||
defineOptions({ name: 'MeEditorFileManage' })
|
||||
|
||||
const emit = defineEmits(['close', 'update:show'])
|
||||
|
||||
defineProps({
|
||||
show: Boolean,
|
||||
})
|
||||
|
||||
const dialogueStore = useDialogueStore()
|
||||
|
||||
const colors = ref([
|
||||
{
|
||||
color: '#f56c6c',
|
||||
percentage: 20,
|
||||
},
|
||||
components: {
|
||||
SvgNotData,
|
||||
{
|
||||
color: '#e6a23c',
|
||||
percentage: 40,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
colors: [
|
||||
{
|
||||
color: '#f56c6c',
|
||||
percentage: 20,
|
||||
},
|
||||
{
|
||||
color: '#e6a23c',
|
||||
percentage: 40,
|
||||
},
|
||||
{
|
||||
color: '#5cb87a',
|
||||
percentage: 60,
|
||||
},
|
||||
{
|
||||
color: '#1989fa',
|
||||
percentage: 80,
|
||||
},
|
||||
{
|
||||
color: '#11ce65',
|
||||
percentage: 100,
|
||||
},
|
||||
],
|
||||
|
||||
items: [],
|
||||
}
|
||||
{
|
||||
color: '#5cb87a',
|
||||
percentage: 60,
|
||||
},
|
||||
computed: {
|
||||
total() {
|
||||
return this.items.filter(item => {
|
||||
return item.isDelete === false
|
||||
}).length
|
||||
},
|
||||
successNum() {
|
||||
return this.items.filter(item => {
|
||||
return item.isDelete === false && item.status == 2
|
||||
}).length
|
||||
},
|
||||
{
|
||||
color: '#1989fa',
|
||||
percentage: 80,
|
||||
},
|
||||
methods: {
|
||||
closeBox() {
|
||||
this.$emit('update:show', false)
|
||||
this.$emit('close', false)
|
||||
},
|
||||
|
||||
upload(file) {
|
||||
ServeFindFileSplitInfo({
|
||||
file_name: file.name,
|
||||
file_size: file.size,
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
const { hash_name, split_size } = res.data
|
||||
|
||||
this.items.unshift({
|
||||
hashName: hash_name,
|
||||
originalFile: file,
|
||||
filename: file.name,
|
||||
status: 0, // 文件上传状态 0:等待上传 1:上传中 2:上传完成 3:网络异常
|
||||
progress: 0,
|
||||
filesize: formatSize(file.size),
|
||||
filetype: file.type || '未知',
|
||||
datetime: parseTime(new Date(), '{m}-{d} {h}:{i}'),
|
||||
ext: getFileExt(file.name),
|
||||
forms: this.fileSlice(file, hash_name, split_size),
|
||||
successNum: 0,
|
||||
isDelete: false,
|
||||
})
|
||||
|
||||
this.triggerUpload(hash_name)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 处理拆分上传文件
|
||||
fileSlice(file, hash, eachSize) {
|
||||
const ext = getFileExt(file.name)
|
||||
const splitNum = Math.ceil(file.size / eachSize) // 分片总数
|
||||
const forms = []
|
||||
|
||||
// 处理每个分片的上传操作
|
||||
for (let i = 0; i < splitNum; i++) {
|
||||
let start = i * eachSize
|
||||
let end = Math.min(file.size, start + eachSize)
|
||||
|
||||
// 构建表单
|
||||
const form = new FormData()
|
||||
form.append('file', file.slice(start, end))
|
||||
form.append('name', file.name)
|
||||
form.append('hash', hash)
|
||||
form.append('ext', ext)
|
||||
form.append('size', file.size)
|
||||
form.append('split_index', i)
|
||||
form.append('split_num', splitNum)
|
||||
forms.push(form)
|
||||
}
|
||||
|
||||
return forms
|
||||
},
|
||||
|
||||
// 触发上传文件
|
||||
triggerUpload(hashName) {
|
||||
let $index = this.getFileIndex(hashName)
|
||||
if ($index < 0 || this.items[$index].isDelte) {
|
||||
return
|
||||
}
|
||||
|
||||
let i = this.items[$index].successNum
|
||||
let form = this.items[$index].forms[i]
|
||||
let length = this.items[$index].forms.length
|
||||
this.items[$index].status = 1
|
||||
ServeFileSubareaUpload(form)
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
$index = this.getFileIndex(hashName)
|
||||
this.items[$index].successNum++
|
||||
this.items[$index].progress = Math.floor(
|
||||
(this.items[$index].successNum / length) * 100
|
||||
)
|
||||
if (this.items[$index].successNum == length) {
|
||||
this.items[$index].status = 2
|
||||
if (res.data.is_file_merge) {
|
||||
ServeSendTalkFile({
|
||||
hash_name: res.data.hash,
|
||||
receiver_id: this.$store.state.dialogue.receiver_id,
|
||||
talk_type: this.$store.state.dialogue.talk_type,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.triggerUpload(hashName)
|
||||
}
|
||||
} else {
|
||||
this.items[$index].status = 3
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
$index = this.getFileIndex(hashName)
|
||||
this.items[$index].status = 3
|
||||
})
|
||||
},
|
||||
|
||||
// 获取分片文件数组索引
|
||||
getFileIndex(hashName) {
|
||||
return this.items.findIndex(item => {
|
||||
return item.hashName === hashName
|
||||
})
|
||||
},
|
||||
|
||||
removeFile(hashName) {
|
||||
let index = this.getFileIndex(hashName)
|
||||
this.items[index].isDelete = true
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.items = []
|
||||
},
|
||||
{
|
||||
color: '#11ce65',
|
||||
percentage: 100,
|
||||
},
|
||||
])
|
||||
|
||||
const items = ref([])
|
||||
|
||||
const total = computed(() => {
|
||||
return items.value.filter(item => {
|
||||
return item.isDelete === false
|
||||
}).length
|
||||
})
|
||||
|
||||
const successNum = computed(() => {
|
||||
return items.value.filter(item => {
|
||||
return item.isDelete === false && item.status == 2
|
||||
}).length
|
||||
})
|
||||
|
||||
function closeBox() {
|
||||
emit('update:show', false)
|
||||
emit('close', false)
|
||||
}
|
||||
|
||||
function upload(file) {
|
||||
ServeFindFileSplitInfo({
|
||||
file_name: file.name,
|
||||
file_size: file.size,
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
const { hash_name, split_size } = res.data
|
||||
|
||||
items.value.unshift({
|
||||
hashName: hash_name,
|
||||
originalFile: file,
|
||||
filename: file.name,
|
||||
status: 0, // 文件上传状态 0:等待上传 1:上传中 2:上传完成 3:网络异常
|
||||
progress: 0,
|
||||
filesize: formatSize(file.size),
|
||||
filetype: file.type || '未知',
|
||||
datetime: parseTime(new Date(), '{m}-{d} {h}:{i}'),
|
||||
ext: getFileExt(file.name),
|
||||
forms: fileSlice(file, hash_name, split_size),
|
||||
successNum: 0,
|
||||
isDelete: false,
|
||||
})
|
||||
|
||||
triggerUpload(hash_name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理拆分上传文件
|
||||
function fileSlice(file, hash, eachSize) {
|
||||
const ext = getFileExt(file.name)
|
||||
const splitNum = Math.ceil(file.size / eachSize) // 分片总数
|
||||
const forms = []
|
||||
|
||||
// 处理每个分片的上传操作
|
||||
for (let i = 0; i < splitNum; i++) {
|
||||
let start = i * eachSize
|
||||
let end = Math.min(file.size, start + eachSize)
|
||||
|
||||
// 构建表单
|
||||
const form = new FormData()
|
||||
form.append('file', file.slice(start, end))
|
||||
form.append('name', file.name)
|
||||
form.append('hash', hash)
|
||||
form.append('ext', ext)
|
||||
form.append('size', file.size)
|
||||
form.append('split_index', i)
|
||||
form.append('split_num', splitNum)
|
||||
forms.push(form)
|
||||
}
|
||||
|
||||
return forms
|
||||
}
|
||||
|
||||
// 触发上传文件
|
||||
function triggerUpload(hashName) {
|
||||
let $index = getFileIndex(hashName)
|
||||
// 历史遗留:此处判断的是不存在的字段 isDelte(原样保留)
|
||||
if ($index < 0 || items.value[$index].isDelte) {
|
||||
return
|
||||
}
|
||||
|
||||
let i = items.value[$index].successNum
|
||||
let form = items.value[$index].forms[i]
|
||||
let length = items.value[$index].forms.length
|
||||
items.value[$index].status = 1
|
||||
ServeFileSubareaUpload(form)
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
$index = getFileIndex(hashName)
|
||||
items.value[$index].successNum++
|
||||
items.value[$index].progress = Math.floor(
|
||||
(items.value[$index].successNum / length) * 100
|
||||
)
|
||||
if (items.value[$index].successNum == length) {
|
||||
items.value[$index].status = 2
|
||||
if (res.data.is_file_merge) {
|
||||
ServeSendTalkFile({
|
||||
hash_name: res.data.hash,
|
||||
receiver_id: dialogueStore.receiver_id,
|
||||
talk_type: dialogueStore.talk_type,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
triggerUpload(hashName)
|
||||
}
|
||||
} else {
|
||||
items.value[$index].status = 3
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
$index = getFileIndex(hashName)
|
||||
items.value[$index].status = 3
|
||||
})
|
||||
}
|
||||
|
||||
// 获取分片文件数组索引
|
||||
function getFileIndex(hashName) {
|
||||
return items.value.findIndex(item => {
|
||||
return item.hashName === hashName
|
||||
})
|
||||
}
|
||||
|
||||
function removeFile(hashName) {
|
||||
let index = getFileIndex(hashName)
|
||||
items.value[index].isDelete = true
|
||||
}
|
||||
|
||||
function clear() {
|
||||
items.value = []
|
||||
}
|
||||
|
||||
// 父组件 MeEditor 通过 ref="fileManageRef" 调用 upload/clear
|
||||
defineExpose({ upload, clear })
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
|
||||
@@ -30,54 +30,57 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'MeEditorImageView',
|
||||
emits: ['close', 'update:show', 'confirm'],
|
||||
props: {
|
||||
show: Boolean,
|
||||
file: File,
|
||||
},
|
||||
watch: {
|
||||
file(file) {
|
||||
this.loadFile(file)
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
src: '',
|
||||
fileSize: '',
|
||||
fileName: '',
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBox() {
|
||||
if (this.loading) {
|
||||
return false
|
||||
}
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
this.$emit('update:show', false)
|
||||
this.$emit('close', false)
|
||||
},
|
||||
loadFile(file) {
|
||||
let reader = new FileReader()
|
||||
this.fileSize = Math.ceil(file.size / 1024)
|
||||
this.fileName = file.name
|
||||
reader.onload = () => {
|
||||
this.src = reader.result
|
||||
}
|
||||
defineOptions({ name: 'MeEditorImageView' })
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
},
|
||||
const emit = defineEmits(['close', 'update:show', 'confirm'])
|
||||
const props = defineProps({
|
||||
show: Boolean,
|
||||
file: File,
|
||||
})
|
||||
|
||||
// 确认按钮事件
|
||||
uploadImage() {
|
||||
this.loading = true
|
||||
this.$emit('confirm')
|
||||
},
|
||||
},
|
||||
const src = ref('')
|
||||
const fileSize = ref('')
|
||||
const fileName = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
watch(
|
||||
() => props.file,
|
||||
(file) => {
|
||||
loadFile(file)
|
||||
}
|
||||
)
|
||||
|
||||
function closeBox() {
|
||||
if (loading.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
emit('update:show', false)
|
||||
emit('close', false)
|
||||
}
|
||||
|
||||
function loadFile(file) {
|
||||
let reader = new FileReader()
|
||||
fileSize.value = Math.ceil(file.size / 1024)
|
||||
fileName.value = file.name
|
||||
reader.onload = () => {
|
||||
src.value = reader.result
|
||||
}
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
|
||||
// 确认按钮事件
|
||||
function uploadImage() {
|
||||
loading.value = true
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
// 父组件通过 $refs.imageViewer 访问 loading / closeBox
|
||||
defineExpose({ loading, closeBox })
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.lum-dialog-box {
|
||||
|
||||
@@ -140,168 +140,166 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||
import Recorder from 'js-audio-recorder'
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: 'MeEditorRecorder',
|
||||
data() {
|
||||
return {
|
||||
// 录音实例
|
||||
recorder: null,
|
||||
})
|
||||
|
||||
// 录音时长
|
||||
duration: 0,
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
// 播放时长
|
||||
playTime: 0,
|
||||
// 录音实例
|
||||
let recorder = null
|
||||
|
||||
animation: false,
|
||||
// 录音时长
|
||||
const duration = ref(0)
|
||||
|
||||
// 当前状态
|
||||
recorderStatus: 0, //0:未开始录音 1:正在录音 2:暂停录音 3:结束录音 4:播放录音 5:停止播放 6:播放结束
|
||||
// 播放时长
|
||||
const playTime = ref(0)
|
||||
|
||||
playTimeout: null,
|
||||
const animation = ref(false)
|
||||
|
||||
// 当前状态
|
||||
const recorderStatus = ref(0) //0:未开始录音 1:正在录音 2:暂停录音 3:结束录音 4:播放录音 5:停止播放 6:播放结束
|
||||
|
||||
let playTimeout = null
|
||||
|
||||
const datetime = computed(() => {
|
||||
let hour = parseInt((duration.value / 60 / 60) % 24) //小时
|
||||
let minute = parseInt((duration.value / 60) % 60) //分钟
|
||||
let seconds = parseInt(duration.value % 60) //秒
|
||||
|
||||
if (hour < 10) hour = `0${hour}`
|
||||
if (minute < 10) minute = `0${minute}`
|
||||
if (seconds < 10) seconds = `0${seconds}`
|
||||
|
||||
return `${hour}:${minute}:${seconds}`
|
||||
})
|
||||
const formatPlayTime = computed(() => {
|
||||
let hour = parseInt((playTime.value / 60 / 60) % 24) //小时
|
||||
let minute = parseInt((playTime.value / 60) % 60) //分钟
|
||||
let seconds = parseInt(playTime.value % 60) //秒
|
||||
|
||||
if (hour < 10) hour = `0${hour}`
|
||||
if (minute < 10) minute = `0${minute}`
|
||||
if (seconds < 10) seconds = `0${seconds}`
|
||||
|
||||
return `${hour}:${minute}:${seconds}`
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (recorder) {
|
||||
destroyRecorder()
|
||||
}
|
||||
})
|
||||
|
||||
const closeBox = () => {
|
||||
if (recorder == null) {
|
||||
emit('close', false)
|
||||
return
|
||||
}
|
||||
|
||||
if (recorderStatus.value == 1) {
|
||||
stopRecorder()
|
||||
} else if (recorderStatus.value == 4) {
|
||||
pausePlayRecorder()
|
||||
}
|
||||
|
||||
// 销毁录音后关闭窗口
|
||||
destroyRecorder(() => {
|
||||
emit('close', false)
|
||||
})
|
||||
}
|
||||
|
||||
// 开始录音
|
||||
const startRecorder = () => {
|
||||
// http://recorder.api.zhuyuntao.cn/Recorder/event.html
|
||||
// https://blog.csdn.net/qq_41619796/article/details/107865602
|
||||
recorder = new Recorder()
|
||||
recorder.onprocess = d => {
|
||||
d = parseInt(d)
|
||||
duration.value = d
|
||||
}
|
||||
|
||||
recorder.start().then(
|
||||
() => {
|
||||
recorderStatus.value = 1
|
||||
animation.value = true
|
||||
},
|
||||
error => {
|
||||
console.log(`${error.name} : ${error.message}`)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
datetime() {
|
||||
let hour = parseInt((this.duration / 60 / 60) % 24) //小时
|
||||
let minute = parseInt((this.duration / 60) % 60) //分钟
|
||||
let seconds = parseInt(this.duration % 60) //秒
|
||||
|
||||
if (hour < 10) hour = `0${hour}`
|
||||
if (minute < 10) minute = `0${minute}`
|
||||
if (seconds < 10) seconds = `0${seconds}`
|
||||
|
||||
return `${hour}:${minute}:${seconds}`
|
||||
},
|
||||
formatPlayTime() {
|
||||
let hour = parseInt((this.playTime / 60 / 60) % 24) //小时
|
||||
let minute = parseInt((this.playTime / 60) % 60) //分钟
|
||||
let seconds = parseInt(this.playTime % 60) //秒
|
||||
|
||||
if (hour < 10) hour = `0${hour}`
|
||||
if (minute < 10) minute = `0${minute}`
|
||||
if (seconds < 10) seconds = `0${seconds}`
|
||||
|
||||
return `${hour}:${minute}:${seconds}`
|
||||
},
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.recorder) {
|
||||
this.destroyRecorder()
|
||||
)
|
||||
}
|
||||
// 暂停录音
|
||||
const pauseRecorder = () => {
|
||||
recorder.pause()
|
||||
recorderStatus.value = 2
|
||||
animation.value = false
|
||||
}
|
||||
// 继续录音
|
||||
const resumeRecorder = () => {
|
||||
recorderStatus.value = 1
|
||||
recorder.resume()
|
||||
animation.value = true
|
||||
}
|
||||
// 结束录音
|
||||
const stopRecorder = () => {
|
||||
recorderStatus.value = 3
|
||||
recorder.stop()
|
||||
animation.value = false
|
||||
}
|
||||
// 录音播放
|
||||
const playRecorder = () => {
|
||||
recorderStatus.value = 4
|
||||
recorder.play()
|
||||
playTimeouts()
|
||||
animation.value = true
|
||||
}
|
||||
// 暂停录音播放
|
||||
const pausePlayRecorder = () => {
|
||||
recorderStatus.value = 5
|
||||
recorder.pausePlay()
|
||||
clearInterval(playTimeout)
|
||||
animation.value = false
|
||||
}
|
||||
// 恢复录音播放
|
||||
const resumePlayRecorder = () => {
|
||||
recorderStatus.value = 4
|
||||
recorder.resumePlay()
|
||||
playTimeouts()
|
||||
animation.value = true
|
||||
}
|
||||
// 销毁录音
|
||||
const destroyRecorder = callBack => {
|
||||
recorder.destroy().then(() => {
|
||||
recorder = null
|
||||
if (callBack) {
|
||||
callBack()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeBox() {
|
||||
if (this.recorder == null) {
|
||||
this.$emit('close', false)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
// 获取录音文件大小(单位:字节)
|
||||
const recorderSize = () => {
|
||||
return recorder.fileSize
|
||||
}
|
||||
|
||||
if (this.recorderStatus == 1) {
|
||||
this.stopRecorder()
|
||||
} else if (this.recorderStatus == 4) {
|
||||
this.pausePlayRecorder()
|
||||
}
|
||||
const playTimeouts = () => {
|
||||
playTimeout = setInterval(() => {
|
||||
let time = parseInt(recorder.getPlayTime())
|
||||
playTime.value = time
|
||||
if (time == duration.value) {
|
||||
clearInterval(playTimeout)
|
||||
animation.value = false
|
||||
recorderStatus.value = 6
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 销毁录音后关闭窗口
|
||||
this.destroyRecorder(() => {
|
||||
this.$emit('close', false)
|
||||
})
|
||||
},
|
||||
|
||||
// 开始录音
|
||||
startRecorder() {
|
||||
let _this = this
|
||||
// http://recorder.api.zhuyuntao.cn/Recorder/event.html
|
||||
// https://blog.csdn.net/qq_41619796/article/details/107865602
|
||||
this.recorder = new Recorder()
|
||||
this.recorder.onprocess = duration => {
|
||||
duration = parseInt(duration)
|
||||
_this.duration = duration
|
||||
}
|
||||
|
||||
this.recorder.start().then(
|
||||
() => {
|
||||
this.recorderStatus = 1
|
||||
this.animation = true
|
||||
},
|
||||
error => {
|
||||
console.log(`${error.name} : ${error.message}`)
|
||||
}
|
||||
)
|
||||
},
|
||||
// 暂停录音
|
||||
pauseRecorder() {
|
||||
this.recorder.pause()
|
||||
this.recorderStatus = 2
|
||||
this.animation = false
|
||||
},
|
||||
// 继续录音
|
||||
resumeRecorder() {
|
||||
this.recorderStatus = 1
|
||||
this.recorder.resume()
|
||||
this.animation = true
|
||||
},
|
||||
// 结束录音
|
||||
stopRecorder() {
|
||||
this.recorderStatus = 3
|
||||
this.recorder.stop()
|
||||
this.animation = false
|
||||
},
|
||||
// 录音播放
|
||||
playRecorder() {
|
||||
this.recorderStatus = 4
|
||||
this.recorder.play()
|
||||
this.playTimeouts()
|
||||
this.animation = true
|
||||
},
|
||||
// 暂停录音播放
|
||||
pausePlayRecorder() {
|
||||
this.recorderStatus = 5
|
||||
this.recorder.pausePlay()
|
||||
clearInterval(this.playTimeout)
|
||||
this.animation = false
|
||||
},
|
||||
// 恢复录音播放
|
||||
resumePlayRecorder() {
|
||||
this.recorderStatus = 4
|
||||
this.recorder.resumePlay()
|
||||
this.playTimeouts()
|
||||
this.animation = true
|
||||
},
|
||||
// 销毁录音
|
||||
destroyRecorder(callBack) {
|
||||
this.recorder.destroy().then(() => {
|
||||
this.recorder = null
|
||||
if (callBack) {
|
||||
callBack()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 获取录音文件大小(单位:字节)
|
||||
recorderSize() {
|
||||
return this.recorder.fileSize
|
||||
},
|
||||
|
||||
playTimeouts() {
|
||||
this.playTimeout = setInterval(() => {
|
||||
let time = parseInt(this.recorder.getPlayTime())
|
||||
this.playTime = time
|
||||
if (time == this.duration) {
|
||||
clearInterval(this.playTimeout)
|
||||
this.animation = false
|
||||
this.recorderStatus = 6
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
|
||||
submit() {
|
||||
alert('功能研发中,敬请期待...')
|
||||
},
|
||||
},
|
||||
const submit = () => {
|
||||
alert('功能研发中,敬请期待...')
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -39,53 +39,52 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ServeFindSysEmoticon, ServeSetUserEmoticon } from '@/api/emoticon'
|
||||
import { useEmoticonStore } from '@/stores/emoticon'
|
||||
|
||||
export default {
|
||||
name: 'MeEditorSystemEmoticon',
|
||||
data() {
|
||||
return {
|
||||
items: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadSysEmoticon()
|
||||
},
|
||||
methods: {
|
||||
closeBox() {
|
||||
this.$emit('close')
|
||||
},
|
||||
defineOptions({ name: 'MeEditorSystemEmoticon' })
|
||||
|
||||
// 获取系统表情包列表
|
||||
loadSysEmoticon() {
|
||||
ServeFindSysEmoticon().then(res => {
|
||||
if (res.code == 200) {
|
||||
this.items = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
setEmoticon(index, item, type) {
|
||||
ServeSetUserEmoticon({
|
||||
emoticon_id: item.id,
|
||||
type: type,
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
if (type == 1) {
|
||||
this.items[index].status = 1
|
||||
this.$store.commit('APPEND_SYS_EMOTICON', res.data)
|
||||
} else {
|
||||
this.items[index].status = 0
|
||||
this.$store.commit('REMOVE_SYS_EMOTICON', {
|
||||
emoticon_id: item.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
const emoticonStore = useEmoticonStore()
|
||||
|
||||
const items = ref([])
|
||||
|
||||
function closeBox() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 获取系统表情包列表
|
||||
function loadSysEmoticon() {
|
||||
ServeFindSysEmoticon().then(res => {
|
||||
if (res.code == 200) {
|
||||
items.value = res.data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setEmoticon(index, item, type) {
|
||||
ServeSetUserEmoticon({
|
||||
emoticon_id: item.id,
|
||||
type: type,
|
||||
}).then(res => {
|
||||
if (res.code == 200) {
|
||||
if (type == 1) {
|
||||
items.value[index].status = 1
|
||||
emoticonStore.APPEND_SYS_EMOTICON(res.data)
|
||||
} else {
|
||||
items.value[index].status = 0
|
||||
emoticonStore.REMOVE_SYS_EMOTICON({
|
||||
emoticon_id: item.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
loadSysEmoticon()
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.lum-dialog-box {
|
||||
|
||||
@@ -69,95 +69,100 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { ServeSendVote } from '@/api/chat'
|
||||
import { ElNotification } from '@/utils/message'
|
||||
import { useDialogueStore } from '@/stores/dialogue'
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: 'MeEditorVote',
|
||||
props: {
|
||||
group_id: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
mode: 0,
|
||||
title: '',
|
||||
options: [
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isCheck() {
|
||||
if (this.title == '') return true
|
||||
})
|
||||
|
||||
return this.options.some(option => option.value == '')
|
||||
},
|
||||
const props = defineProps({
|
||||
group_id: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
let items = []
|
||||
const { receiver_id } = this.$store.state.dialogue
|
||||
this.options.forEach(option => {
|
||||
items.push(option.value)
|
||||
})
|
||||
})
|
||||
|
||||
this.loading = true
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
ServeSendVote({
|
||||
receiver_id,
|
||||
mode: this.mode,
|
||||
title: this.title,
|
||||
options: items,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
this.$emit('close')
|
||||
this.$notify({
|
||||
title: '友情提示',
|
||||
message: '发起投票成功!',
|
||||
type: 'success',
|
||||
})
|
||||
} else {
|
||||
this.$notify({
|
||||
title: '友情提示',
|
||||
message: res.message,
|
||||
type: 'warning',
|
||||
})
|
||||
}
|
||||
const dialogueStore = useDialogueStore()
|
||||
|
||||
const loading = ref(false)
|
||||
const mode = ref(0)
|
||||
const title = ref('')
|
||||
const options = ref([
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
value: '',
|
||||
},
|
||||
])
|
||||
|
||||
const isCheck = computed(() => {
|
||||
if (title.value == '') return true
|
||||
|
||||
return options.value.some(option => option.value == '')
|
||||
})
|
||||
|
||||
function submit() {
|
||||
let items = []
|
||||
const { receiver_id } = dialogueStore
|
||||
options.value.forEach(option => {
|
||||
items.push(option.value)
|
||||
})
|
||||
|
||||
loading.value = true
|
||||
|
||||
ServeSendVote({
|
||||
receiver_id,
|
||||
mode: mode.value,
|
||||
title: title.value,
|
||||
options: items,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
emit('close')
|
||||
ElNotification({
|
||||
title: '友情提示',
|
||||
message: '发起投票成功!',
|
||||
type: 'success',
|
||||
})
|
||||
.catch(() => {
|
||||
this.loading = false
|
||||
} else {
|
||||
ElNotification({
|
||||
title: '友情提示',
|
||||
message: res.message,
|
||||
type: 'warning',
|
||||
})
|
||||
},
|
||||
addOption() {
|
||||
if (this.options.length >= 6) {
|
||||
return false
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
this.options.push({
|
||||
value: '',
|
||||
})
|
||||
},
|
||||
removeOption(index) {
|
||||
if (this.options.length <= 2) {
|
||||
return false
|
||||
}
|
||||
function addOption() {
|
||||
if (options.value.length >= 6) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.options.splice(index, 1)
|
||||
},
|
||||
},
|
||||
options.value.push({
|
||||
value: '',
|
||||
})
|
||||
}
|
||||
|
||||
function removeOption(index) {
|
||||
if (options.value.length <= 2) {
|
||||
return false
|
||||
}
|
||||
|
||||
options.value.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
<img :src="'https://avatars.dicebear.com/api/initials/'+text+'.svg?fontSize=38'" alt=""/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props:{
|
||||
text:{
|
||||
type:null,
|
||||
default:''
|
||||
}
|
||||
<script setup>
|
||||
defineProps({
|
||||
text:{
|
||||
type:null,
|
||||
default:''
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -2,19 +2,17 @@
|
||||
<img :src="text || 'https://avatars.dicebear.com/api/initials/'+name+'.svg?fontSize=38'" alt=""/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props:{
|
||||
text:{
|
||||
type:null,
|
||||
default:''
|
||||
},
|
||||
name:{
|
||||
type:null,
|
||||
default:''
|
||||
},
|
||||
}
|
||||
}
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
text: {
|
||||
type: null,
|
||||
default: ''
|
||||
},
|
||||
name: {
|
||||
type: null,
|
||||
default: ''
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -7,27 +7,23 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { noOncallImage } from "@/assets/images";
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: 'Empty',
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '数据为空...',
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
default: noOncallImage,
|
||||
},
|
||||
})
|
||||
|
||||
defineProps({
|
||||
text: {
|
||||
type: String,
|
||||
default: '数据为空...',
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
src: {
|
||||
type: String,
|
||||
default: noOncallImage,
|
||||
},
|
||||
created() {},
|
||||
methods: {},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.empty-content {
|
||||
|
||||
@@ -4,22 +4,21 @@
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { resolveLegacyIcon } from "@/core/legacy-icon-map";
|
||||
|
||||
export default {
|
||||
defineOptions({
|
||||
name: "LegacyElIcon",
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
computed: {
|
||||
iconComponent() {
|
||||
return resolveLegacyIcon(this.name);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const iconComponent = computed(() => resolveLegacyIcon(props.name));
|
||||
</script>
|
||||
|
||||
@@ -12,16 +12,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Loading',
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '数据加载中 ...',
|
||||
},
|
||||
<script setup>
|
||||
defineOptions({ name: 'Loading' })
|
||||
|
||||
defineProps({
|
||||
text: {
|
||||
type: String,
|
||||
default: '数据加载中 ...',
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.loading-content {
|
||||
|
||||
@@ -10,29 +10,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.getNum() <= 2) {
|
||||
setTimeout(() => {
|
||||
this.isShow = true
|
||||
}, 1000 * 60 * 2)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNum() {
|
||||
return parseInt(sessionStorage.getItem('ABS_BOX')) || 0
|
||||
},
|
||||
close() {
|
||||
sessionStorage.setItem('ABS_BOX', this.getNum() + 1)
|
||||
this.isShow = false
|
||||
},
|
||||
},
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const isShow = ref(false);
|
||||
|
||||
const getNum = () => {
|
||||
return parseInt(sessionStorage.getItem("ABS_BOX")) || 0;
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
sessionStorage.setItem("ABS_BOX", getNum() + 1);
|
||||
isShow.value = false;
|
||||
};
|
||||
|
||||
if (getNum() <= 2) {
|
||||
setTimeout(() => {
|
||||
isShow.value = true;
|
||||
}, 1000 * 60 * 2);
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -89,113 +89,113 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { VueCropper } from 'vue-cropper'
|
||||
import { ServeUploadFileStream } from '@/api/upload'
|
||||
import { ElMessage } from '@/utils/message'
|
||||
|
||||
export default {
|
||||
name: 'AvatarCropper',
|
||||
components: {
|
||||
VueCropper,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cusPreviewsImg: '',
|
||||
previews: {},
|
||||
option: {
|
||||
img: '',
|
||||
size: 1,
|
||||
full: false,
|
||||
outputType: 'png',
|
||||
canMove: true,
|
||||
fixedBox: true,
|
||||
original: false,
|
||||
canMoveBox: true,
|
||||
autoCrop: true,
|
||||
// 只有自动截图开启 宽度高度才生效
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 150,
|
||||
centerBox: false,
|
||||
high: true,
|
||||
},
|
||||
fixed: true,
|
||||
fixedNumber: [1, 1],
|
||||
defineOptions({ name: 'AvatarCropper' })
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const cropper = ref(null)
|
||||
const fileInput = ref(null)
|
||||
|
||||
const cusPreviewsImg = ref('')
|
||||
const previews = ref({})
|
||||
const option = reactive({
|
||||
img: '',
|
||||
size: 1,
|
||||
full: false,
|
||||
outputType: 'png',
|
||||
canMove: true,
|
||||
fixedBox: true,
|
||||
original: false,
|
||||
canMoveBox: true,
|
||||
autoCrop: true,
|
||||
// 只有自动截图开启 宽度高度才生效
|
||||
autoCropWidth: 200,
|
||||
autoCropHeight: 150,
|
||||
centerBox: false,
|
||||
high: true,
|
||||
})
|
||||
const fixed = ref(true)
|
||||
const fixedNumber = ref([1, 1])
|
||||
|
||||
function clickUpload() {
|
||||
fileInput.value.click()
|
||||
}
|
||||
function clearCrop() {
|
||||
if (!cusPreviewsImg.value) return false
|
||||
cropper.value.clearCrop()
|
||||
}
|
||||
function refreshCrop() {
|
||||
if (!cusPreviewsImg.value) return false
|
||||
cropper.value.refresh()
|
||||
}
|
||||
function rotateLeft() {
|
||||
if (!cusPreviewsImg.value) return false
|
||||
cropper.value.rotateLeft()
|
||||
}
|
||||
function rotateRight() {
|
||||
if (!cusPreviewsImg.value) return false
|
||||
cropper.value.rotateRight()
|
||||
}
|
||||
// 实时预览函数
|
||||
function realTime() {
|
||||
cropper.value.getCropData(img => {
|
||||
cusPreviewsImg.value = img
|
||||
})
|
||||
}
|
||||
|
||||
// 上传回调事件
|
||||
function uploadImg(e, num) {
|
||||
let file = e.target.files[0]
|
||||
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
|
||||
ElMessage('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
|
||||
return false
|
||||
}
|
||||
|
||||
let reader = new FileReader()
|
||||
reader.onload = e => {
|
||||
let data
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
data = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
data = e.target.result
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
clickUpload() {
|
||||
this.$refs.fileInput.click()
|
||||
},
|
||||
clearCrop() {
|
||||
if (!this.cusPreviewsImg) return false
|
||||
this.$refs.cropper.clearCrop()
|
||||
},
|
||||
refreshCrop() {
|
||||
if (!this.cusPreviewsImg) return false
|
||||
this.$refs.cropper.refresh()
|
||||
},
|
||||
rotateLeft() {
|
||||
if (!this.cusPreviewsImg) return false
|
||||
this.$refs.cropper.rotateLeft()
|
||||
},
|
||||
rotateRight() {
|
||||
if (!this.cusPreviewsImg) return false
|
||||
this.$refs.cropper.rotateRight()
|
||||
},
|
||||
// 实时预览函数
|
||||
realTime() {
|
||||
this.$refs.cropper.getCropData(img => {
|
||||
this.cusPreviewsImg = img
|
||||
})
|
||||
},
|
||||
if (num === 1) {
|
||||
option.img = data
|
||||
} else if (num === 2) {
|
||||
// 历史遗留 bug:example2 从未定义,原样保留(此分支实际不可达,num 恒为 1)
|
||||
// eslint-disable-next-line no-undef
|
||||
example2.img = data
|
||||
}
|
||||
}
|
||||
// 转化为base64
|
||||
// reader.readAsDataURL(file)
|
||||
// 转化为blob
|
||||
reader.readAsArrayBuffer(file)
|
||||
}
|
||||
|
||||
// 上传回调事件
|
||||
uploadImg(e, num) {
|
||||
let file = e.target.files[0]
|
||||
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
|
||||
this.$message('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
|
||||
return false
|
||||
// 上传图片到服务器
|
||||
function uploadService() {
|
||||
if (cusPreviewsImg.value == '') return
|
||||
ServeUploadFileStream({
|
||||
fileStream: cusPreviewsImg.value,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
emit('close', 1, res.data.avatar)
|
||||
} else {
|
||||
ElMessage('文件上传失败,请稍后再试...')
|
||||
}
|
||||
|
||||
let reader = new FileReader()
|
||||
reader.onload = e => {
|
||||
let data
|
||||
if (typeof e.target.result === 'object') {
|
||||
// 把Array Buffer转化为blob 如果是base64不需要
|
||||
data = window.URL.createObjectURL(new Blob([e.target.result]))
|
||||
} else {
|
||||
data = e.target.result
|
||||
}
|
||||
if (num === 1) {
|
||||
this.option.img = data
|
||||
} else if (num === 2) {
|
||||
this.example2.img = data
|
||||
}
|
||||
}
|
||||
// 转化为base64
|
||||
// reader.readAsDataURL(file)
|
||||
// 转化为blob
|
||||
reader.readAsArrayBuffer(file)
|
||||
},
|
||||
|
||||
// 上传图片到服务器
|
||||
uploadService() {
|
||||
if (this.cusPreviewsImg == '') return
|
||||
ServeUploadFileStream({
|
||||
fileStream: this.cusPreviewsImg,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
this.$emit('close', 1, res.data.avatar)
|
||||
} else {
|
||||
this.$message('文件上传失败,请稍后再试...')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message('文件上传失败,请稍后再试...')
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage('文件上传失败,请稍后再试...')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -25,29 +25,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.getNum() <= 3) {
|
||||
setTimeout(() => {
|
||||
this.isShow = true
|
||||
}, 1000 * 30)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNum() {
|
||||
return parseInt(localStorage.getItem('REWARD_BOX')) || 0
|
||||
},
|
||||
close() {
|
||||
localStorage.setItem('REWARD_BOX', this.getNum() + 1)
|
||||
this.isShow = false
|
||||
},
|
||||
},
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const isShow = ref(false)
|
||||
|
||||
function getNum() {
|
||||
return parseInt(localStorage.getItem('REWARD_BOX')) || 0
|
||||
}
|
||||
|
||||
function close() {
|
||||
localStorage.setItem('REWARD_BOX', getNum() + 1)
|
||||
isShow.value = false
|
||||
}
|
||||
|
||||
// created
|
||||
if (getNum() <= 3) {
|
||||
setTimeout(() => {
|
||||
isShow.value = true
|
||||
}, 1000 * 30)
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -2,37 +2,31 @@
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
// 待开发
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
skins: [
|
||||
{
|
||||
theme: '',
|
||||
class: 'default',
|
||||
text: '默认',
|
||||
},
|
||||
{
|
||||
theme: '',
|
||||
class: 'red',
|
||||
text: '红色',
|
||||
},
|
||||
{
|
||||
theme: '',
|
||||
class: 'dark',
|
||||
text: '暗黑',
|
||||
},
|
||||
{
|
||||
theme: '',
|
||||
class: 'blue',
|
||||
text: '浅蓝',
|
||||
},
|
||||
],
|
||||
}
|
||||
import { ref } from "vue";
|
||||
|
||||
const skins = ref([
|
||||
{
|
||||
theme: "",
|
||||
class: "default",
|
||||
text: "默认",
|
||||
},
|
||||
created() {},
|
||||
methods: {},
|
||||
}
|
||||
{
|
||||
theme: "",
|
||||
class: "red",
|
||||
text: "红色",
|
||||
},
|
||||
{
|
||||
theme: "",
|
||||
class: "dark",
|
||||
text: "暗黑",
|
||||
},
|
||||
{
|
||||
theme: "",
|
||||
class: "blue",
|
||||
text: "浅蓝",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -6,15 +6,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
created () { },
|
||||
methods: {},
|
||||
}
|
||||
<script setup>
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.welcome-box {
|
||||
|
||||
@@ -17,29 +17,23 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
params: {
|
||||
type: Object,
|
||||
default() {},
|
||||
},
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
params: {
|
||||
type: Object,
|
||||
default() {},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
avatar:
|
||||
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||
talk_type: 1,
|
||||
nickname: '阿萨纳斯卡',
|
||||
content: '阿斯纳俺家你卡萨啊看看番按实际开发n',
|
||||
datetime: '2021-06-18 23:15:12',
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {},
|
||||
created() {},
|
||||
}
|
||||
})
|
||||
|
||||
const avatar = ref(
|
||||
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png'
|
||||
)
|
||||
const talk_type = ref(1)
|
||||
const nickname = ref('阿萨纳斯卡')
|
||||
const content = ref('阿斯纳俺家你卡萨啊看看番按实际开发n')
|
||||
const datetime = ref('2021-06-18 23:15:12')
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.notify-box {
|
||||
|
||||
@@ -19,43 +19,36 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { parseTime } from '@/utils/functions'
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
avatar: {
|
||||
type: String,
|
||||
default:
|
||||
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||
},
|
||||
talk_type: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
nickname: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
datetime: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
defineProps({
|
||||
avatar: {
|
||||
type: String,
|
||||
default:
|
||||
'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
talk_type: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
methods: {
|
||||
formatTime(datetime) {
|
||||
datetime = datetime || new Date()
|
||||
return parseTime(datetime, '{m}/{d} {h}:{i} 分')
|
||||
},
|
||||
nickname: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
datetime: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const formatTime = (datetime) => {
|
||||
datetime = datetime || new Date()
|
||||
return parseTime(datetime, '{m}/{d} {h}:{i} 分')
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -3,32 +3,33 @@
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'svg-icon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
defineOptions({ name: 'svg-icon' })
|
||||
|
||||
const props = defineProps({
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const iconName = computed(() => {
|
||||
return `#icon-${props.iconClass}`
|
||||
})
|
||||
|
||||
const svgClass = computed(() => {
|
||||
if (props.className) {
|
||||
return 'svg-icon ' + props.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
|
||||
@@ -34,57 +34,55 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, nextTick, getCurrentInstance } from 'vue'
|
||||
import { ServeSearchContact } from '@/api/contacts'
|
||||
|
||||
export default {
|
||||
name: 'UserSearch',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
isShow: false,
|
||||
mobile: '',
|
||||
error: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 显示窗口
|
||||
open() {
|
||||
this.mobile = ''
|
||||
this.isShow = true
|
||||
this.$nextTick(() => {
|
||||
document.getElementById('serach-mobile').focus()
|
||||
})
|
||||
},
|
||||
defineOptions({ name: 'UserSearch' })
|
||||
|
||||
// 关闭窗口
|
||||
close() {
|
||||
this.isShow = false
|
||||
},
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
onSubmit() {
|
||||
let { mobile } = this
|
||||
const loading = ref(false)
|
||||
const isShow = ref(false)
|
||||
const mobile = ref('')
|
||||
const error = ref(false)
|
||||
|
||||
if (mobile == '') return false
|
||||
|
||||
this.loading = true
|
||||
ServeSearchContact({
|
||||
mobile,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
this.$user(res.data.id)
|
||||
this.close()
|
||||
} else {
|
||||
this.error = true
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
// 显示窗口
|
||||
const open = () => {
|
||||
mobile.value = ''
|
||||
isShow.value = true
|
||||
nextTick(() => {
|
||||
document.getElementById('serach-mobile').focus()
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭窗口
|
||||
const close = () => {
|
||||
isShow.value = false
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
if (mobile.value == '') return false
|
||||
|
||||
loading.value = true
|
||||
ServeSearchContact({
|
||||
mobile: mobile.value,
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code == 200) {
|
||||
proxy.$user(res.data.id)
|
||||
close()
|
||||
} else {
|
||||
error.value = true
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 父组件通过 ref 调用 open()(im/src/views/message/index.vue)
|
||||
defineExpose({ open, close })
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.lum-dialog-box {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="user-header">
|
||||
<div class="avatar">
|
||||
<div class="avatar-box">
|
||||
<img :src="detail.avatar" :onerror="$store.state.defaultAvatar" />
|
||||
<img :src="detail.avatar" :onerror="appStore.defaultAvatar" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="nickname">
|
||||
@@ -121,136 +121,141 @@
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
// import { ServeSearchUser } from "@/api/user";
|
||||
import { reactive, ref } from "vue";
|
||||
import { ServeCreateContact, ServeEditContactRemark } from "@/api/contacts";
|
||||
import { toTalk } from "@/utils/talk";
|
||||
import { defaultUserBanner } from "@/assets/images";
|
||||
import { ElMessage } from "@/utils/message";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
|
||||
export default {
|
||||
name: "UserCardDetail",
|
||||
props: {
|
||||
user_id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
defineOptions({ name: "UserCardDetail" });
|
||||
|
||||
const props = defineProps({
|
||||
user_id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
detail: {
|
||||
mobile: "",
|
||||
nickname: "",
|
||||
avatar: "",
|
||||
motto: "",
|
||||
friend_status: 0,
|
||||
friend_apply: 0,
|
||||
nickname_remark: "",
|
||||
bag: defaultUserBanner,
|
||||
gender: 0,
|
||||
},
|
||||
});
|
||||
|
||||
// 好友备注表单
|
||||
editRemark: {
|
||||
isShow: false,
|
||||
text: "",
|
||||
},
|
||||
const emit = defineEmits(["close", "changeRemark"]);
|
||||
|
||||
// 好友申请表单
|
||||
apply: {
|
||||
isShow: false,
|
||||
text: "",
|
||||
},
|
||||
const appStore = useAppStore();
|
||||
|
||||
contacts: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// this.loadUserDetail();
|
||||
},
|
||||
methods: {
|
||||
formatGender(value) {
|
||||
const arr = ["未知", "男", "女"];
|
||||
return arr[value] || "未知";
|
||||
},
|
||||
formatMobile(value) {
|
||||
if (!value) return "";
|
||||
return (
|
||||
value.substr(0, 3) + " " + value.substr(3, 4) + " " + value.substr(7, 4)
|
||||
);
|
||||
},
|
||||
close() {
|
||||
if (this.contacts) return false;
|
||||
const detail = reactive({
|
||||
mobile: "",
|
||||
nickname: "",
|
||||
avatar: "",
|
||||
motto: "",
|
||||
friend_status: 0,
|
||||
friend_apply: 0,
|
||||
nickname_remark: "",
|
||||
bag: defaultUserBanner,
|
||||
gender: 0,
|
||||
});
|
||||
|
||||
this.$emit("close");
|
||||
},
|
||||
// 好友备注表单
|
||||
const editRemark = reactive({
|
||||
isShow: false,
|
||||
text: "",
|
||||
});
|
||||
|
||||
// 点击编辑备注信息
|
||||
clickEditRemark() {
|
||||
this.editRemark.isShow = true;
|
||||
this.editRemark.text = this.detail.nickname_remark;
|
||||
},
|
||||
// 好友申请表单
|
||||
const apply = reactive({
|
||||
isShow: false,
|
||||
text: "",
|
||||
});
|
||||
|
||||
// 获取用户信息
|
||||
// loadUserDetail() {
|
||||
// ServeSearchUser({
|
||||
// user_id: this.user_id,
|
||||
// }).then((res) => {
|
||||
// if (res.code == 200) {
|
||||
// this.detail.user_id = res.data.id;
|
||||
// Object.assign(this.detail, res.data);
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
const contacts = ref(false);
|
||||
|
||||
// 发送添加好友申请
|
||||
sendApply() {
|
||||
if (this.apply.text == "") return;
|
||||
ServeCreateContact({
|
||||
friend_id: this.detail.user_id,
|
||||
remark: this.apply.text,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.apply.isShow = false;
|
||||
this.apply.text = "";
|
||||
this.detail.friend_apply = 1;
|
||||
} else {
|
||||
this.$message.error("发送好友申请失败,请稍后再试...");
|
||||
}
|
||||
});
|
||||
},
|
||||
// created() {
|
||||
// loadUserDetail();
|
||||
// }
|
||||
|
||||
// 编辑好友备注信息
|
||||
editRemarkSubmit() {
|
||||
let data = {
|
||||
friend_id: this.detail.user_id,
|
||||
remarks: this.editRemark.text,
|
||||
};
|
||||
const formatGender = (value) => {
|
||||
const arr = ["未知", "男", "女"];
|
||||
return arr[value] || "未知";
|
||||
};
|
||||
|
||||
if (data.remarks == this.detail.nickname_remark) {
|
||||
this.editRemark.isShow = false;
|
||||
return;
|
||||
}
|
||||
const formatMobile = (value) => {
|
||||
if (!value) return "";
|
||||
return (
|
||||
value.substr(0, 3) + " " + value.substr(3, 4) + " " + value.substr(7, 4)
|
||||
);
|
||||
};
|
||||
|
||||
ServeEditContactRemark(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.editRemark.isShow = false;
|
||||
this.detail.nickname_remark = data.remarks;
|
||||
this.$emit("changeRemark", data);
|
||||
}
|
||||
});
|
||||
},
|
||||
const close = () => {
|
||||
if (contacts.value) return false;
|
||||
|
||||
// 隐藏申请表单
|
||||
closeApply() {
|
||||
this.apply.isShow = false;
|
||||
},
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 发送好友消息
|
||||
sendMessage() {
|
||||
this.close();
|
||||
toTalk(1, this.user_id);
|
||||
},
|
||||
},
|
||||
// 点击编辑备注信息
|
||||
const clickEditRemark = () => {
|
||||
editRemark.isShow = true;
|
||||
editRemark.text = detail.nickname_remark;
|
||||
};
|
||||
|
||||
// 获取用户信息
|
||||
// const loadUserDetail = () => {
|
||||
// ServeSearchUser({
|
||||
// user_id: props.user_id,
|
||||
// }).then((res) => {
|
||||
// if (res.code == 200) {
|
||||
// detail.user_id = res.data.id;
|
||||
// Object.assign(detail, res.data);
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
// 发送添加好友申请
|
||||
const sendApply = () => {
|
||||
if (apply.text == "") return;
|
||||
ServeCreateContact({
|
||||
friend_id: detail.user_id,
|
||||
remark: apply.text,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
apply.isShow = false;
|
||||
apply.text = "";
|
||||
detail.friend_apply = 1;
|
||||
} else {
|
||||
ElMessage.error("发送好友申请失败,请稍后再试...");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑好友备注信息
|
||||
const editRemarkSubmit = () => {
|
||||
let data = {
|
||||
friend_id: detail.user_id,
|
||||
remarks: editRemark.text,
|
||||
};
|
||||
|
||||
if (data.remarks == detail.nickname_remark) {
|
||||
editRemark.isShow = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ServeEditContactRemark(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
editRemark.isShow = false;
|
||||
detail.nickname_remark = data.remarks;
|
||||
emit("changeRemark", data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 隐藏申请表单
|
||||
const closeApply = () => {
|
||||
apply.isShow = false;
|
||||
};
|
||||
|
||||
// 发送好友消息
|
||||
const sendMessage = () => {
|
||||
close();
|
||||
toTalk(1, props.user_id);
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createApp, h } from "vue";
|
||||
import UserCardDetail from "./UserCardDetail";
|
||||
import router from "@/router";
|
||||
import store from "@/store";
|
||||
import { createPinia } from "pinia";
|
||||
import { setupElementPlus } from "@/plugins/element";
|
||||
import { setupLegacyMessage } from "@/utils/message";
|
||||
import { registerDirectives } from "@/core/directives";
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
cardApp.component("legacy-el-icon", LegacyElIcon);
|
||||
cardApp.config.globalProperties.$legacyIcon = resolveLegacyIcon;
|
||||
cardApp.use(router);
|
||||
cardApp.use(store);
|
||||
cardApp.use(createPinia());
|
||||
cardApp.mount(container);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import store from "@/store";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
import router from "@/router";
|
||||
import { ElNotification } from "element-plus";
|
||||
|
||||
@@ -10,20 +11,15 @@ class Base {
|
||||
this.$notify = ElNotification;
|
||||
}
|
||||
|
||||
getStoreInstance() {
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的ID
|
||||
*/
|
||||
getAccountId() {
|
||||
// console.log("store.state", store.state.user);
|
||||
return store.state.user.id;
|
||||
return useUserStore().id;
|
||||
}
|
||||
|
||||
getTalkParams() {
|
||||
let { talk_type, receiver_id, index_name } = store.state.dialogue;
|
||||
let { talk_type, receiver_id, index_name } = useDialogueStore();
|
||||
|
||||
return { talk_type, receiver_id, index_name };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Base from './base'
|
||||
import store from '@/store'
|
||||
import { useNotifyStore } from '@/stores/notify'
|
||||
import router from '@/router'
|
||||
|
||||
/**
|
||||
@@ -23,7 +23,7 @@ class FriendApply extends Base {
|
||||
}
|
||||
|
||||
handle() {
|
||||
store.commit('INCR_APPLY_NUM')
|
||||
useNotifyStore().INCR_APPLY_NUM()
|
||||
|
||||
this.$notify({
|
||||
title: '好友申请',
|
||||
@@ -33,7 +33,7 @@ class FriendApply extends Base {
|
||||
type: 'info',
|
||||
customClass: 'pointer',
|
||||
onClick: function() {
|
||||
store.commit('SET_APPLY_NUM', 0)
|
||||
useNotifyStore().SET_APPLY_NUM(0)
|
||||
router.push({
|
||||
path: '/contacts/apply',
|
||||
query: { t: new Date().getTime() },
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Base from './base'
|
||||
import { useNotifyStore } from '@/stores/notify'
|
||||
|
||||
/**
|
||||
* 键盘输入事件
|
||||
@@ -38,9 +39,7 @@ class Keyboard extends Base {
|
||||
return false
|
||||
}
|
||||
|
||||
let store = this.getStoreInstance()
|
||||
|
||||
store.commit('UPDATE_KEYBOARD_EVENT')
|
||||
useNotifyStore().UPDATE_KEYBOARD_EVENT()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Base from './base'
|
||||
import { useNotifyStore } from '@/stores/notify'
|
||||
|
||||
/**
|
||||
* 好友状态事件
|
||||
@@ -21,7 +22,7 @@ class Login extends Base {
|
||||
}
|
||||
|
||||
handle() {
|
||||
this.getStoreInstance().dispatch('ACT_UPDATE_FRIEND_STATUS', {
|
||||
useNotifyStore().ACT_UPDATE_FRIEND_STATUS({
|
||||
status: this.resource.status,
|
||||
friend_id: parseInt(this.resource.user_id),
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Base from './base'
|
||||
import store from '@/store'
|
||||
import { useDialogueStore } from '@/stores/dialogue'
|
||||
|
||||
/**
|
||||
* 好友邀请消息处理
|
||||
@@ -32,7 +32,7 @@ class Revoke extends Base {
|
||||
return false
|
||||
}
|
||||
|
||||
store.commit('UPDATE_DIALOGUE', {
|
||||
useDialogueStore().UPDATE_DIALOGUE({
|
||||
id: this.resource.record_id,
|
||||
is_revoke: 1,
|
||||
})
|
||||
|
||||
@@ -5,6 +5,9 @@ import NewMessageNotify from "@/components/notify/NewMessageNotify";
|
||||
import { ServeClearTalkUnreadNum, ServeCreateTalkList } from "@/api/chat";
|
||||
import { formatTalkItem, findTalkIndex, toTalk } from "@/utils/talk";
|
||||
import { parseTime } from "@/utils/functions";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
import { useNotifyStore } from "@/stores/notify";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
|
||||
import mixin from '@/mixins/main-mixin'
|
||||
/**
|
||||
@@ -44,9 +47,9 @@ class Talk extends Base {
|
||||
|
||||
this.resource = resource;
|
||||
|
||||
// 判断发送者消息是否在当前用户列表中
|
||||
// 判断发送者消息是否在当前用户列表中
|
||||
const bridge = getAppBridge();
|
||||
if (this.sender_id && !bridge.$store.state.talks.items.find(item => {
|
||||
if (this.sender_id && !useTalkStore().items.find(item => {
|
||||
return item.userId == this.sender_id
|
||||
})) {
|
||||
bridge.loadUserSetting('update')
|
||||
@@ -108,11 +111,10 @@ class Talk extends Base {
|
||||
}
|
||||
|
||||
handle () {
|
||||
let store = this.getStoreInstance();
|
||||
// console.log("触发handle");
|
||||
// 判断当前是否在聊天页面
|
||||
if (!this.isTalkPage()) {
|
||||
store.commit("INCR_UNREAD_NUM");
|
||||
useNotifyStore().INCR_UNREAD_NUM();
|
||||
|
||||
// 判断消息是否来自于我自己,否则会提示消息通知
|
||||
return !this.isCurrSender() && this.showMessageNocice();
|
||||
@@ -181,7 +183,7 @@ class Talk extends Base {
|
||||
|
||||
ServeCreateTalkList(receiver_id).then(({ code, data }) => {
|
||||
if (code == 200) {
|
||||
this.getStoreInstance().commit("PUSH_TALK_ITEM", formatTalkItem(data));
|
||||
useTalkStore().PUSH_TALK_ITEM(formatTalkItem(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -190,13 +192,14 @@ class Talk extends Base {
|
||||
* 插入对话记录
|
||||
*/
|
||||
insertTalkRecord () {
|
||||
let store = this.getStoreInstance();
|
||||
const talkStore = useTalkStore();
|
||||
const dialogueStore = useDialogueStore();
|
||||
let record = this.resource;
|
||||
// console.log("插入谈话记录", record);
|
||||
|
||||
record.float = this.getFloatType();
|
||||
|
||||
store.commit("PUSH_DIALOGUE", record);
|
||||
dialogueStore.PUSH_DIALOGUE(record);
|
||||
|
||||
// 获取聊天面板元素节点
|
||||
let el = document.getElementById("lumenChatPanel");
|
||||
@@ -214,14 +217,14 @@ class Talk extends Base {
|
||||
});
|
||||
} else {
|
||||
// console.log("%c SET_TLAK_UNREAD_MESSAGE %c", "color:red");
|
||||
store.commit("SET_TLAK_UNREAD_MESSAGE", {
|
||||
talkStore.SET_TLAK_UNREAD_MESSAGE({
|
||||
content: this.getTalkText(),
|
||||
nickname: record.name,
|
||||
});
|
||||
}
|
||||
// console.log("%c 准备更新...UPDATE_TALK_ITEM ", "color:red");
|
||||
|
||||
store.commit("UPDATE_TALK_ITEM", {
|
||||
talkStore.UPDATE_TALK_ITEM({
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.getTalkText() || record.text,
|
||||
updated_at: parseTime(new Date()),
|
||||
@@ -240,11 +243,9 @@ class Talk extends Base {
|
||||
* 更新对话列表记录
|
||||
*/
|
||||
updateTalkItem () {
|
||||
let store = this.getStoreInstance();
|
||||
useNotifyStore().INCR_UNREAD_NUM();
|
||||
|
||||
store.commit("INCR_UNREAD_NUM");
|
||||
|
||||
store.commit("UPDATE_TALK_MESSAGE", {
|
||||
useTalkStore().UPDATE_TALK_MESSAGE({
|
||||
index_name: this.getIndexName(),
|
||||
msg_text: this.getTalkText(),
|
||||
updated_at: parseTime(new Date()),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import store from "@/store";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import config from "@/config/config";
|
||||
import WsSocket from "@/plugins/ws-socket";
|
||||
import { getToken } from "@/utils/auth";
|
||||
@@ -100,7 +100,7 @@ class SocketInstance {
|
||||
* @param {Boolean} status 连接状态
|
||||
*/
|
||||
updateSocketStatus (status) {
|
||||
store.commit("UPDATE_SOCKET_STATUS", status);
|
||||
useAppStore().UPDATE_SOCKET_STATUS(status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import "core-js/stable";
|
||||
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import App from "@/App.vue";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import MainMixin from "./mixins/main-mixin";
|
||||
import face from "@/components/face";
|
||||
@@ -30,7 +30,7 @@ registerDirectives(app);
|
||||
registerGlobalComponents(app);
|
||||
registerIcons(app);
|
||||
|
||||
app.use(store);
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
setupContextmenu(app);
|
||||
app.use(VueVirtualScroller);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import SocketInstance from "@/im-server/socket-instance";
|
||||
import { ServeGetUserSetting,ServeGetStoreSetting } from "@/api/user";
|
||||
import store from "@/store";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
import { useNotifyStore } from "@/stores/notify";
|
||||
import { ServeGetTalkList,ServeGetStoreTalkList } from "@/api/chat";
|
||||
import { formatTalkItem } from "@/utils/talk";
|
||||
export default {
|
||||
@@ -23,7 +25,7 @@ export default {
|
||||
return ServeGetUserSetting().then(async ({ code, result }) => {
|
||||
// 如果result有值说明用户创建成功
|
||||
if (result) {
|
||||
store.commit("UPDATE_USER_INFO", {
|
||||
useUserStore().UPDATE_USER_INFO({
|
||||
id: result.id,
|
||||
face: result.face,
|
||||
name: result.nickName,
|
||||
@@ -52,7 +54,7 @@ export default {
|
||||
//标识有值代表是店铺
|
||||
return ServeGetStoreSetting().then(async ({ code, result }) => {
|
||||
if (result) {
|
||||
store.commit("UPDATE_USER_INFO", {
|
||||
useUserStore().UPDATE_USER_INFO({
|
||||
id: result.id,
|
||||
face: result.storeLogo,
|
||||
name: result.storeName,
|
||||
@@ -77,8 +79,8 @@ export default {
|
||||
ServeGetTalkList()
|
||||
.then(({ code, result }) => {
|
||||
if (code !== 200) return false;
|
||||
store.commit("SET_UNREAD_NUM", 0);
|
||||
store.commit("SET_TALK_ITEMS", {
|
||||
useNotifyStore().SET_UNREAD_NUM(0);
|
||||
useTalkStore().SET_TALK_ITEMS({
|
||||
items: result.map((item) => formatTalkItem(item)),
|
||||
});
|
||||
let index_name = sessionStorage.getItem("send_message_index_name");
|
||||
@@ -97,8 +99,8 @@ export default {
|
||||
this.loadStatus = this.talkNum == 0 ? 0 : 1;
|
||||
return ServeGetStoreTalkList().then(({ code, result }) => {
|
||||
if (code !== 200 || !Array.isArray(result)) return false;
|
||||
this.$store.commit("SET_UNREAD_NUM", 0);
|
||||
this.$store.commit("SET_TALK_ITEMS", {
|
||||
useNotifyStore().SET_UNREAD_NUM(0);
|
||||
useTalkStore().SET_TALK_ITEMS({
|
||||
items: result.map((item) => formatTalkItem(item)),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ElNotification, ElMessageBox } from "element-plus";
|
||||
let wsSignIn; // ws 是否是掉线状态
|
||||
import store from "@/store";
|
||||
import { useDialogueStore } from "@/stores/dialogue";
|
||||
class WsSocket {
|
||||
/**
|
||||
* Websocket 连接
|
||||
@@ -81,7 +81,7 @@ class WsSocket {
|
||||
* 重连成功后关闭掉线提示,新增重连提示
|
||||
*/
|
||||
if (wsSignIn) {
|
||||
store.commit('SET_WS_STATUS',true);
|
||||
useDialogueStore().SET_WS_STATUS(true);
|
||||
wsSignIn.close();
|
||||
|
||||
ElNotification({
|
||||
@@ -106,7 +106,7 @@ class WsSocket {
|
||||
connect.onclose = this.onClose.bind(this);
|
||||
this.connect = connect;
|
||||
|
||||
store.commit('SET_WS_STATUS',false);
|
||||
useDialogueStore().SET_WS_STATUS(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +160,7 @@ class WsSocket {
|
||||
duration: 0,
|
||||
});
|
||||
// 掉线更改消息状态
|
||||
store.commit('SET_WS_STATUS',true);
|
||||
useDialogueStore().SET_WS_STATUS(true);
|
||||
let reconnect = this.config.reconnect;
|
||||
if (reconnect.lockReconnect || reconnect.number == 0) {
|
||||
return;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
const getters = {
|
||||
// 用户登录状态
|
||||
loginStatus: state => state.user.loginStatus,
|
||||
|
||||
// socket 连接状态
|
||||
socketStatus: state => state.socketStatus,
|
||||
}
|
||||
|
||||
export default getters
|
||||
@@ -1,30 +0,0 @@
|
||||
import { createStore } from "vuex";
|
||||
|
||||
import user from "./modules/user";
|
||||
import talks from "./modules/talk";
|
||||
import notify from "./modules/notify";
|
||||
import settings from "./modules/settings";
|
||||
import emoticon from "./modules/emoticon";
|
||||
import dialogue from "./modules/dialogue";
|
||||
import note from "./modules/note";
|
||||
|
||||
import state from "./state";
|
||||
import getters from "./getters";
|
||||
import mutations from "./mutations";
|
||||
|
||||
const store = createStore({
|
||||
modules: {
|
||||
user,
|
||||
notify,
|
||||
talks,
|
||||
settings,
|
||||
emoticon,
|
||||
dialogue,
|
||||
note,
|
||||
},
|
||||
state,
|
||||
getters,
|
||||
mutations,
|
||||
});
|
||||
|
||||
export default store;
|
||||
@@ -1,95 +0,0 @@
|
||||
export default {
|
||||
state: {
|
||||
// 对话来源[1:私聊;2:群聊]
|
||||
talk_type: 0,
|
||||
|
||||
// 接收者ID
|
||||
receiver_id: 0,
|
||||
|
||||
is_robot: 0,
|
||||
|
||||
// 聊天记录
|
||||
records: [
|
||||
{
|
||||
id: "",
|
||||
createTime: "",
|
||||
toUser: "",
|
||||
isRead: false,
|
||||
messageType: "",
|
||||
talkId: "",
|
||||
text: "",
|
||||
float: "",
|
||||
},
|
||||
],
|
||||
webSocketWithOut:false, // ws 是否是掉线 无输出状态
|
||||
// 对话索引(聊天对话的唯一索引)
|
||||
index_name: null,
|
||||
},
|
||||
mutations: {
|
||||
// 设置ws状态
|
||||
SET_WS_STATUS: (state,resource) =>{
|
||||
state.webSocketWithOut = resource
|
||||
},
|
||||
// 更新对话
|
||||
UPDATE_DIALOGUE_MESSAGE (state, resource) {
|
||||
state.records = [];
|
||||
state.talk_type = parseInt(resource.talk_type);
|
||||
state.receiver_id = parseInt(resource.receiver_id);
|
||||
state.is_robot = parseInt(resource.is_robot);
|
||||
|
||||
/**
|
||||
* receiver_id 就是 好友id
|
||||
* 比如 a 和 b 聊天 receiver_id = b的id
|
||||
*/
|
||||
state.index_name = (resource.talk_type || 1) + "_" + resource.receiver_id;
|
||||
},
|
||||
|
||||
// 数组头部压入对话记录1494593861786271744 1494593778193793024
|
||||
UNSHIFT_DIALOGUE (state, records) {
|
||||
// console.log("%c 数组头部压入对话记录", "color:green");
|
||||
// console.log("state", state);
|
||||
// console.log("records", records);
|
||||
if (state.records.length > 0) {
|
||||
state.records.unshift(...records);
|
||||
} else {
|
||||
state.records.push(...records);
|
||||
}
|
||||
|
||||
// console.log("最后的数据",state.records)
|
||||
},
|
||||
|
||||
// 推送对话记录
|
||||
PUSH_DIALOGUE (state, record) {
|
||||
record = {...record,webSocketStatus:state.webSocketWithOut}
|
||||
console.log("推送对话",)
|
||||
state.records.push(record);
|
||||
},
|
||||
|
||||
// 更新对话记录
|
||||
UPDATE_DIALOGUE (state, resource) {
|
||||
for (let i in state.records) {
|
||||
if (state.records[i].id === resource.id) {
|
||||
Object.assign(state.records[i], resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 删除对话记录
|
||||
DELETE_DIALOGUE (state, index) {
|
||||
state.records.splice(index, 1);
|
||||
},
|
||||
|
||||
BATCH_DELETE_DIALOGUE (state, ids) {
|
||||
ids.forEach((record_id) => {
|
||||
let index = state.records.findIndex((item) => item.id == record_id);
|
||||
if (index >= 0) state.records.splice(index, 1);
|
||||
});
|
||||
},
|
||||
|
||||
// 数组头部压入对话记录
|
||||
SET_DIALOGUE (state, records) {
|
||||
state.records = records;
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const Note = {
|
||||
state: {
|
||||
tags: [],
|
||||
class: [],
|
||||
},
|
||||
getters: {},
|
||||
mutations: {
|
||||
SET_NOTE_TAGS(state, tags) {
|
||||
state.tags = tags
|
||||
},
|
||||
|
||||
PUSH_NOTE_TAG(state, tag) {
|
||||
state.tags.unshift(tag)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default Note
|
||||
@@ -1,62 +0,0 @@
|
||||
export default {
|
||||
state: {
|
||||
// 聊天消息未读数
|
||||
unreadNum: 0,
|
||||
|
||||
// 好友申请未读数
|
||||
applyNum: 0,
|
||||
|
||||
// 好友键盘事件监听
|
||||
inputEvent: 0,
|
||||
|
||||
// 好友登录状态监听
|
||||
friendStatus: {
|
||||
// 登录状态[0:下线;1:在线;]
|
||||
status: 0,
|
||||
// 好友ID
|
||||
friend_id: 0,
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
// 消息未读数自增
|
||||
INCR_UNREAD_NUM(state) {
|
||||
console.log("触发消息未读")
|
||||
state.unreadNum++
|
||||
},
|
||||
|
||||
// 好友申请事件监听
|
||||
INCR_APPLY_NUM(state) {
|
||||
state.applyNum++
|
||||
},
|
||||
|
||||
// 设置消息未读数
|
||||
SET_UNREAD_NUM(state, value) {
|
||||
state.unreadNum = value
|
||||
},
|
||||
|
||||
// 好友申请事件监听
|
||||
SET_APPLY_NUM(state, value) {
|
||||
state.applyNum = value
|
||||
},
|
||||
|
||||
// 自增好友键盘输入事件
|
||||
UPDATE_KEYBOARD_EVENT(state) {
|
||||
state.inputEvent++
|
||||
},
|
||||
|
||||
// 更新好友登录状态
|
||||
UPDATE_FRIEND_STATUS(state, value) {
|
||||
state.friendStatus = value
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
ACT_UPDATE_FRIEND_STATUS({ commit }, value) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
commit('UPDATE_FRIEND_STATUS', value)
|
||||
resolve()
|
||||
}, 0)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import {
|
||||
getToken,
|
||||
getUserSettingCache,
|
||||
setUserSettingCache,
|
||||
} from '@/utils/auth'
|
||||
|
||||
let state = {
|
||||
// 主题模式 true:全屏模式 false:居中模式
|
||||
themeMode: true,
|
||||
|
||||
// 主题模式为居中模式下,body 的背景图片
|
||||
themeBagImg: 'bag003',
|
||||
|
||||
// 主题颜色
|
||||
themeColor: '',
|
||||
|
||||
// 消息提示音
|
||||
notifyCueTone: true,
|
||||
|
||||
// 键盘输入事件消息推送开关
|
||||
keyboardEventNotify: true,
|
||||
}
|
||||
|
||||
if (getToken()) {
|
||||
Object.assign(state, getUserSettingCache())
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户相关设置
|
||||
*/
|
||||
const Settings = {
|
||||
state,
|
||||
mutations: {
|
||||
// 设置主题模式
|
||||
SET_THEME_MODE(state, mode) {
|
||||
state.themeMode = mode
|
||||
setUserSettingCache(state)
|
||||
},
|
||||
|
||||
// 设置主题的背景图片
|
||||
SET_THEME_BAGIMG(state, bagName) {
|
||||
state.themeBagImg = bagName
|
||||
setUserSettingCache(state)
|
||||
},
|
||||
|
||||
// 主题颜色
|
||||
SET_THEME_COLOR(state, color) {
|
||||
state.themeColor = color
|
||||
setUserSettingCache(state)
|
||||
},
|
||||
|
||||
// 设置消息提示音状态
|
||||
SET_NOTIFY_CUE_TONE(state, isTrue) {
|
||||
state.notifyCueTone = isTrue
|
||||
setUserSettingCache(state)
|
||||
},
|
||||
|
||||
// 设置键盘输入事件消息推送状态
|
||||
SET_KEYBOARD_EVENT_NOTIFY(state, isTrue) {
|
||||
state.keyboardEventNotify = isTrue
|
||||
setUserSettingCache(state)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default Settings
|
||||
@@ -1,128 +0,0 @@
|
||||
import { getSort, getMutipSort } from "@/utils/functions";
|
||||
import { formatTalkItem } from "@/utils/talk";
|
||||
import { ServeGetTalkList } from "@/api/chat";
|
||||
const Talk = {
|
||||
state: {
|
||||
// 用户对话列表
|
||||
items: [],
|
||||
|
||||
// 最后一条消息
|
||||
unreadMessage: {
|
||||
num: 0,
|
||||
nickname: "未知",
|
||||
content: "...",
|
||||
},
|
||||
|
||||
// 对话列表重载状态
|
||||
heavyLoad: false,
|
||||
},
|
||||
getters: {
|
||||
// 过滤所有置顶对话列表
|
||||
topItems: (state) => {
|
||||
return state.items.filter((item) => item.is_top == 1);
|
||||
},
|
||||
talkItems: (state) => {
|
||||
return state.items.sort(
|
||||
getMutipSort([getSort((a, b) => a.lastTalkTime > b.lastTalkTime)])
|
||||
);
|
||||
},
|
||||
// 消息未读数总计
|
||||
unreadNum: (state) => {
|
||||
return state.items.reduce((total, item) => {
|
||||
return total + parseInt(item.unread);
|
||||
}, 0);
|
||||
},
|
||||
talkNum: (state) => state.items.length,
|
||||
},
|
||||
mutations: {
|
||||
|
||||
// 设置对话列表
|
||||
SET_TALK_ITEMS (state, resource) {
|
||||
state.items = resource.items;
|
||||
},
|
||||
|
||||
// 更新对话节点
|
||||
UPDATE_TALK_ITEM (state, resource) {
|
||||
// console.log("%c 更新对话节点", "color:#32c");
|
||||
// console.log("state", state);
|
||||
// console.log("resource", resource);
|
||||
|
||||
// console.log("%c 更新对话节点结束", "color:#32c",state.items);
|
||||
let index = state.items.findIndex(
|
||||
(item) => item.userId === resource.index_name.split("_")[1]
|
||||
);
|
||||
if (index >= 0) {
|
||||
Object.assign(state.items[index], resource);
|
||||
}
|
||||
},
|
||||
|
||||
// 新增对话节点
|
||||
PUSH_TALK_ITEM (state, resource) {
|
||||
// console.log(state)
|
||||
state.items.push(resource);
|
||||
},
|
||||
|
||||
// 移除对话节点
|
||||
REMOVE_TALK_ITEM (state, index_name) {
|
||||
for (let i in state.items) {
|
||||
if (state.items[i].index_name === index_name) {
|
||||
state.items.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// async getTalkList() {
|
||||
// let { code, result } = ServeGetTalkList();
|
||||
// if (code !== 200) return false;
|
||||
|
||||
// store.commit("SET_TALK_ITEMS", {
|
||||
// items: result.map((item) => formatTalkItem(item)),
|
||||
// });
|
||||
// },
|
||||
|
||||
// 更新对话消息
|
||||
UPDATE_TALK_MESSAGE (state, resource) {
|
||||
// console.log("%c 更新对话消息", "color:green");
|
||||
// console.log("state", state);
|
||||
// console.log("resource", resource);
|
||||
// console.log("%c 更新对话结束", "color:green",state.items);
|
||||
|
||||
let enableGetTalkList = true
|
||||
state.items.forEach(item => {
|
||||
if (item.userId == resource.index_name.split("_")[1]) {
|
||||
item.unread++;
|
||||
item.msg_text = resource.msg_text;
|
||||
item.lastTalkTime = resource.updated_at;
|
||||
item.lastTalkMessage = resource.msg_text;
|
||||
item.updated_at = resource.updated_at;
|
||||
enableGetTalkList = false
|
||||
}
|
||||
})
|
||||
// 循环如果当前用户不在对话记录列表中 就重新请求对话列表接口
|
||||
enableGetTalkList ? this.commit('getTalkList') : ''
|
||||
},
|
||||
|
||||
// 触发对话列表重新加载
|
||||
TRIGGER_TALK_ITEMS_LOAD (state, status = false) {
|
||||
state.heavyLoad = status;
|
||||
},
|
||||
|
||||
SET_TLAK_UNREAD_MESSAGE (state, resource) {
|
||||
state.unreadMessage.num++;
|
||||
state.unreadMessage.nickname = resource.nickname;
|
||||
state.unreadMessage.content = resource.content;
|
||||
},
|
||||
|
||||
// 清除最后一条未读消息
|
||||
CLEAR_TLAK_UNREAD_MESSAGE (state) {
|
||||
state.unreadMessage = {
|
||||
num: 0,
|
||||
nickname: "未知",
|
||||
content: "...",
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default Talk;
|
||||
@@ -1,73 +0,0 @@
|
||||
import { setUserInfo, getUserInfo, getToken } from "@/utils/auth";
|
||||
import { defaultAvatar, defaultUserBanner } from "@/assets/images";
|
||||
|
||||
// import { ServeLogout } from "@/api/user";
|
||||
|
||||
let state = {
|
||||
// 用户ID
|
||||
id: 0,
|
||||
// 用户昵称
|
||||
name: "",
|
||||
// 个性头像
|
||||
face: defaultAvatar,
|
||||
// 名片背景
|
||||
visitCardBag: defaultUserBanner,
|
||||
// 当前登录状态
|
||||
loginStatus: false,
|
||||
toUser:""
|
||||
};
|
||||
|
||||
// 判断用户是否登录
|
||||
if (getToken()) {
|
||||
let userInfo = getUserInfo();
|
||||
state.name = userInfo.name;
|
||||
state.id = userInfo.id;
|
||||
state.face = userInfo.face ? userInfo.face : state.avatar;
|
||||
state.loginStatus = true;
|
||||
}
|
||||
|
||||
const User = {
|
||||
state,
|
||||
mutations: {
|
||||
// 用户退出登录
|
||||
USER_LOGOUT(state) {
|
||||
state.id = 0;
|
||||
state.face = "";
|
||||
state.name = "";
|
||||
state.loginStatus = false;
|
||||
},
|
||||
|
||||
// 设置用户登录状态
|
||||
UPDATE_LOGIN_STATUS(state) {
|
||||
state.loginStatus = true;
|
||||
},
|
||||
|
||||
// 更新用户信息
|
||||
UPDATE_USER_INFO(state, data) {
|
||||
for (const key in data) {
|
||||
if (state.hasOwnProperty(key)) {
|
||||
state[key] = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
// 保存用户信息到缓存
|
||||
setUserInfo({
|
||||
id: state.id,
|
||||
face: state.face,
|
||||
name: state.name,
|
||||
});
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 退出登录处理操作
|
||||
ACT_USER_LOGOUT({ commit }) {
|
||||
commit("USER_LOGOUT");
|
||||
// ServeLogout().finally(() => {
|
||||
// removeAll();
|
||||
// location.reload();
|
||||
// });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default User;
|
||||
@@ -1,9 +0,0 @@
|
||||
// 根级别的 mutation
|
||||
const mutations = {
|
||||
// 更新socket 连接状态
|
||||
UPDATE_SOCKET_STATUS(state, status) {
|
||||
state.socketStatus = status
|
||||
},
|
||||
}
|
||||
|
||||
export default mutations
|
||||
@@ -1,11 +0,0 @@
|
||||
import { defaultAvatar } from "@/assets/images";
|
||||
|
||||
// 根级别的 state
|
||||
const state = {
|
||||
socketStatus: false,
|
||||
website_name: process.env.VUE_APP_WEBSITE_NAME,
|
||||
// 头像加载失败后的默认头像
|
||||
defaultAvatar: "this.src='" + defaultAvatar + "'",
|
||||
}
|
||||
|
||||
export default state
|
||||
23
im/src/stores/app.js
Normal file
23
im/src/stores/app.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defaultAvatar } from "@/assets/images";
|
||||
import { useUserStore } from "./user";
|
||||
|
||||
// 原 vuex 根级别 state/mutation/getter
|
||||
export const useAppStore = defineStore("app", {
|
||||
state: () => ({
|
||||
socketStatus: false,
|
||||
website_name: process.env.VUE_APP_WEBSITE_NAME,
|
||||
// 头像加载失败后的默认头像
|
||||
defaultAvatar: "this.src='" + defaultAvatar + "'",
|
||||
}),
|
||||
getters: {
|
||||
// 用户登录状态(跨模块读取 user store)
|
||||
loginStatus: () => useUserStore().loginStatus,
|
||||
},
|
||||
actions: {
|
||||
// 更新socket 连接状态
|
||||
UPDATE_SOCKET_STATUS(status) {
|
||||
this.socketStatus = status;
|
||||
},
|
||||
},
|
||||
});
|
||||
94
im/src/stores/dialogue.js
Normal file
94
im/src/stores/dialogue.js
Normal file
@@ -0,0 +1,94 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
// 原 vuex dialogue 模块
|
||||
export const useDialogueStore = defineStore("dialogue", {
|
||||
state: () => ({
|
||||
// 对话来源[1:私聊;2:群聊]
|
||||
talk_type: 0,
|
||||
|
||||
// 接收者ID
|
||||
receiver_id: 0,
|
||||
|
||||
is_robot: 0,
|
||||
|
||||
// 聊天记录
|
||||
records: [
|
||||
{
|
||||
id: "",
|
||||
createTime: "",
|
||||
toUser: "",
|
||||
isRead: false,
|
||||
messageType: "",
|
||||
talkId: "",
|
||||
text: "",
|
||||
float: "",
|
||||
},
|
||||
],
|
||||
webSocketWithOut: false, // ws 是否是掉线 无输出状态
|
||||
// 对话索引(聊天对话的唯一索引)
|
||||
index_name: null,
|
||||
}),
|
||||
actions: {
|
||||
// 设置ws状态
|
||||
SET_WS_STATUS(resource) {
|
||||
this.webSocketWithOut = resource;
|
||||
},
|
||||
|
||||
// 更新对话
|
||||
UPDATE_DIALOGUE_MESSAGE(resource) {
|
||||
this.records = [];
|
||||
this.talk_type = parseInt(resource.talk_type);
|
||||
this.receiver_id = parseInt(resource.receiver_id);
|
||||
this.is_robot = parseInt(resource.is_robot);
|
||||
|
||||
/**
|
||||
* receiver_id 就是 好友id
|
||||
* 比如 a 和 b 聊天 receiver_id = b的id
|
||||
*/
|
||||
this.index_name = (resource.talk_type || 1) + "_" + resource.receiver_id;
|
||||
},
|
||||
|
||||
// 数组头部压入对话记录
|
||||
UNSHIFT_DIALOGUE(records) {
|
||||
if (this.records.length > 0) {
|
||||
this.records.unshift(...records);
|
||||
} else {
|
||||
this.records.push(...records);
|
||||
}
|
||||
},
|
||||
|
||||
// 推送对话记录
|
||||
PUSH_DIALOGUE(record) {
|
||||
record = { ...record, webSocketStatus: this.webSocketWithOut };
|
||||
console.log("推送对话");
|
||||
this.records.push(record);
|
||||
},
|
||||
|
||||
// 更新对话记录
|
||||
UPDATE_DIALOGUE(resource) {
|
||||
for (let i in this.records) {
|
||||
if (this.records[i].id === resource.id) {
|
||||
Object.assign(this.records[i], resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 删除对话记录
|
||||
DELETE_DIALOGUE(index) {
|
||||
this.records.splice(index, 1);
|
||||
},
|
||||
|
||||
BATCH_DELETE_DIALOGUE(ids) {
|
||||
ids.forEach((record_id) => {
|
||||
let index = this.records.findIndex((item) => item.id == record_id);
|
||||
if (index >= 0) this.records.splice(index, 1);
|
||||
});
|
||||
},
|
||||
|
||||
// 数组头部压入对话记录
|
||||
SET_DIALOGUE(records) {
|
||||
this.records = records;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,36 +1,36 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ServeFindUserEmoticon, ServeUploadEmoticon } from "@/api/emoticon";
|
||||
|
||||
import { ServeCollectEmoticon } from "@/api/chat";
|
||||
|
||||
import { ElNotification } from "element-plus";
|
||||
|
||||
export default {
|
||||
state: {
|
||||
items: [
|
||||
],
|
||||
},
|
||||
mutations: {
|
||||
// 原 vuex emoticon 模块
|
||||
export const useEmoticonStore = defineStore("emoticon", {
|
||||
state: () => ({
|
||||
items: [],
|
||||
}),
|
||||
actions: {
|
||||
// 加载用户表情包
|
||||
LOAD_USER_EMOTICON(state) {
|
||||
LOAD_USER_EMOTICON() {
|
||||
// TODO 隐藏
|
||||
return;
|
||||
// eslint-disable-next-line no-unreachable
|
||||
ServeFindUserEmoticon().then((res) => {
|
||||
if (res.code == 200) {
|
||||
const { collect_emoticon, sys_emoticon } = res.data;
|
||||
|
||||
state.items = state.items.slice(0, 2);
|
||||
this.items = this.items.slice(0, 2);
|
||||
|
||||
// 用户收藏的系统表情包
|
||||
state.items[1].list = collect_emoticon;
|
||||
this.items[1].list = collect_emoticon;
|
||||
|
||||
// 用户添加的系统表情包
|
||||
state.items.push(...sys_emoticon);
|
||||
this.items.push(...sys_emoticon);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 收藏用户表情包
|
||||
SAVE_USER_EMOTICON(state, resoure) {
|
||||
SAVE_USER_EMOTICON(resoure) {
|
||||
ServeCollectEmoticon({
|
||||
record_id: resoure.record_id,
|
||||
})
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
type: "success",
|
||||
});
|
||||
|
||||
this.commit("LOAD_USER_EMOTICON");
|
||||
this.LOAD_USER_EMOTICON();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -55,13 +55,13 @@ export default {
|
||||
},
|
||||
|
||||
// 自定义上传用户表情包
|
||||
UPLOAD_USER_EMOTICON(state, resoure) {
|
||||
UPLOAD_USER_EMOTICON(resoure) {
|
||||
let fileData = new FormData();
|
||||
fileData.append("emoticon", resoure.file);
|
||||
ServeUploadEmoticon(fileData)
|
||||
.then((res) => {
|
||||
if (res.code == 200) {
|
||||
state.items[1].list.push(res.data);
|
||||
this.items[1].list.push(res.data);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -74,18 +74,18 @@ export default {
|
||||
},
|
||||
|
||||
// 添加系统表情包
|
||||
APPEND_SYS_EMOTICON(state, resoure) {
|
||||
state.items.push(resoure);
|
||||
APPEND_SYS_EMOTICON(resoure) {
|
||||
this.items.push(resoure);
|
||||
},
|
||||
|
||||
// 移除系统表情包
|
||||
REMOVE_SYS_EMOTICON(state, resoure) {
|
||||
for (let i in state.items) {
|
||||
if (state.items[i].emoticon_id === resoure.emoticon_id) {
|
||||
state.items.splice(i, 1);
|
||||
REMOVE_SYS_EMOTICON(resoure) {
|
||||
for (let i in this.items) {
|
||||
if (this.items[i].emoticon_id === resoure.emoticon_id) {
|
||||
this.items.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
18
im/src/stores/note.js
Normal file
18
im/src/stores/note.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
// 原 vuex note 模块
|
||||
export const useNoteStore = defineStore("note", {
|
||||
state: () => ({
|
||||
tags: [],
|
||||
class: [],
|
||||
}),
|
||||
actions: {
|
||||
SET_NOTE_TAGS(tags) {
|
||||
this.tags = tags;
|
||||
},
|
||||
|
||||
PUSH_NOTE_TAG(tag) {
|
||||
this.tags.unshift(tag);
|
||||
},
|
||||
},
|
||||
});
|
||||
65
im/src/stores/notify.js
Normal file
65
im/src/stores/notify.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
// 原 vuex notify 模块
|
||||
export const useNotifyStore = defineStore("notify", {
|
||||
state: () => ({
|
||||
// 聊天消息未读数
|
||||
unreadNum: 0,
|
||||
|
||||
// 好友申请未读数
|
||||
applyNum: 0,
|
||||
|
||||
// 好友键盘事件监听
|
||||
inputEvent: 0,
|
||||
|
||||
// 好友登录状态监听
|
||||
friendStatus: {
|
||||
// 登录状态[0:下线;1:在线;]
|
||||
status: 0,
|
||||
// 好友ID
|
||||
friend_id: 0,
|
||||
},
|
||||
}),
|
||||
actions: {
|
||||
// 消息未读数自增
|
||||
INCR_UNREAD_NUM() {
|
||||
console.log("触发消息未读");
|
||||
this.unreadNum++;
|
||||
},
|
||||
|
||||
// 好友申请事件监听
|
||||
INCR_APPLY_NUM() {
|
||||
this.applyNum++;
|
||||
},
|
||||
|
||||
// 设置消息未读数
|
||||
SET_UNREAD_NUM(value) {
|
||||
this.unreadNum = value;
|
||||
},
|
||||
|
||||
// 好友申请事件监听
|
||||
SET_APPLY_NUM(value) {
|
||||
this.applyNum = value;
|
||||
},
|
||||
|
||||
// 自增好友键盘输入事件
|
||||
UPDATE_KEYBOARD_EVENT() {
|
||||
this.inputEvent++;
|
||||
},
|
||||
|
||||
// 更新好友登录状态
|
||||
UPDATE_FRIEND_STATUS(value) {
|
||||
this.friendStatus = value;
|
||||
},
|
||||
|
||||
// 原 vuex action ACT_UPDATE_FRIEND_STATUS
|
||||
ACT_UPDATE_FRIEND_STATUS(value) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
this.UPDATE_FRIEND_STATUS(value);
|
||||
resolve();
|
||||
}, 0);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
68
im/src/stores/settings.js
Normal file
68
im/src/stores/settings.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import { defineStore } from "pinia";
|
||||
import {
|
||||
getToken,
|
||||
getUserSettingCache,
|
||||
setUserSettingCache,
|
||||
} from "@/utils/auth";
|
||||
|
||||
// 模块加载时合并本地缓存的设置(与原 vuex settings 模块行为一致)
|
||||
function initState() {
|
||||
const state = {
|
||||
// 主题模式 true:全屏模式 false:居中模式
|
||||
themeMode: true,
|
||||
|
||||
// 主题模式为居中模式下,body 的背景图片
|
||||
themeBagImg: "bag003",
|
||||
|
||||
// 主题颜色
|
||||
themeColor: "",
|
||||
|
||||
// 消息提示音
|
||||
notifyCueTone: true,
|
||||
|
||||
// 键盘输入事件消息推送开关
|
||||
keyboardEventNotify: true,
|
||||
};
|
||||
if (getToken()) {
|
||||
Object.assign(state, getUserSettingCache());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户相关设置
|
||||
*/
|
||||
export const useSettingsStore = defineStore("settings", {
|
||||
state: initState,
|
||||
actions: {
|
||||
// 设置主题模式
|
||||
SET_THEME_MODE(mode) {
|
||||
this.themeMode = mode;
|
||||
setUserSettingCache(this.$state);
|
||||
},
|
||||
|
||||
// 设置主题的背景图片
|
||||
SET_THEME_BAGIMG(bagName) {
|
||||
this.themeBagImg = bagName;
|
||||
setUserSettingCache(this.$state);
|
||||
},
|
||||
|
||||
// 主题颜色
|
||||
SET_THEME_COLOR(color) {
|
||||
this.themeColor = color;
|
||||
setUserSettingCache(this.$state);
|
||||
},
|
||||
|
||||
// 设置消息提示音状态
|
||||
SET_NOTIFY_CUE_TONE(isTrue) {
|
||||
this.notifyCueTone = isTrue;
|
||||
setUserSettingCache(this.$state);
|
||||
},
|
||||
|
||||
// 设置键盘输入事件消息推送状态
|
||||
SET_KEYBOARD_EVENT_NOTIFY(isTrue) {
|
||||
this.keyboardEventNotify = isTrue;
|
||||
setUserSettingCache(this.$state);
|
||||
},
|
||||
},
|
||||
});
|
||||
111
im/src/stores/talk.js
Normal file
111
im/src/stores/talk.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { getSort, getMutipSort } from "@/utils/functions";
|
||||
|
||||
// 原 vuex talks 模块
|
||||
export const useTalkStore = defineStore("talks", {
|
||||
state: () => ({
|
||||
// 用户对话列表
|
||||
items: [],
|
||||
|
||||
// 最后一条消息
|
||||
unreadMessage: {
|
||||
num: 0,
|
||||
nickname: "未知",
|
||||
content: "...",
|
||||
},
|
||||
|
||||
// 对话列表重载状态
|
||||
heavyLoad: false,
|
||||
}),
|
||||
getters: {
|
||||
// 过滤所有置顶对话列表
|
||||
topItems: (state) => {
|
||||
return state.items.filter((item) => item.is_top == 1);
|
||||
},
|
||||
// 原 vuex getter,注意:sort 会原地修改 items 数组(历史行为,原样保留)
|
||||
talkItems: (state) => {
|
||||
return state.items.sort(
|
||||
getMutipSort([getSort((a, b) => a.lastTalkTime > b.lastTalkTime)])
|
||||
);
|
||||
},
|
||||
// 消息未读数总计
|
||||
unreadNum: (state) => {
|
||||
return state.items.reduce((total, item) => {
|
||||
return total + parseInt(item.unread);
|
||||
}, 0);
|
||||
},
|
||||
talkNum: (state) => state.items.length,
|
||||
},
|
||||
actions: {
|
||||
// 设置对话列表
|
||||
SET_TALK_ITEMS(resource) {
|
||||
this.items = resource.items;
|
||||
},
|
||||
|
||||
// 更新对话节点
|
||||
UPDATE_TALK_ITEM(resource) {
|
||||
let index = this.items.findIndex(
|
||||
(item) => item.userId === resource.index_name.split("_")[1]
|
||||
);
|
||||
if (index >= 0) {
|
||||
Object.assign(this.items[index], resource);
|
||||
}
|
||||
},
|
||||
|
||||
// 新增对话节点
|
||||
PUSH_TALK_ITEM(resource) {
|
||||
this.items.push(resource);
|
||||
},
|
||||
|
||||
// 移除对话节点
|
||||
REMOVE_TALK_ITEM(index_name) {
|
||||
for (let i in this.items) {
|
||||
if (this.items[i].index_name === index_name) {
|
||||
this.items.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 更新对话消息
|
||||
UPDATE_TALK_MESSAGE(resource) {
|
||||
let enableGetTalkList = true;
|
||||
this.items.forEach((item) => {
|
||||
if (item.userId == resource.index_name.split("_")[1]) {
|
||||
item.unread++;
|
||||
item.msg_text = resource.msg_text;
|
||||
item.lastTalkTime = resource.updated_at;
|
||||
item.lastTalkMessage = resource.msg_text;
|
||||
item.updated_at = resource.updated_at;
|
||||
enableGetTalkList = false;
|
||||
}
|
||||
});
|
||||
// 循环如果当前用户不在对话记录列表中 就重新请求对话列表接口
|
||||
// 原代码此处为 this.commit('getTalkList'),目标 action 早已被原作者注释删除,
|
||||
// vuex 对未知 mutation 仅告警不中断,此处保留为空操作
|
||||
if (enableGetTalkList) {
|
||||
/* noop */
|
||||
}
|
||||
},
|
||||
|
||||
// 触发对话列表重新加载
|
||||
TRIGGER_TALK_ITEMS_LOAD(status = false) {
|
||||
this.heavyLoad = status;
|
||||
},
|
||||
|
||||
SET_TLAK_UNREAD_MESSAGE(resource) {
|
||||
this.unreadMessage.num++;
|
||||
this.unreadMessage.nickname = resource.nickname;
|
||||
this.unreadMessage.content = resource.content;
|
||||
},
|
||||
|
||||
// 清除最后一条未读消息
|
||||
CLEAR_TLAK_UNREAD_MESSAGE() {
|
||||
this.unreadMessage = {
|
||||
num: 0,
|
||||
nickname: "未知",
|
||||
content: "...",
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
68
im/src/stores/user.js
Normal file
68
im/src/stores/user.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { setUserInfo, getUserInfo, getToken } from "@/utils/auth";
|
||||
import { defaultAvatar, defaultUserBanner } from "@/assets/images";
|
||||
|
||||
// 判断用户是否登录(模块加载时初始化,与原 vuex user 模块行为一致)
|
||||
function initState() {
|
||||
const state = {
|
||||
// 用户ID
|
||||
id: 0,
|
||||
// 用户昵称
|
||||
name: "",
|
||||
// 个性头像
|
||||
face: defaultAvatar,
|
||||
// 名片背景
|
||||
visitCardBag: defaultUserBanner,
|
||||
// 当前登录状态
|
||||
loginStatus: false,
|
||||
toUser: "",
|
||||
};
|
||||
if (getToken()) {
|
||||
let userInfo = getUserInfo();
|
||||
state.name = userInfo.name;
|
||||
state.id = userInfo.id;
|
||||
// 原代码如此:state.avatar 并不存在(恒为 undefined)
|
||||
state.face = userInfo.face ? userInfo.face : state.avatar;
|
||||
state.loginStatus = true;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore("user", {
|
||||
state: initState,
|
||||
actions: {
|
||||
// 用户退出登录
|
||||
USER_LOGOUT() {
|
||||
this.id = 0;
|
||||
this.face = "";
|
||||
this.name = "";
|
||||
this.loginStatus = false;
|
||||
},
|
||||
|
||||
// 设置用户登录状态
|
||||
UPDATE_LOGIN_STATUS() {
|
||||
this.loginStatus = true;
|
||||
},
|
||||
|
||||
// 更新用户信息
|
||||
UPDATE_USER_INFO(data) {
|
||||
for (const key in data) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.$state, key)) {
|
||||
this[key] = data[key];
|
||||
}
|
||||
}
|
||||
|
||||
// 保存用户信息到缓存
|
||||
setUserInfo({
|
||||
id: this.id,
|
||||
face: this.face,
|
||||
name: this.name,
|
||||
});
|
||||
},
|
||||
|
||||
// 退出登录处理操作(原 vuex action ACT_USER_LOGOUT)
|
||||
ACT_USER_LOGOUT() {
|
||||
this.USER_LOGOUT();
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,10 +1,22 @@
|
||||
import { h } from "vue";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
import MainMixin from "@/mixins/main-mixin";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
|
||||
let refreshViewFn = null;
|
||||
|
||||
// vuex → pinia 兼容门面:外部(im-server/event/talk.js)仍以
|
||||
// $store.state.talks.items 的旧 vuex 形态访问,这里用惰性 getter 返回
|
||||
// 对应的 pinia store(store 实例上直接暴露 state 属性),
|
||||
// getter 内调用 useTalkStore() 以保证 pinia 已激活
|
||||
const store = {
|
||||
get state() {
|
||||
return {
|
||||
talks: useTalkStore(),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const mixinCtx = {
|
||||
get $store() {
|
||||
return store;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import store from "@/store";
|
||||
import { useTalkStore } from "@/stores/talk";
|
||||
import router from "@/router";
|
||||
import { parseTime } from "@/utils/functions";
|
||||
import { ServeCreateTalkList } from "@/api/chat";
|
||||
@@ -11,7 +11,7 @@ const KEY_INDEX_NAME = "send_message_index_name";
|
||||
* @param {String} index_name
|
||||
*/
|
||||
export function findTalkIndex (index_name) {
|
||||
return store.state.talks.items.findIndex(
|
||||
return useTalkStore().items.findIndex(
|
||||
(item) => item.index_name == index_name
|
||||
);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ export function findTalkIndex (index_name) {
|
||||
* @param {String} index_name
|
||||
*/
|
||||
export function findTalk (index_name) {
|
||||
return store.state.talks.items.find((item) => item.index_name == index_name);
|
||||
return useTalkStore().items.find((item) => item.index_name == index_name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,62 +43,66 @@
|
||||
</audio>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { computed, watch } from "vue";
|
||||
import Face from '../../components/face'
|
||||
import { mapState } from "vuex";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useNotifyStore } from "@/stores/notify";
|
||||
import { useSettingsStore } from "@/stores/settings";
|
||||
import { ServeFindFriendApplyNum } from "@/api/contacts";
|
||||
|
||||
export default {
|
||||
components: { Face },
|
||||
name: "MainLayout",
|
||||
props: {
|
||||
idx: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
defineOptions({ name: "MainLayout" });
|
||||
|
||||
defineProps({
|
||||
idx: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
face: (state) => state.user.face,
|
||||
name: (state) => state.user.name,
|
||||
id: (state) => state.user.id,
|
||||
defaultAvatar: (state) => state.defaultAvatar,
|
||||
socketStatus: (state) => state.socketStatus,
|
||||
unreadNum: (state) => state.notify.unreadNum,
|
||||
applyNum: (state) => state.notify.applyNum,
|
||||
notifyCueTone: (state) => state.settings.notifyCueTone,
|
||||
themeMode: (state) => state.settings.themeMode,
|
||||
themeBagImg: (state) => state.settings.themeBagImg,
|
||||
}),
|
||||
},
|
||||
watch: {
|
||||
unreadNum (n, o) {
|
||||
if (n > 0 && n > o && this.notifyCueTone) {
|
||||
this.play();
|
||||
}
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.setApplyNum();
|
||||
},
|
||||
methods: {
|
||||
play () {
|
||||
document
|
||||
.querySelector("#audio")
|
||||
.play()
|
||||
.catch(() => {
|
||||
console.error("消息提示音播放异常");
|
||||
});
|
||||
},
|
||||
logout () {
|
||||
this.$store.dispatch("ACT_USER_LOGOUT");
|
||||
},
|
||||
setApplyNum () {
|
||||
// TODO 暂且return
|
||||
return;
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const notifyStore = useNotifyStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const face = computed(() => userStore.face);
|
||||
const name = computed(() => userStore.name);
|
||||
const id = computed(() => userStore.id);
|
||||
const defaultAvatar = computed(() => appStore.defaultAvatar);
|
||||
const socketStatus = computed(() => appStore.socketStatus);
|
||||
const unreadNum = computed(() => notifyStore.unreadNum);
|
||||
const applyNum = computed(() => notifyStore.applyNum);
|
||||
const notifyCueTone = computed(() => settingsStore.notifyCueTone);
|
||||
const themeMode = computed(() => settingsStore.themeMode);
|
||||
const themeBagImg = computed(() => settingsStore.themeBagImg);
|
||||
|
||||
watch(unreadNum, (n, o) => {
|
||||
if (n > 0 && n > o && notifyCueTone.value) {
|
||||
play();
|
||||
}
|
||||
});
|
||||
|
||||
// 原 created 钩子
|
||||
setApplyNum();
|
||||
|
||||
function play () {
|
||||
document
|
||||
.querySelector("#audio")
|
||||
.play()
|
||||
.catch(() => {
|
||||
console.error("消息提示音播放异常");
|
||||
});
|
||||
}
|
||||
|
||||
function logout () {
|
||||
userStore.ACT_USER_LOGOUT();
|
||||
}
|
||||
|
||||
function setApplyNum () {
|
||||
// TODO 暂且return
|
||||
return;
|
||||
}
|
||||
</script>
|
||||
<style lang="less" >
|
||||
.main-layout {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,39 +16,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, onBeforeUnmount } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { SvgNotFount } from '@/core/icons'
|
||||
|
||||
export default {
|
||||
name: 'NotFoundPage',
|
||||
components: {
|
||||
SvgNotFount,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
second: 10,
|
||||
setInterval: null,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.setInterval = setInterval(() => {
|
||||
this.second--
|
||||
if (this.second == 0) {
|
||||
clearInterval(this.setInterval)
|
||||
this.toHome()
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
beforeUnmount() {
|
||||
clearInterval(this.setInterval)
|
||||
},
|
||||
methods: {
|
||||
toHome() {
|
||||
this.$router.push({
|
||||
path: '/',
|
||||
})
|
||||
},
|
||||
},
|
||||
defineOptions({ name: 'NotFoundPage' })
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const second = ref(10)
|
||||
let timer = null
|
||||
|
||||
timer = setInterval(() => {
|
||||
second.value--
|
||||
if (second.value == 0) {
|
||||
clearInterval(timer)
|
||||
toHome()
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer)
|
||||
})
|
||||
|
||||
function toHome() {
|
||||
router.push({
|
||||
path: '/',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
Reference in New Issue
Block a user