Commit 342401e1 by panjiangyi

update dependency

parent 84b48c2e
.idea/*
.nyc_output
build
node_modules
test
coverage
*.log
yarn.lock
.DS_Store
\ No newline at end of file
...@@ -67,23 +67,23 @@ ...@@ -67,23 +67,23 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue, Ref } from "vue-property-decorator" import { Component, Ref, Vue, Watch } from "vue-property-decorator";
import { formatFileSize } from "../utils" import { namespace } from "vuex-class";
import { import {
getFileType, getFileType,
getSvg, getSvg,
MAX_IMAGE_SIZE_STRING, MAX_FILE_SIZE,
MAX_FILE_SIZE_STRING, MAX_FILE_SIZE_STRING,
MESSAGE_FILE_EMPTY,
MAX_IMAGE_SIZE, MAX_IMAGE_SIZE,
MESSAGE_IMAGE_TOO_LARGE, MAX_IMAGE_SIZE_STRING,
MAX_FILE_SIZE, MESSAGE_FILE_EMPTY,
MESSAGE_FILE_TOO_LARGE, MESSAGE_FILE_TOO_LARGE,
} from "../components/file-controller" MESSAGE_IMAGE_TOO_LARGE,
import { ChatStore } from "../store/model" } from "../components/file-controller";
import { namespace } from "vuex-class" import { EmojiService } from "../service/emoji";
import { Watch } from "vue-property-decorator" import { ChatStore } from "../store/model";
import { EmojiService } from "../service/emoji" import { formatFileSize } from "../utils";
export const enum InputMessageType { export const enum InputMessageType {
Text = "text", Text = "text",
...@@ -92,32 +92,32 @@ export const enum InputMessageType { ...@@ -92,32 +92,32 @@ export const enum InputMessageType {
} }
export interface InputMessageBody { export interface InputMessageBody {
text?: string text?: string;
url?: string url?: string;
name?: string name?: string;
size?: number size?: number;
} }
export interface InputMessage { export interface InputMessage {
type: InputMessageType type: InputMessageType;
body: InputMessageBody body: InputMessageBody;
file?: File | null file?: File | null;
} }
const chatStoreNamespace = namespace("chatStore") const chatStoreNamespace = namespace("chatStore");
const chatCache: { [key: number]: any } = {} const chatCache: { [key: number]: any } = {};
export const IMAGE_INFO_CLASS = "img-info" export const IMAGE_INFO_CLASS = "img-info";
export const FILE_INFO_CLASS = "file-info" export const FILE_INFO_CLASS = "file-info";
export function isImageOrFile(node: ChildNode) { export function isImageOrFile(node: ChildNode) {
const e = node as HTMLElement const e = node as HTMLElement;
return ( return (
e.classList && e.classList &&
(e.classList.contains(IMAGE_INFO_CLASS) || (e.classList.contains(IMAGE_INFO_CLASS) ||
e.classList.contains(FILE_INFO_CLASS)) e.classList.contains(FILE_INFO_CLASS))
) );
} }
@Component({ components: {} }) @Component({ components: {} })
...@@ -140,23 +140,23 @@ export default class Input extends Vue { ...@@ -140,23 +140,23 @@ export default class Input extends Vue {
@Watch("chatId") @Watch("chatId")
private onChatIdChanged(v: number, old: number) { private onChatIdChanged(v: number, old: number) {
if (old) { if (old) {
const current = this.getNodeListFromInputBox() const current = this.getNodeListFromInputBox();
if (current && current.length) { if (current && current.length) {
chatCache[old] = current chatCache[old] = current;
} }
} }
this.clearInput() this.clearInput();
if (v) { if (v) {
const cache = chatCache[v] const cache = chatCache[v];
if (cache) { if (cache) {
const e = document.querySelector( const e = document.querySelector(
"#chat-input-box" "#chat-input-box"
) as HTMLElement ) as HTMLElement;
if (e) { if (e) {
for (const node of cache as ChildNode[]) { for (const node of cache as ChildNode[]) {
e.appendChild(node) e.appendChild(node);
} }
} }
} }
...@@ -164,40 +164,40 @@ export default class Input extends Vue { ...@@ -164,40 +164,40 @@ export default class Input extends Vue {
} }
public mounted() { public mounted() {
this.messageInputBox.addEventListener("paste", this.handlePasteEvent) this.messageInputBox.addEventListener("paste", this.handlePasteEvent);
document.addEventListener("click", this.hideEmoji) document.addEventListener("click", this.hideEmoji);
document.addEventListener("selectionchange", this.handleSaveRange) document.addEventListener("selectionchange", this.handleSaveRange);
this.$onBeforeDestroy(() => { this.$onBeforeDestroy(() => {
document.removeEventListener("click", this.hideEmoji) document.removeEventListener("click", this.hideEmoji);
document.removeEventListener( document.removeEventListener(
"selectionchange", "selectionchange",
this.handleSaveRange this.handleSaveRange
) );
}) });
this.setupEmoji() this.setupEmoji();
this.focus() this.focus();
} }
public focus() { public focus() {
this.messageInputBox.focus() this.messageInputBox.focus();
} }
private clearInput() { private clearInput() {
this.messageInputBox.innerHTML = "" this.messageInputBox.innerHTML = "";
const input = document.getElementById( const input = document.getElementById(
"chat-upload-file" "chat-upload-file"
) as HTMLInputElement ) as HTMLInputElement;
if (input) { if (input) {
input.value = "" input.value = "";
} }
} }
private allowLoadImg() { private allowLoadImg() {
this.acceptType = "image/*" this.acceptType = "image/*";
} }
private allowLoadFile() { private allowLoadFile() {
this.acceptType = "*" this.acceptType = "*";
} }
private async handlePasteEvent(event: ClipboardEvent) { private async handlePasteEvent(event: ClipboardEvent) {
...@@ -206,39 +206,39 @@ export default class Input extends Vue { ...@@ -206,39 +206,39 @@ export default class Input extends Vue {
* 1、浏览器自带复制粘贴图片到输入框的功能,与js加工后的图片重复了, * 1、浏览器自带复制粘贴图片到输入框的功能,与js加工后的图片重复了,
* 2、默认复制粘贴功能会粘贴dom结构 * 2、默认复制粘贴功能会粘贴dom结构
* */ * */
event.preventDefault() event.preventDefault();
const items = event.clipboardData && event.clipboardData.items const items = event.clipboardData && event.clipboardData.items;
let html = "" let html = "";
const promiseArr = [] const promiseArr = [];
if (items && items.length) { if (items && items.length) {
// 检索剪切板items中类型带有image的 // 检索剪切板items中类型带有image的
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
if (items[i].kind === "file") { if (items[i].kind === "file") {
const file = items[i].getAsFile() const file = items[i].getAsFile();
if (file) { if (file) {
if (file.size <= 0) { if (file.size <= 0) {
this.$emit("error", MESSAGE_FILE_EMPTY) this.$emit("error", MESSAGE_FILE_EMPTY);
return return;
} }
if (this.isImage(file)) { if (this.isImage(file)) {
if (file.size >= MAX_IMAGE_SIZE) { if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE) this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
return return;
} }
html += this.buildImageHtml(file) html += this.buildImageHtml(file);
} else { } else {
if (file.size >= MAX_FILE_SIZE) { if (file.size >= MAX_FILE_SIZE) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE) this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return return;
} }
html += this.buildFileHtml(file) html += this.buildFileHtml(file);
} }
break break;
} }
} else { } else {
promiseArr.push( promiseArr.push(
new Promise<void>((done) => { new Promise<void>((reslove) => {
const contentType = items[i].type const contentType = items[i].type;
items[i].getAsString((k) => { items[i].getAsString((k) => {
/* /*
* items第一项是文本 * items第一项是文本
...@@ -247,56 +247,56 @@ export default class Input extends Vue { ...@@ -247,56 +247,56 @@ export default class Input extends Vue {
*/ */
if (i === 0) { if (i === 0) {
if (contentType === "text/plain") { if (contentType === "text/plain") {
html += k html += k;
} }
} else if (i === 1) { } else if (i === 1) {
const srcRegex = const srcRegex =
/<img[^>]+src="([^">]+)"\s+title="([^">]+)"/g /<img[^>]+src="([^">]+)"\s+title="([^">]+)"/g;
let result let result;
do { do {
result = srcRegex.exec(k) result = srcRegex.exec(k);
if (result) { if (result) {
const [, src, name] = result const [, src, name] = result;
html += `<img tabindex="-1" src="${src}" data-image='${JSON.stringify( html += `<img tabindex="-1" src="${src}" data-image='${JSON.stringify(
{ {
url: src, url: src,
name, name,
} }
)}'>` )}'>`;
html = html.replace(name, "") html = html.replace(name, "");
} }
} while (result) } while (result);
} }
done() reslove();
}) });
}) })
) );
} }
} }
} }
await Promise.all(promiseArr) await Promise.all(promiseArr);
if (html) { if (html) {
this.insertHtmlAtCaret(html) this.insertHtmlAtCaret(html);
} }
} }
private async handleSendMsg(e: Event) { private async handleSendMsg(e: Event) {
// 防止换行 // 防止换行
e.preventDefault() e.preventDefault();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
const data = this.getNodeListFromInputBox() const data = this.getNodeListFromInputBox();
this.$emit("send", data, resolve) this.$emit("send", data, resolve);
} catch (e) { } catch (e) {
this.$emit("error", e) this.$emit("error", e);
reject(e) reject(e);
} }
}).then(() => { }).then(() => {
this.clearInput() this.clearInput();
if (this.chatId) { if (this.chatId) {
chatCache[this.chatId] = [] chatCache[this.chatId] = [];
} }
}) });
} }
/** /**
...@@ -304,57 +304,57 @@ export default class Input extends Vue { ...@@ -304,57 +304,57 @@ export default class Input extends Vue {
* @returns 返回的是节点数组 * @returns 返回的是节点数组
*/ */
private getNodeListFromInputBox() { private getNodeListFromInputBox() {
this.messageInputBox.normalize() this.messageInputBox.normalize();
const nodes = Array.from(this.messageInputBox.childNodes) const nodes = Array.from(this.messageInputBox.childNodes);
return this.combine(nodes) return this.combine(nodes);
} }
/** /**
* 文本,链接等需要合并成纯文本发送 * 文本,链接等需要合并成纯文本发送
*/ */
private combine(nodes: ChildNode[]) { private combine(nodes: ChildNode[]) {
const sendingNodes: ChildNode[] = [] const sendingNodes: ChildNode[] = [];
let needCreateNewNode = false let needCreateNewNode = false;
let text = "" let text = "";
for (const item of nodes) { for (const item of nodes) {
if (!isImageOrFile(item) && item.textContent) { if (!isImageOrFile(item) && item.textContent) {
if (needCreateNewNode) { if (needCreateNewNode) {
text = "" text = "";
needCreateNewNode = false needCreateNewNode = false;
} }
text += item.textContent text += item.textContent;
} else { } else {
needCreateNewNode = true needCreateNewNode = true;
if (text) { if (text) {
this.checkTextLength(text) this.checkTextLength(text);
const node = document.createTextNode(text) const node = document.createTextNode(text);
sendingNodes.push(node) sendingNodes.push(node);
} }
sendingNodes.push(item) sendingNodes.push(item);
} }
} }
if (text) { if (text) {
this.checkTextLength(text) this.checkTextLength(text);
const node = document.createTextNode(text) const node = document.createTextNode(text);
sendingNodes.push(node) sendingNodes.push(node);
} }
return sendingNodes return sendingNodes;
} }
private checkTextLength(text: string) { private checkTextLength(text: string) {
if (text.length >= 4000) { if (text.length >= 4000) {
throw new Error("消息不能超过4000个字") throw new Error("消息不能超过4000个字");
} }
} }
private handleSaveRange() { private handleSaveRange() {
const sel = window.getSelection() const sel = window.getSelection();
if (sel && sel.rangeCount) { if (sel && sel.rangeCount) {
const range = sel.getRangeAt(0) const range = sel.getRangeAt(0);
const oldRange = this.getRange && this.getRange() const oldRange = this.getRange && this.getRange();
if ( if (
this.messageInputBox && this.messageInputBox &&
this.messageInputBox.contains(range.endContainer) this.messageInputBox.contains(range.endContainer)
...@@ -365,10 +365,10 @@ export default class Input extends Vue { ...@@ -365,10 +365,10 @@ export default class Input extends Vue {
range.endContainer === oldRange.endContainer && range.endContainer === oldRange.endContainer &&
range.endOffset === oldRange.endOffset range.endOffset === oldRange.endOffset
) { ) {
return return;
} }
this.saveRange && this.saveRange(range) this.saveRange && this.saveRange(range);
} }
} }
} }
...@@ -380,74 +380,74 @@ export default class Input extends Vue { ...@@ -380,74 +380,74 @@ export default class Input extends Vue {
* 在光标处插入元素 * 在光标处插入元素
*/ */
public insertHtmlAtCaret = (function () { public insertHtmlAtCaret = (function () {
let range: Range | null = null let range: Range | null = null;
return function (this: Input, html: string) { return function (this: Input, html: string) {
if (this.saveRange == null) { if (this.saveRange == null) {
this.saveRange = (alternate) => (range = alternate) this.saveRange = (alternate) => (range = alternate);
} }
if (this.getRange == null) { if (this.getRange == null) {
this.getRange = () => range this.getRange = () => range;
} }
const sel = window.getSelection() const sel = window.getSelection();
if (sel) { if (sel) {
if (range) { if (range) {
range.deleteContents() range.deleteContents();
sel.removeAllRanges() sel.removeAllRanges();
sel.addRange(range) sel.addRange(range);
} else { } else {
this.focus() this.focus();
range = sel.getRangeAt(0) range = sel.getRangeAt(0);
document.execCommand("selectAll") document.execCommand("selectAll");
window.getSelection()?.collapseToEnd() window.getSelection()?.collapseToEnd();
} }
} }
const el = document.createElement("div") const el = document.createElement("div");
el.innerHTML = html el.innerHTML = html;
const frag = document.createDocumentFragment() const frag = document.createDocumentFragment();
let node = null let node = null;
let lastNode = null let lastNode = null;
while ((node = el.firstChild)) { while ((node = el.firstChild)) {
lastNode = frag.appendChild(node) lastNode = frag.appendChild(node);
} }
range?.insertNode(frag) range?.insertNode(frag);
// Preserve the selection // Preserve the selection
if (lastNode) { if (lastNode) {
if (range) { if (range) {
range = range.cloneRange() range = range.cloneRange();
range.setStartAfter(lastNode) range.setStartAfter(lastNode);
range.collapse(true) range.collapse(true);
sel?.removeAllRanges() sel?.removeAllRanges();
sel?.addRange(range) sel?.addRange(range);
} }
} }
} };
})() })()
private selectEmoji(emoji: any) { private selectEmoji(emoji: any) {
this.insertHtmlAtCaret(emoji.emoji_chars) this.insertHtmlAtCaret(emoji.emoji_chars);
this.hideEmoji() this.hideEmoji();
} }
private isImage(file: File) { private isImage(file: File) {
return file.type.startsWith("image") return file.type.startsWith("image");
} }
private buildImageHtml(file: File) { private buildImageHtml(file: File) {
const url = URL.createObjectURL(file) const url = URL.createObjectURL(file);
return `<img class="${IMAGE_INFO_CLASS}" tabindex="-1" src="${url}" data-image='${JSON.stringify( return `<img class="${IMAGE_INFO_CLASS}" tabindex="-1" src="${url}" data-image='${JSON.stringify(
{ {
url, url,
name: file.name, name: file.name,
size: file.size, size: file.size,
} }
)}'>` )}'>`;
} }
private buildFileHtml(file: File) { private buildFileHtml(file: File) {
const extension = file.name.split(".") const extension = file.name.split(".");
const type = getFileType(file.name) const type = getFileType(file.name);
return `<div class="${FILE_INFO_CLASS}" tabindex="-1" title="${ return `<div class="${FILE_INFO_CLASS}" tabindex="-1" title="${
extension[extension.length - 1] extension[extension.length - 1]
}" data-file='${JSON.stringify({ }" data-file='${JSON.stringify({
...@@ -460,73 +460,73 @@ export default class Input extends Vue { ...@@ -460,73 +460,73 @@ export default class Input extends Vue {
file.size file.size
)}</div></div><span class="file-icon" title="${type}">${getSvg( )}</div></div><span class="file-icon" title="${type}">${getSvg(
type type
)}</span></div> ` // 注意</div>最后面有个空 )}</span></div> `; // 注意</div>最后面有个空
} }
private onChange(e: Event) { private onChange(e: Event) {
const target = e.target as HTMLElement const target = e.target as HTMLElement;
if (target) { if (target) {
const input = document.getElementById( const input = document.getElementById(
target.id as string target.id as string
) as HTMLInputElement ) as HTMLInputElement;
if (input) { if (input) {
const files = input.files const files = input.files;
if (files && files.length) { if (files && files.length) {
let html = "" let html = "";
for (let index = 0; index < files.length; index++) { for (let index = 0; index < files.length; index++) {
const file = files[index] const file = files[index];
if (file.size <= 0) { if (file.size <= 0) {
this.$emit("error", MESSAGE_FILE_EMPTY) this.$emit("error", MESSAGE_FILE_EMPTY);
return return;
} }
if (this.isImage(file)) { if (this.isImage(file)) {
if (file.size >= MAX_IMAGE_SIZE) { if (file.size >= MAX_IMAGE_SIZE) {
this.$emit("error", MESSAGE_IMAGE_TOO_LARGE) this.$emit("error", MESSAGE_IMAGE_TOO_LARGE);
return return;
} }
html += this.buildImageHtml(file) html += this.buildImageHtml(file);
} else { } else {
if (file.size >= MAX_FILE_SIZE) { if (file.size >= MAX_FILE_SIZE) {
this.$emit("error", MESSAGE_FILE_TOO_LARGE) this.$emit("error", MESSAGE_FILE_TOO_LARGE);
return return;
} }
html += this.buildFileHtml(file) html += this.buildFileHtml(file);
} }
} }
this.insertHtmlAtCaret(html) this.insertHtmlAtCaret(html);
} }
} }
} }
} }
private toggleEmoji() { private toggleEmoji() {
this.emojiPanelVisibility = !this.emojiPanelVisibility this.emojiPanelVisibility = !this.emojiPanelVisibility;
} }
private hideEmoji(e?: Event) { private hideEmoji(e?: Event) {
if (e && e.target) { if (e && e.target) {
const target = e.target as HTMLElement const target = e.target as HTMLElement;
if (target.closest(".emoji-picker")) { if (target.closest(".emoji-picker")) {
return return;
} }
} }
this.emojiPanelVisibility = false this.emojiPanelVisibility = false;
} }
private noop() { private noop() {
return
} }
private setupEmoji() { private setupEmoji() {
EmojiService.onReady(() => { EmojiService.onReady(() => {
const service = new EmojiService() const service = new EmojiService();
service.getEmoji().then((r) => { service.getEmoji().then((r) => {
if (r) { if (r) {
this.emoji = r.list this.emoji = r.list;
} }
}) });
}) });
} }
} }
</script> </script>
......
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@types/node": {
"version": "16.3.1",
"resolved": "http://npm.job.qinqinxiaobao.com/@types%2fnode/-/node-16.3.1.tgz",
"integrity": "sha1-JGkforDD7IwNNL/P1JXtrFWT67Q="
},
"@types/sha1": {
"version": "1.1.3",
"resolved": "http://npm.job.qinqinxiaobao.com/@types%2fsha1/-/sha1-1.1.3.tgz",
"integrity": "sha1-1Mw38X0JPFJDgtkDJrpydO9GN6g=",
"requires": {
"@types/node": "*"
}
},
"axios": {
"version": "0.19.2",
"resolved": "http://npm.job.qinqinxiaobao.com/axios/-/axios-0.19.2.tgz",
"integrity": "sha1-PqNsXYgY0NX4qKl6bTa4bNwAyyc=",
"requires": {
"follow-redirects": "1.5.10"
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "http://npm.job.qinqinxiaobao.com/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"charenc": {
"version": "0.0.2",
"resolved": "http://npm.job.qinqinxiaobao.com/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
},
"crypt": {
"version": "0.0.2",
"resolved": "http://npm.job.qinqinxiaobao.com/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
},
"debug": {
"version": "3.1.0",
"resolved": "http://npm.job.qinqinxiaobao.com/debug/-/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"requires": {
"ms": "2.0.0"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "http://npm.job.qinqinxiaobao.com/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio=",
"requires": {
"debug": "=3.1.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "http://npm.job.qinqinxiaobao.com/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
},
"get-intrinsic": {
"version": "1.1.1",
"resolved": "http://npm.job.qinqinxiaobao.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
"integrity": "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y=",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1"
}
},
"has": {
"version": "1.0.3",
"resolved": "http://npm.job.qinqinxiaobao.com/has/-/has-1.0.3.tgz",
"integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=",
"requires": {
"function-bind": "^1.1.1"
}
},
"has-symbols": {
"version": "1.0.2",
"resolved": "http://npm.job.qinqinxiaobao.com/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM="
},
"ms": {
"version": "2.0.0",
"resolved": "http://npm.job.qinqinxiaobao.com/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"object-inspect": {
"version": "1.11.0",
"resolved": "http://npm.job.qinqinxiaobao.com/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha1-nc6xRs7dQUig2eUauI00z1CZIrE="
},
"qs": {
"version": "6.10.1",
"resolved": "http://npm.job.qinqinxiaobao.com/qs/-/qs-6.10.1.tgz",
"integrity": "sha1-STFIL6jWR6Wqt5nFJx0hM7mB+2o=",
"requires": {
"side-channel": "^1.0.4"
}
},
"sha1": {
"version": "1.1.1",
"resolved": "http://npm.job.qinqinxiaobao.com/sha1/-/sha1-1.1.1.tgz",
"integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
"requires": {
"charenc": ">= 0.0.1",
"crypt": ">= 0.0.1"
}
},
"side-channel": {
"version": "1.0.4",
"resolved": "http://npm.job.qinqinxiaobao.com/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha1-785cj9wQTudRslxY1CkAEfpeos8=",
"requires": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"tweetnacl": {
"version": "1.0.3",
"resolved": "http://npm.job.qinqinxiaobao.com/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha1-rAr3FoBFjYpjeNDQ0FCrFAfTVZY="
},
"vuex-class": {
"version": "0.3.2",
"resolved": "http://npm.job.qinqinxiaobao.com/vuex-class/-/vuex-class-0.3.2.tgz",
"integrity": "sha1-x+lqB2wWghN9TSOo3P3GPyIOF6g="
},
"wamp.js": {
"version": "0.2.6",
"resolved": "http://npm.job.qinqinxiaobao.com/wamp.js/-/wamp.js-0.2.6.tgz",
"integrity": "sha512-ZQz4t94m2faHJnyFilRCmd3RaXXLOb8Z17LqgQeWoMJiyzrVkOwbl8n1CP5L3U7+M+8P83jjlPKwzKKQzN7DEA==",
"requires": {
"tweetnacl": "^1.0.1",
"ws": "^7.1.0"
}
},
"ws": {
"version": "7.5.3",
"resolved": "http://npm.job.qinqinxiaobao.com/ws/-/ws-7.5.3.tgz",
"integrity": "sha1-Fgg1tjx9l7+rQY/BuKn87SrAGnQ="
},
"xchat-client": {
"version": "2.0.20",
"resolved": "http://npm.job.qinqinxiaobao.com/xchat-client/-/xchat-client-2.0.20.tgz",
"integrity": "sha512-Fn9vay5sL2H55Vr4zndhvo7O1Ieskx9/ES9g/yWLfr8kiYMa0Q4uKh5ZJltTxk8xzAqXFHPbZFYJPJFZoyJ69g==",
"requires": {
"wamp.js": "^0.2.0"
}
}
}
}
{
"dependencies": {
"@types/sha1": "^1.1.2",
"axios": "^0.19.2",
"qs": "^6.9.3",
"sha1": "^1.1.1",
"vuex-class": "^0.3.2",
"xchat-client": "^2.0.19"
}
}
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