Commit 5b0e1790 by Sixong.Zhu

eslint , remove moment

parent bd1a816c
...@@ -115,9 +115,7 @@ ...@@ -115,9 +115,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { Component, Prop, Ref, Vue } from "vue-property-decorator";
import { parserMessage } from "./controller"; import { parserMessage } from "./controller";
import { EVENTS } from "@/EventConsts"; import { EVENTS } from "@/EventConsts";
import { chatStore, ChatStore } from "@/customer-service/store/model"; import { chatStore, ChatStore } from "@/customer-service/store/model";
import { import {
......
...@@ -54,9 +54,7 @@ ...@@ -54,9 +54,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { Component, Prop, Ref, Vue } from "vue-property-decorator";
import Controller from "./controller/chat-list"; import Controller from "./controller/chat-list";
import { EVENTS } from "@/EventConsts"; import { EVENTS } from "@/EventConsts";
import avatar from "@/customer-service/components/avatar.vue"; import avatar from "@/customer-service/components/avatar.vue";
import { Chat as ChatType } from "@/customer-service/xim/models/chat"; import { Chat as ChatType } from "@/customer-service/xim/models/chat";
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";
import { ChatStore, chatStore } from "../store/model"; import { ChatStore, chatStore } from "../store/model";
...@@ -66,6 +67,7 @@ export default class ChatMembers extends Vue { ...@@ -66,6 +67,7 @@ export default class ChatMembers extends Vue {
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.chat-members { .chat-members {
padding: 20px; padding: 20px;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
Component, Component,
...@@ -43,19 +44,13 @@ import { ...@@ -43,19 +44,13 @@ import {
Vue, Vue,
Watch, Watch,
} from "vue-property-decorator"; } from "vue-property-decorator";
import MessageInput from "@/customer-service/components/message-input.vue"; import MessageInput from "@/customer-service/components/message-input.vue";
import messages from "@/customer-service/components/message-list.vue"; import messages from "@/customer-service/components/message-list.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
type RoomInfoTab = "customer" | "order"; type RoomInfoTab = "customer" | "order";
@Component({ @Component({ components: { MessageInput, messages } })
components: {
MessageInput,
messages,
},
})
export default class ChatRoom extends Vue { export default class ChatRoom extends Vue {
@Ref("chatBox") chatBox!: Element; @Ref("chatBox") chatBox!: Element;
@Ref("top") refTop!: Element; @Ref("top") refTop!: Element;
......
...@@ -56,9 +56,9 @@ ...@@ -56,9 +56,9 @@
/> />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator"; import { Component, Prop, Vue } from "vue-property-decorator";
import ChatCreator from "@/customer-service/components/create-chat.vue"; import ChatCreator from "@/customer-service/components/create-chat.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
import { ChatRole } from "../model"; import { ChatRole } from "../model";
...@@ -192,6 +192,7 @@ export default class ChatTitle extends Vue { ...@@ -192,6 +192,7 @@ export default class ChatTitle extends Vue {
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.room-title { .room-title {
font-size: 16px; font-size: 16px;
......
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";
import { parserMessage } from "."; import { parserMessage } from ".";
import { chatStore, ChatStore } from "@/customer-service/store/model"; import { chatStore, ChatStore } from "@/customer-service/store/model";
import { formatTime, TimeFormatRule } from "@/customer-service/utils/time"; import { formatTime, TimeFormatRule } from "@/customer-service/utils/time";
import { Chat as ChatItem } from "@/customer-service/xim/models/chat"; import { Chat as ChatItem } from "@/customer-service/xim/models/chat";
......
...@@ -6,13 +6,15 @@ export function parserMessage(type: string, rawMsg: string) { ...@@ -6,13 +6,15 @@ export function parserMessage(type: string, rawMsg: string) {
if (type === MessageType.Text) { if (type === MessageType.Text) {
const msg = JSON.parse(rawMsg); const msg = JSON.parse(rawMsg);
return msg.text; return msg.text;
} else if (type === MessageType.Image) { }
if (type === MessageType.Image) {
return `[图片]`; return `[图片]`;
} else if (type === MessageType.File) { }
if (type === MessageType.File) {
return `[文件]`; return `[文件]`;
} else if (type === MessageType.Withdraw) { }
if (type === MessageType.Withdraw) {
return `[撤回了一条消息]`; return `[撤回了一条消息]`;
} else {
return `[系统自动回复]`;
} }
return `[系统自动回复]`;
} }
...@@ -56,26 +56,19 @@ ...@@ -56,26 +56,19 @@
</span> </span>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ListEasy, ListTypes, TagManagerTypes } from "uniplat-sdk"; import { ListEasy, ListTypes, TagManagerTypes } from "uniplat-sdk";
import { Component, Prop, Vue, Watch } from "vue-property-decorator"; import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import buttonThrottle from "../utils/button-throttle"; import buttonThrottle from "../utils/button-throttle";
import GeneralTagSelectForFilter from "@/components/statistic/GeneralTagSelectForFilter.vue"; import GeneralTagSelectForFilter from "@/components/statistic/GeneralTagSelectForFilter.vue";
import avatar from "@/customer-service/components/avatar.vue"; import avatar from "@/customer-service/components/avatar.vue";
import chat from "@/customer-service/xim/index"; import chat from "@/customer-service/xim/index";
type User = {
id: string;
name: string;
};
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T; type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
@Component({ components: { avatar, GeneralTagSelectForFilter } }) @Component({ components: { avatar, GeneralTagSelectForFilter } })
export default class ChatCreator extends Vue { export default class ChatCreator extends Vue {
@Prop({ @Prop({ type: Array, default: () => [] })
type: Array,
default: () => [],
})
private selected!: number[]; private selected!: number[];
@Watch("currentPage") @Watch("currentPage")
...@@ -83,7 +76,7 @@ export default class ChatCreator extends Vue { ...@@ -83,7 +76,7 @@ export default class ChatCreator extends Vue {
this.nextPage(); this.nextPage();
} }
private tagGroups: TagManagerTypes.TagGroup[] = [] private tagGroups: TagManagerTypes.TagGroup[] = [];
private searchText = ""; private searchText = "";
private currentPage = 1; private currentPage = 1;
private total = 0; private total = 0;
...@@ -122,7 +115,7 @@ export default class ChatCreator extends Vue { ...@@ -122,7 +115,7 @@ export default class ChatCreator extends Vue {
const { pageData, getList } = await list.query({ const { pageData, getList } = await list.query({
pageIndex: this.currentPage, pageIndex: this.currentPage,
item_size: this.pageSize, item_size: this.pageSize,
tagFilters: this.getSelectedTags() tagFilters: this.getSelectedTags(),
}); });
this.total = pageData.record_count; this.total = pageData.record_count;
this.getList = getList; this.getList = getList;
......
<template> <template>
<el-dialog <el-dialog
:modal="false" :modal="false"
:before-close="close" :before-close="close"
:visible="value" :visible="value"
custom-class="hide-header show-close padding-0 width-auto" custom-class="hide-header show-close padding-0 width-auto"
> >
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="preview-title text-center">图片预览</div> <div class="preview-title text-center">图片预览</div>
<div class="d-flex justify-content-center" style="min-width: 300px"> <div class="d-flex justify-content-center" style="min-width: 300px">
<img v-if="file" :src="file.url" :style="style" /> <img v-if="file" :src="file.url" :style="style" />
</div> </div>
<div class="d-flex justify-content-center actions"> <div class="d-flex justify-content-center actions">
<span <span
class="d-flex align-items-center justify-content-center" class="d-flex align-items-center justify-content-center"
@click="set2Default" @click="set2Default"
>1:1</span >1:1</span
> >
<a <a
class="d-flex align-items-center justify-content-center" class="d-flex align-items-center justify-content-center"
:href="file.url | downloadUrl(getAttachment)" :href="file.url"
:download="getAttachment" :download="getAttachment"
> >
<i class="el-icon-download"></i> <i class="el-icon-download"></i>
</a> </a>
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Mixins, Model, Prop } from "vue-property-decorator"; import { Component, Model, Prop, Vue } from "vue-property-decorator";
import { Filters } from '../mixin/filter';
@Component({ components: {} }) @Component({ components: {} })
export default class ImagePreview extends Mixins(Filters) { export default class ImagePreview extends Vue {
@Model("update") @Model("update")
private value!: boolean; private value!: boolean;
@Prop() @Prop()
private file!: { name: string; url: string }; private file!: { name: string; url: string };
private style: { private style: {
"max-height": number | string; "max-height": number | string;
"max-width": number | string; "max-width": number | string;
} = { } = {
"max-height": "300px", "max-height": "300px",
"max-width": "600px", "max-width": "600px",
}; };
private close() { private close() {
setTimeout( setTimeout(
() => (this.style = { "max-height": "300px", "max-width": "600px" }), () =>
300 (this.style = { "max-height": "300px", "max-width": "600px" }),
); 300
this.$emit("update", false); );
} this.$emit("update", false);
}
private set2Default() { private set2Default() {
this.style = { "max-height": "1600px", "max-width": "1600px" }; this.style = { "max-height": "1600px", "max-width": "1600px" };
} }
private get getAttachment() { private get getAttachment() {
if (this.file) { if (this.file) {
return this.file.name; return this.file.name;
}
return "文件下载";
} }
return "文件下载";
}
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.preview-title { .preview-title {
font-size: 18px; font-size: 18px;
color: #333; color: #333;
margin-bottom: 15px; margin-bottom: 15px;
} }
.actions { .actions {
margin: 15px 0; margin: 15px 0;
> span, > span,
a { a {
width: 30px; width: 30px;
height: 30px; height: 30px;
background-color: #7a7b7d; background-color: #7a7b7d;
color: #fff; color: #fff;
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
i { i {
color: #fff; color: #fff;
font-size: 20px; font-size: 20px;
} }
& + span { & + span {
margin-left: 15px; margin-left: 15px;
}
} }
}
> a { > a {
margin-left: 15px; margin-left: 15px;
} }
} }
</style> </style>
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Ref, Vue, Watch } from "vue-property-decorator"; import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import ChatInput, { import ChatInput, {
FILE_INFO_CLASS, FILE_INFO_CLASS,
isImageOrFile, isImageOrFile,
...@@ -17,7 +16,6 @@ import { Message, MessageType } from "../model"; ...@@ -17,7 +16,6 @@ import { Message, MessageType } from "../model";
import { uploadFile } from "../service/upload"; import { uploadFile } from "../service/upload";
import { ChatLoggerService } from "../xim/logger"; import { ChatLoggerService } from "../xim/logger";
import xim from "../xim/xim"; import xim from "../xim/xim";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
let sendingMessageIndex = 1; let sendingMessageIndex = 1;
......
...@@ -39,15 +39,12 @@ ...@@ -39,15 +39,12 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Ref, Vue, Watch } from "vue-property-decorator"; import { Component, Prop, Ref, Vue, Watch } from "vue-property-decorator";
import { Message, MessageType } from "../model"; import { Message, MessageType } from "../model";
import { throttle } from "../utils"; import { throttle } from "../utils";
import { formatTime } from "../utils/time"; import { formatTime } from "../utils/time";
import ImagePreview from "./image-preview.vue"; import ImagePreview from "./image-preview.vue";
import message from "./message.vue"; import message from "./message.vue";
import VideoPreview from "./video-preview.vue"; import VideoPreview from "./video-preview.vue";
import { ChatStore, chatStore } from "@/customer-service/store/model"; import { ChatStore, chatStore } from "@/customer-service/store/model";
import { dbController } from "../database"; import { dbController } from "../database";
......
...@@ -108,449 +108,443 @@ ...@@ -108,449 +108,443 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Inject, Mixins, Prop } from "vue-property-decorator"; import { Component, Inject, Prop, Vue } from "vue-property-decorator";
import * as dto from "../model";
import { Filters } from "../mixin/filter"; import chat from "./../xim";
import * as dto from "../model"; import {
isAudio,
import chat from "./../xim"; isImage,
import { isVideo,
isAudio, MAX_FILE_SIZE,
isImage, MAX_IMAGE_SIZE,
isVideo, } from "./message-item/file-controller";
MAX_FILE_SIZE, import WhoReadList from "./who-read-list.vue";
MAX_IMAGE_SIZE, import avatar from "@/customer-service/components/avatar.vue";
} from "./message-item/file-controller"; import { chatStore, ChatStore } from "@/customer-service/store/model";
import ximInstance from "../xim/xim";
import WhoReadList from "./who-read-list.vue"; import { dbController } from "../database";
import ImageMessage from "./message-item/image-message.vue";
import avatar from "@/customer-service/components/avatar.vue"; import FileMessage from "./message-item/file-message.vue";
import { chatStore, ChatStore } from "@/customer-service/store/model"; import AudioMessage from "./message-item/audio-message.vue";
import ximInstance from "../xim/xim"; import VideoMessage from "./message-item/video-message.vue";
import { dbController } from "../database"; import TextMessage from "./message-item/text-message.vue";
import WithdrawMessage from "./message-item/withdraw-message.vue";
import ImageMessage from "./message-item/image-message.vue"; import xim from "./../xim";
import FileMessage from "./message-item/file-message.vue";
import AudioMessage from "./message-item/audio-message.vue"; const twoMinutes = 2 * 60 * 1000;
import VideoMessage from "./message-item/video-message.vue";
import TextMessage from "./message-item/text-message.vue"; const messageMapping = new Map<dto.MessageType, string>([
import WithdrawMessage from "./message-item/withdraw-message.vue"; [dto.MessageType.Image, "image-message"],
import xim from "./../xim"; [dto.MessageType.File, "file-message"],
[dto.MessageType.Video, "video-message"],
const twoMinutes = 2 * 60 * 1000; [dto.MessageType.Voice, "audio-message"],
[dto.MessageType.Text, "text-message"],
const messageMapping = new Map<dto.MessageType, string>([ [dto.MessageType.Withdraw, "withdraw-message"],
[dto.MessageType.Image, "image-message"], [dto.MessageType.GeneralOrderMsg, "text-message"],
[dto.MessageType.File, "file-message"], ]);
[dto.MessageType.Video, "video-message"],
[dto.MessageType.Voice, "audio-message"], @Component({
[dto.MessageType.Text, "text-message"], components: {
[dto.MessageType.Withdraw, "withdraw-message"], WhoReadList,
[dto.MessageType.GeneralOrderMsg, "text-message"], avatar,
]); ImageMessage,
FileMessage,
@Component({ AudioMessage,
components: { VideoMessage,
WhoReadList, TextMessage,
avatar, WithdrawMessage,
ImageMessage, },
FileMessage, })
AudioMessage, export default class Message extends Vue {
VideoMessage, @chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID)
TextMessage, private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID;
WithdrawMessage,
}, @chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS)
}) private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS;
export default class Message extends Mixins(Filters) {
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_USER_UID) @chatStore.State(ChatStore.STATE_CHAT_SOURCE)
private readonly chatMyId!: ChatStore.STATE_CHAT_CURRENT_USER_UID; private readonly chatSource!: ChatStore.STATE_CHAT_SOURCE;
@chatStore.Getter(ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS) @chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID)
private readonly chatMembers!: ChatStore.GETTER_CURRENT_CHAT_PRESENT_MEMBERS; private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID;
@chatStore.State(ChatStore.STATE_CHAT_SOURCE) @chatStore.Mutation(ChatStore.MUTATION_WITHDRAW)
private readonly chatSource!: ChatStore.STATE_CHAT_SOURCE; private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW;
@chatStore.State(ChatStore.STATE_CHAT_CURRENT_CHAT_ID) @chatStore.Action(ChatStore.ACTION_SET_HANDLED)
private readonly chatId!: ChatStore.STATE_CHAT_CURRENT_CHAT_ID; private readonly setHandled!: ChatStore.ACTION_SET_HANDLED;
@chatStore.Mutation(ChatStore.MUTATION_WITHDRAW) @Prop({ type: Object, default: () => Object.create(null) })
private readonly executeWithDraw!: ChatStore.MUTATION_WITHDRAW; private readonly data!: dto.Message;
@chatStore.Action(ChatStore.ACTION_SET_HANDLED) @Prop()
private readonly setHandled!: ChatStore.ACTION_SET_HANDLED; private readonly isSendingMessage!: boolean;
@Prop({ type: Object, default: () => Object.create(null) }) @Prop()
private readonly data!: dto.Message; private readonly failed!: boolean;
@Prop() @Prop({ default: "circle" })
private readonly isSendingMessage!: boolean; private readonly shape!: string;
@Prop() @Inject({ default: false }) readonly showReadSummary!: boolean;
private readonly failed!: boolean;
private readonly backend = chat.isBackend();
@Prop({ default: "circle" })
private readonly shape!: string; private messageComponent = "";
@Inject({ default: false }) readonly showReadSummary!: boolean; private readListVisibility = false;
private readonly backend = chat.isBackend(); private org = "";
private messageComponent = ""; private readerListOffset = false;
private defaultMessageHandledStatus = dto.MessageHandled.Default;
private readListVisibility = false; private showHostAvatar: boolean = false;
private org = ""; private get canWithdraw() {
if (this.backend && this.data) {
private readerListOffset = false; return new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
private defaultMessageHandledStatus = dto.MessageHandled.Default;
private showHostAvatar: boolean = false;
private get canWithdraw() {
if (this.backend && this.data) {
return new Date().valueOf() - this.data.ts * 1000 < twoMinutes;
}
return false;
}
private get isWithdrawMessage() {
return this.data.type === dto.MessageType.Withdraw;
}
private get isAllRead() {
return this.data.read_count >= this.data.total_read_count;
} }
return false;
}
private get messageBody(): { eid?: string; oid?: string; msg: any } { private get isWithdrawMessage() {
if (this.data) { return this.data.type === dto.MessageType.Withdraw;
try { }
return { ...this.data, msg: JSON.parse(this.data.msg) };
} catch {
return {
...this.data,
msg: JSON.parse(this.data.msg.replace(/\n/g, "\\n")),
};
}
}
return { msg: { text: "" } }; private get isAllRead() {
} return this.data.read_count >= this.data.total_read_count;
}
private get handled() { private get messageBody(): { eid?: string; oid?: string; msg: any } {
if (this.data) { if (this.data) {
return this.defaultMessageHandledStatus || this.data.handled; try {
return { ...this.data, msg: JSON.parse(this.data.msg) };
} catch {
return {
...this.data,
msg: JSON.parse(this.data.msg.replace(/\n/g, "\\n")),
};
} }
return dto.MessageHandled.Default;
} }
private get isMyMessage() { return { msg: { text: "" } };
if (this.isSendingMessage) { }
return true;
}
const senderEid = this.messageBody.eid; private get handled() {
return senderEid!.toString() === this.chatMyId!.toString(); if (this.data) {
return this.defaultMessageHandledStatus || this.data.handled;
} }
return dto.MessageHandled.Default;
}
created() { private get isMyMessage() {
this.messageComponent = messageMapping.get(this.messageType) as string; if (this.isSendingMessage) {
return true;
} }
private get userName() { const senderEid = this.messageBody.eid;
if (this.chatMembers) { return senderEid!.toString() === this.chatMyId!.toString();
const t = this.chatMembers.find((i) => i.eid === this.data.eid); }
if (t) {
return t.name; created() {
} this.messageComponent = messageMapping.get(this.messageType) as string;
}
private get userName() {
if (this.chatMembers) {
const t = this.chatMembers.find((i) => i.eid === this.data.eid);
if (t) {
return t.name;
} }
return "";
} }
return "";
}
private get avatar() { private get avatar() {
const avatar = chat.getUserMapping(); const avatar = chat.getUserMapping();
if (this.isSendingMessage) { if (this.isSendingMessage) {
if (Object.getOwnPropertyNames(avatar).length > 0) { if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true; this.showHostAvatar = true;
} else { } else {
this.showHostAvatar = false; this.showHostAvatar = false;
}
if (avatar && this.chatMyId) {
const user = avatar[this.chatMyId];
if (user && user.avatar) {
return user.avatar;
}
}
} }
if (avatar && this.chatMyId) {
if (avatar && this.data) { const user = avatar[this.chatMyId];
if (Object.getOwnPropertyNames(avatar).length > 0) { if (user && user.avatar) {
this.showHostAvatar = true; return user.avatar;
} else {
this.showHostAvatar = false;
}
const value = avatar[this.data.eid];
if (value && value.avatar) {
return value.avatar;
} }
} }
}
return ""; if (avatar && this.data) {
if (Object.getOwnPropertyNames(avatar).length > 0) {
this.showHostAvatar = true;
} else {
this.showHostAvatar = false;
}
const value = avatar[this.data.eid];
if (value && value.avatar) {
return value.avatar;
}
} }
private get messageType() { return "";
const type = this.data?.type; }
if (type === "file") {
const name = this.messageBody?.msg.name; private get messageType() {
if (name) { const type = this.data?.type;
const size = this.messageBody?.msg.size; if (type === "file") {
if (size) { const name = this.messageBody?.msg.name;
const outImageSize = size > MAX_IMAGE_SIZE; if (name) {
if (!outImageSize && isImage(name)) { const size = this.messageBody?.msg.size;
return dto.MessageType.Image; if (size) {
const outImageSize = size > MAX_IMAGE_SIZE;
if (!outImageSize && isImage(name)) {
return dto.MessageType.Image;
}
const outSize = size > MAX_FILE_SIZE;
if (!outSize) {
if (isAudio(name)) {
return dto.MessageType.Voice;
} }
const outSize = size > MAX_FILE_SIZE; if (isVideo(name)) {
if (!outSize) { return dto.MessageType.Video;
if (isAudio(name)) {
return dto.MessageType.Voice;
}
if (isVideo(name)) {
return dto.MessageType.Video;
}
} }
} }
} }
} }
return type;
} }
return type;
}
private get isTextMessage() { private get isTextMessage() {
return this.messageType === dto.MessageType.Text; return this.messageType === dto.MessageType.Text;
} }
private get matchKeywords() { private get matchKeywords() {
if (this.isTextMessage && !this.isMyMessage) { if (this.isTextMessage && !this.isMyMessage) {
const m = this.messageBody.msg as { text: string }; const m = this.messageBody.msg as { text: string };
if (m && m.text) { if (m && m.text) {
const keywords = xim.getMatchedTextKeywords(); const keywords = xim.getMatchedTextKeywords();
return keywords.find((i) => m.text.includes(i)); return keywords.find((i) => m.text.includes(i));
}
} }
return false;
} }
return false;
}
private isCustomer() { private isCustomer() {
return !this.showReadSummary; return !this.showReadSummary;
} }
private openFile(url: string) { private openFile(url: string) {
if (this.isSendingMessage) { if (this.isSendingMessage) {
return; return;
}
if (this.failed) {
return;
}
const copy = { ...this.messageBody.msg };
copy.url = url;
this.$emit("open", { type: this.messageType, msg: copy });
} }
if (this.failed) {
private withdraw() { return;
ximInstance.withdraw(this.chatId!, this.data.id).finally(() => {
dbController
.removeMessage(this.chatId!, this.data.id)
.finally(() => {
this.executeWithDraw(this.data.id);
this.$emit("withdraw", this.data.id);
});
});
} }
const copy = { ...this.messageBody.msg };
copy.url = url;
this.$emit("open", { type: this.messageType, msg: copy });
}
private openReaderList(e: MouseEvent) { private withdraw() {
this.readerListOffset = e.x < 450; ximInstance.withdraw(this.chatId!, this.data.id).finally(() => {
this.readListVisibility = true; dbController
} .removeMessage(this.chatId!, this.data.id)
.finally(() => {
this.executeWithDraw(this.data.id);
this.$emit("withdraw", this.data.id);
});
});
}
private executeHandled() { private openReaderList(e: MouseEvent) {
this.setHandled({ this.readerListOffset = e.x < 450;
id: this.data.id, this.readListVisibility = true;
value: (this.defaultMessageHandledStatus = }
dto.MessageHandled.Handled),
});
this.closeKeywordPopover();
}
private ignoredKeyword() { private executeHandled() {
this.setHandled({ this.setHandled({
id: this.data.id, id: this.data.id,
value: (this.defaultMessageHandledStatus = value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Ignored), dto.MessageHandled.Handled),
}); });
this.closeKeywordPopover(); this.closeKeywordPopover();
} }
private closeKeywordPopover() { private ignoredKeyword() {
document.body.click(); this.setHandled({
} id: this.data.id,
value: (this.defaultMessageHandledStatus =
dto.MessageHandled.Ignored),
});
this.closeKeywordPopover();
}
private closeKeywordPopover() {
document.body.click();
} }
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.message-con { .message-con {
padding-bottom: 20px; padding-bottom: 20px;
margin-right: 15px; margin-right: 15px;
position: relative; position: relative;
&.my-message { &.my-message {
.msg-detail { .msg-detail {
background-color: #dbf2ff; background-color: #dbf2ff;
border-radius: 8px 0 8px 8px; border-radius: 8px 0 8px 8px;
}
.msg-read {
display: inline-block;
color: #bfe1ff;
margin-right: 15px;
user-select: none;
flex: none;
margin-top: auto;
}
.download-icon {
margin-right: 15px;
margin-left: 0;
margin-top: 0;
}
.withdraw {
color: #999;
position: absolute;
bottom: 0;
right: 0;
font-size: 12px;
display: none;
cursor: pointer;
}
&:hover {
.withdraw {
display: inline-block;
}
}
} }
&.offset-bottom { .msg-read {
margin-bottom: 30px; display: inline-block;
color: #bfe1ff;
margin-right: 15px;
user-select: none;
flex: none;
margin-top: auto;
} }
> i { .download-icon {
height: 16px; margin-right: 15px;
font-size: 16px; margin-left: 0;
margin-right: 10px; margin-top: 0;
} }
}
.msg-name { .withdraw {
font-size: 14px; color: #999;
color: #888; position: absolute;
text-align: right; bottom: 0;
margin-bottom: 3px; right: 0;
min-height: 16px; font-size: 12px;
&.algin-left { display: none;
text-align: left; cursor: pointer;
} }
}
.msg-content { &:hover {
text-align: right; .withdraw {
&.algin-left { display: inline-block;
text-align: left; }
} }
} }
.msg-detail { &.offset-bottom {
margin-top: 10px; margin-bottom: 30px;
font-size: 14px;
line-height: 20px;
background: #f5f6fa;
border-radius: 0px 8px 8px;
padding: 10px;
word-break: break-word;
/deep/ img {
max-width: 300px;
}
} }
.download-icon { > i {
cursor: pointer; height: 16px;
text-decoration: none; font-size: 16px;
margin-left: 15px; margin-right: 10px;
margin-top: 42px;
i {
color: #fff;
font-size: 14px;
}
} }
}
.no-selection {
user-select: none; .msg-name {
font-size: 14px;
color: #888;
text-align: right;
margin-bottom: 3px;
min-height: 16px;
&.algin-left {
text-align: left;
} }
}
.pointer { .msg-content {
cursor: pointer; text-align: right;
&.algin-left {
text-align: left;
} }
}
.all {
color: #4389f8; .msg-detail {
margin-top: 10px;
font-size: 14px;
line-height: 20px;
background: #f5f6fa;
border-radius: 0px 8px 8px;
padding: 10px;
word-break: break-word;
/deep/ img {
max-width: 300px;
} }
}
.match-keyword { .download-icon {
background-color: #fff3e0; cursor: pointer;
border-radius: 13px; text-decoration: none;
padding: 3px 8px; margin-left: 15px;
color: #e87005; margin-top: 42px;
position: absolute;
bottom: -10px;
left: 0;
cursor: pointer;
font-size: 12px;
&.handled { i {
color: #59ba7b; color: #fff;
background-color: #f0f0f0; font-size: 14px;
cursor: default; }
} }
.no-selection {
user-select: none;
}
.pointer {
cursor: pointer;
}
.all {
color: #4389f8;
}
.match-keyword {
background-color: #fff3e0;
border-radius: 13px;
padding: 3px 8px;
color: #e87005;
position: absolute;
bottom: -10px;
left: 0;
cursor: pointer;
font-size: 12px;
&.handled {
color: #59ba7b;
background-color: #f0f0f0;
cursor: default;
}
&.ignored { &.ignored {
color: #999; color: #999;
background-color: #f0f0f0; background-color: #f0f0f0;
cursor: default; cursor: default;
} }
i { i {
margin-right: 5px; margin-right: 5px;
}
} }
}
.keyword-action { .keyword-action {
list-style: none; list-style: none;
li { li {
list-style: none; list-style: none;
padding: 8px 10px; padding: 8px 10px;
color: #077aec; color: #077aec;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: #f5f6fa; background-color: #f5f6fa;
}
} }
} }
}
</style> </style>
<style lang="less"> <style lang="less">
.match-keyword-popover { .match-keyword-popover {
padding: 0; padding: 0;
} }
</style> </style>
...@@ -102,9 +102,8 @@ ...@@ -102,9 +102,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Ref, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";
import { MessageType } from "../model"; import { MessageType } from "../model";
import { ChatStore, chatStore } from "../store/model"; import { ChatStore, chatStore } from "../store/model";
import buttonThrottle from "../utils/button-throttle"; import buttonThrottle from "../utils/button-throttle";
......
<template> <template>
<el-dialog <el-dialog
:modal="false" :modal="false"
:before-close="close" :before-close="close"
:visible="value" :visible="value"
custom-class="hide-header show-close padding-0 width-auto" custom-class="hide-header show-close padding-0 width-auto"
> >
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="preview-title text-center">视频预览</div> <div class="preview-title text-center">视频预览</div>
<div class="d-flex justify-content-center" style="min-width: 300px"> <div class="d-flex justify-content-center" style="min-width: 300px">
<video <video
ref="video" ref="video"
v-if="file" v-if="file"
:src="file.url" :src="file.url"
controls controls
:style="style" :style="style"
></video> ></video>
</div> </div>
<div class="d-flex justify-content-center actions"> <div class="d-flex justify-content-center actions">
<span <span
class="d-flex align-items-center justify-content-center" class="d-flex align-items-center justify-content-center"
@click="set2Default" @click="set2Default"
>1:1</span >1:1</span
> >
<a <a
class="d-flex align-items-center justify-content-center" class="d-flex align-items-center justify-content-center"
:href="file.url | downloadUrl(getAttachment)" :href="file.url"
:download="getAttachment" :download="getAttachment"
> >
<i class="el-icon-download"></i> <i class="el-icon-download"></i>
</a> </a>
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
Component, Component,
Mixins, Model,
Model, Prop,
Prop, Ref,
Ref, Vue,
Watch Watch,
} from "vue-property-decorator"; } from "vue-property-decorator";
import { Filters } from '../mixin/filter';
@Component({ components: {} }) @Component({ components: {} })
export default class VideoPreview extends Mixins(Filters) { export default class VideoPreview extends Vue {
@Model("update") @Model("update")
private value!: boolean; private value!: boolean;
@Prop() @Prop()
private file!: { name: string; url: string }; private file!: { name: string; url: string };
@Ref("video") @Ref("video")
private video!: HTMLVideoElement; private video!: HTMLVideoElement;
private style: { private style: {
"max-height": number | string; "max-height": number | string;
"max-width": number | string; "max-width": number | string;
} = { } = {
"max-height": "800px", "max-height": "800px",
"max-width": "800px", "max-width": "800px",
}; };
private close() { private close() {
setTimeout( setTimeout(
() => (this.style = { "max-height": "300px", "max-width": "600px" }), () =>
300 (this.style = { "max-height": "300px", "max-width": "600px" }),
); 300
this.$emit("update", false); );
} this.$emit("update", false);
private set2Default() {
this.style = { "max-height": "1600px", "max-width": "1600px" };
}
private get getAttachment() {
if (this.file) {
return this.file.name;
} }
return "视频下载";
} private set2Default() {
this.style = { "max-height": "1600px", "max-width": "1600px" };
@Watch("value") }
private onOpen() {
if (this.value) { private get getAttachment() {
this.video?.load(); if (this.file) {
setTimeout(() => this.video?.play(), 100); return this.file.name;
} else { }
this.video?.pause(); return "视频下载";
}
@Watch("value")
private onOpen() {
if (this.value) {
this.video?.load();
setTimeout(() => this.video?.play(), 100);
} else {
this.video?.pause();
}
} }
}
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.preview-title { .preview-title {
font-size: 18px; font-size: 18px;
color: #333; color: #333;
margin-bottom: 15px; margin-bottom: 15px;
} }
.actions { .actions {
margin: 15px 0; margin: 15px 0;
> span, > span,
a { a {
width: 30px; width: 30px;
height: 30px; height: 30px;
background-color: #7a7b7d; background-color: #7a7b7d;
color: #fff; color: #fff;
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
i { i {
color: #fff; color: #fff;
font-size: 20px; font-size: 20px;
}
& + span {
margin-left: 15px;
}
} }
& + span { > a {
margin-left: 15px; margin-left: 15px;
} }
}
> a {
margin-left: 15px;
}
} }
</style> </style>
...@@ -59,10 +59,8 @@ ...@@ -59,10 +59,8 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { Component, Prop, Ref, Vue } from "vue-property-decorator";
import { namespace } from "vuex-class"; import { namespace } from "vuex-class";
import * as dto from "../model"; import * as dto from "../model";
import { unique } from "../utils"; import { unique } from "../utils";
import avatar from "@/customer-service/components/avatar.vue"; import avatar from "@/customer-service/components/avatar.vue";
import { ChatStore } from "@/customer-service/store/model"; import { ChatStore } from "@/customer-service/store/model";
import chat from "@/customer-service/xim/index"; import chat from "@/customer-service/xim/index";
......
...@@ -56,11 +56,11 @@ ...@@ -56,11 +56,11 @@
/> />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { EVENTS } from "@/EventConsts"; import { EVENTS } from "@/EventConsts";
import startProcessDialog from "@/views/workflow2/components/startProcessDialog.vue"; import startProcessDialog from "@/views/workflow2/components/startProcessDialog.vue";
import { Component, Prop, Ref, Vue } from "vue-property-decorator"; import { Component, Prop, Ref, Vue } from "vue-property-decorator";
import Chat from "../xim/index"; import Chat from "../xim/index";
enum WorkFlowStatus { enum WorkFlowStatus {
...@@ -68,12 +68,8 @@ enum WorkFlowStatus { ...@@ -68,12 +68,8 @@ enum WorkFlowStatus {
"已启动" = 1, "已启动" = 1,
"已完成" = 2, "已完成" = 2,
} }
const sdk = Chat.getSdk;
@Component({ @Component({ components: { startProcessDialog } })
components: {
startProcessDialog,
},
})
export default class WorkFlow extends Vue { export default class WorkFlow extends Vue {
@Ref("startProcessDialog") @Ref("startProcessDialog")
private readonly startProcessIns!: startProcessDialog; private readonly startProcessIns!: startProcessDialog;
...@@ -107,7 +103,7 @@ export default class WorkFlow extends Vue { ...@@ -107,7 +103,7 @@ export default class WorkFlow extends Vue {
private flowList = []; private flowList = [];
public async created() { public async created() {
this.flowList = await sdk() this.flowList = await Chat.getSdk()
.model(this.model_name) .model(this.model_name)
.workflow2() .workflow2()
.queryProcessByAssociateId(+this.id); .queryProcessByAssociateId(+this.id);
...@@ -130,6 +126,7 @@ export default class WorkFlow extends Vue { ...@@ -130,6 +126,7 @@ export default class WorkFlow extends Vue {
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.workflows { .workflows {
padding: 10px 30px; padding: 10px 30px;
......
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
<script lang="ts"> <script lang="ts">
import { Component, Ref, Vue, Watch } from "vue-property-decorator"; import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import { namespace } from "vuex-class"; import { namespace } from "vuex-class";
import { import {
getFileType, getFileType,
getSvg, getSvg,
......
import moment from "moment";
import Vue from "vue";
import Component from "vue-class-component";
// Define a super class component
@Component({
filters: {
downloadUrl(time: number) {
const format = {
sameDay: 'HH:mm',
nextDay: 'MM/DD',
nextWeek: 'MM/DD',
lastDay: '昨天HH:mm',
lastWeek: 'MM/DD',
sameElse: 'YYYY.MM.DD',
};
return moment(time).calendar(null, format);
}
},
})
export class Filters extends Vue {
}
...@@ -49,11 +49,6 @@ ...@@ -49,11 +49,6 @@
"debug": "=3.1.0" "debug": "=3.1.0"
} }
}, },
"moment": {
"version": "2.29.1",
"resolved": "http://npm.job.qinqinxiaobao.com/moment/-/moment-2.29.1.tgz",
"integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M="
},
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://npm.job.qinqinxiaobao.com/ms/-/ms-2.0.0.tgz", "resolved": "http://npm.job.qinqinxiaobao.com/ms/-/ms-2.0.0.tgz",
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
"dependencies": { "dependencies": {
"@types/sha1": "^1.1.2", "@types/sha1": "^1.1.2",
"axios": "^0.19.2", "axios": "^0.19.2",
"moment": "^2.29.1",
"qs": "~6.9.3", "qs": "~6.9.3",
"sha1": "^1.1.1", "sha1": "^1.1.1",
"vuex-class": "^0.3.2", "vuex-class": "^0.3.2",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment