mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-15 05:12:49 +00:00
feat: 消息翻译支持切换语言
This commit is contained in:
parent
cce7523f45
commit
621726ab3b
@ -1543,12 +1543,13 @@ class DialogController extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* @api {get} api/dialog/msg/translation 32. 翻译消息
|
* @api {get} api/dialog/msg/translation 32. 翻译消息
|
||||||
*
|
*
|
||||||
* @apiDescription 将文本消息翻译成当前语言,需要token身份
|
* @apiDescription 需要token身份
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
* @apiGroup dialog
|
* @apiGroup dialog
|
||||||
* @apiName msg__translation
|
* @apiName msg__translation
|
||||||
*
|
*
|
||||||
* @apiParam {Number} msg_id 消息ID
|
* @apiParam {Number} msg_id 消息ID
|
||||||
|
* @apiParam {String} [language] 目标语言,默认当前语言
|
||||||
*
|
*
|
||||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||||
@ -1559,7 +1560,7 @@ class DialogController extends AbstractController
|
|||||||
User::auth();
|
User::auth();
|
||||||
//
|
//
|
||||||
$msg_id = intval(Request::input("msg_id"));
|
$msg_id = intval(Request::input("msg_id"));
|
||||||
$language = Base::headerOrInput('language');
|
$language = Base::inputOrHeader('language');
|
||||||
$targetLanguage = match ($language) {
|
$targetLanguage = match ($language) {
|
||||||
"zh" => "简体中文",
|
"zh" => "简体中文",
|
||||||
"zh-CHT" => "繁体中文",
|
"zh-CHT" => "繁体中文",
|
||||||
|
|||||||
@ -97,6 +97,16 @@ class Base
|
|||||||
return Base::nullShow(Request::header($key), Request::input($key));
|
return Base::nullShow(Request::header($key), Request::input($key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果input没有则通过header读取
|
||||||
|
* @param $key
|
||||||
|
* @return mixed|string
|
||||||
|
*/
|
||||||
|
public static function inputOrHeader($key)
|
||||||
|
{
|
||||||
|
return Base::nullShow(Request::input($key), Request::header($key));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取版本号
|
* 获取版本号
|
||||||
* @return string
|
* @return string
|
||||||
|
|||||||
@ -7,6 +7,9 @@
|
|||||||
<!--任务操作-->
|
<!--任务操作-->
|
||||||
<TaskOperation/>
|
<TaskOperation/>
|
||||||
|
|
||||||
|
<!--下拉菜单-->
|
||||||
|
<DropdownMenu/>
|
||||||
|
|
||||||
<!--全局浮窗加载器-->
|
<!--全局浮窗加载器-->
|
||||||
<FloatSpinner/>
|
<FloatSpinner/>
|
||||||
|
|
||||||
@ -40,10 +43,19 @@ import PreviewImageState from "./components/PreviewImage/state";
|
|||||||
import NetworkException from "./components/NetworkException";
|
import NetworkException from "./components/NetworkException";
|
||||||
import GuidePage from "./components/GuidePage";
|
import GuidePage from "./components/GuidePage";
|
||||||
import TaskOperation from "./pages/manage/components/TaskOperation";
|
import TaskOperation from "./pages/manage/components/TaskOperation";
|
||||||
|
import DropdownMenu from "./components/DropdownMenu";
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {TaskOperation, NetworkException, PreviewImageState, RightBottom, FloatSpinner, GuidePage},
|
components: {
|
||||||
|
DropdownMenu,
|
||||||
|
TaskOperation,
|
||||||
|
NetworkException,
|
||||||
|
PreviewImageState,
|
||||||
|
RightBottom,
|
||||||
|
FloatSpinner,
|
||||||
|
GuidePage
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
176
resources/assets/js/components/DropdownMenu.vue
Normal file
176
resources/assets/js/components/DropdownMenu.vue
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
<template>
|
||||||
|
<EDropdown
|
||||||
|
ref="dropdown"
|
||||||
|
trigger="click"
|
||||||
|
class="task-operation-dropdown"
|
||||||
|
placement="bottom"
|
||||||
|
size="small"
|
||||||
|
:style="styles"
|
||||||
|
@command="onCommand"
|
||||||
|
@visible-change="visibleChange">
|
||||||
|
<div ref="icon" class="task-operation-icon"></div>
|
||||||
|
<EDropdownMenu ref="dropdownMenu" slot="dropdown" class="task-operation-more-dropdown">
|
||||||
|
<li class="task-operation-more-warp small">
|
||||||
|
<ul>
|
||||||
|
<EDropdownItem
|
||||||
|
v-for="(item, key) in list"
|
||||||
|
:key="key"
|
||||||
|
:command="item.value"
|
||||||
|
:disabled="active === item.value">
|
||||||
|
<div class="item">{{item.label}}</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</EDropdownMenu>
|
||||||
|
</EDropdown>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {mapState} from "vuex";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
list: [], // 数据列表: [{label: '', value: ''}]
|
||||||
|
active: '', // 当前选中的值
|
||||||
|
onUpdate: null, // 选中后的回调函数
|
||||||
|
scrollHide: false, // 滚动立即隐藏
|
||||||
|
|
||||||
|
element: null,
|
||||||
|
target: null,
|
||||||
|
styles: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.target) {
|
||||||
|
this.target.removeEventListener('scroll', this.handlerEventListeners);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapState(['menuOperation'])
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
menuOperation(data) {
|
||||||
|
if (data.event && data.list) {
|
||||||
|
if (this.$refs.dropdown.visible && this.element === data.event.target) {
|
||||||
|
this.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const eventRect = data.event.target.getBoundingClientRect();
|
||||||
|
this.styles = {
|
||||||
|
left: `${eventRect.left}px`,
|
||||||
|
top: `${eventRect.top}px`,
|
||||||
|
width: `${eventRect.width}px`,
|
||||||
|
height: `${eventRect.height}px`,
|
||||||
|
}
|
||||||
|
this.list = data.list;
|
||||||
|
this.active = data.active && this.list.find(item => item.value === data.active) ? data.active : '';
|
||||||
|
this.onUpdate = typeof data.onUpdate === "function" ? data.onUpdate : null;
|
||||||
|
this.scrollHide = typeof data.scrollHide === "boolean" ? data.scrollHide : false;
|
||||||
|
//
|
||||||
|
this.$refs.icon.focus();
|
||||||
|
this.updatePopper();
|
||||||
|
this.show();
|
||||||
|
this.setupEventListeners(data.event)
|
||||||
|
} else {
|
||||||
|
this.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
show() {
|
||||||
|
this.$refs.dropdown.show()
|
||||||
|
},
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.$refs.dropdown.hide()
|
||||||
|
},
|
||||||
|
|
||||||
|
onCommand(value) {
|
||||||
|
this.hide();
|
||||||
|
if (typeof this.onUpdate === "function") {
|
||||||
|
this.onUpdate(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visibleChange(visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePopper() {
|
||||||
|
this.$nextTick(this.$refs.dropdownMenu.updatePopper)
|
||||||
|
},
|
||||||
|
|
||||||
|
setupEventListeners(event) {
|
||||||
|
this.element = event.target;
|
||||||
|
let target = this.getScrollParent(this.element);
|
||||||
|
if (target === window.document.body || target === window.document.documentElement) {
|
||||||
|
target = window;
|
||||||
|
}
|
||||||
|
if (this.target) {
|
||||||
|
if (this.target === target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.target.removeEventListener('scroll', this.handlerEventListeners);
|
||||||
|
}
|
||||||
|
this.target = target;
|
||||||
|
this.target.addEventListener('scroll', this.handlerEventListeners);
|
||||||
|
},
|
||||||
|
|
||||||
|
handlerEventListeners(e) {
|
||||||
|
if (!this.visible || !this.element) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.scrollHide) {
|
||||||
|
this.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scrollRect = e.target.getBoundingClientRect();
|
||||||
|
const eventRect = this.element.getBoundingClientRect();
|
||||||
|
if (eventRect.top < scrollRect.top || eventRect.top > scrollRect.top + scrollRect.height) {
|
||||||
|
this.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.styles = {
|
||||||
|
left: `${eventRect.left}px`,
|
||||||
|
top: `${eventRect.top}px`,
|
||||||
|
width: `${eventRect.width}px`,
|
||||||
|
height: `${eventRect.height}px`,
|
||||||
|
};
|
||||||
|
this.updatePopper();
|
||||||
|
},
|
||||||
|
|
||||||
|
getScrollParent(element) {
|
||||||
|
const parent = element.parentNode;
|
||||||
|
if (!parent) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
if (parent === window.document) {
|
||||||
|
if (window.document.body.scrollTop || window.document.body.scrollLeft) {
|
||||||
|
return window.document.body;
|
||||||
|
} else {
|
||||||
|
return window.document.documentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
['scroll', 'auto'].indexOf(this.getStyleComputedProperty(parent, 'overflow')) !== -1 ||
|
||||||
|
['scroll', 'auto'].indexOf(this.getStyleComputedProperty(parent, 'overflow-x')) !== -1 ||
|
||||||
|
['scroll', 'auto'].indexOf(this.getStyleComputedProperty(parent, 'overflow-y')) !== -1
|
||||||
|
) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
return this.getScrollParent(element.parentNode);
|
||||||
|
},
|
||||||
|
|
||||||
|
getStyleComputedProperty(element, property) {
|
||||||
|
const css = window.getComputedStyle(element, null);
|
||||||
|
return css[property];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -15,10 +15,10 @@
|
|||||||
<template v-if="translation">
|
<template v-if="translation">
|
||||||
<div class="content-divider">
|
<div class="content-divider">
|
||||||
<span></span>
|
<span></span>
|
||||||
<div class="divider-label">{{ translation.label }}</div>
|
<div class="divider-label translation-label" @click="viewText">{{ translation.label }}</div>
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-additional">{{translation.value}}</div>
|
<div class="content-additional">{{translation.content}}</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -26,7 +26,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import DialogMarkdown from "../DialogMarkdown.vue";
|
import DialogMarkdown from "../DialogMarkdown.vue";
|
||||||
import {languageName} from "../../../../language";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {DialogMarkdown},
|
components: {DialogMarkdown},
|
||||||
@ -35,11 +34,11 @@ export default {
|
|||||||
msg: Object,
|
msg: Object,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['audioPlaying', 'cacheTranslations']),
|
...mapState(['audioPlaying', 'cacheTranslations', 'cacheTranslationLanguage']),
|
||||||
|
|
||||||
translation() {
|
translation({cacheTranslations, msgId, cacheTranslationLanguage}) {
|
||||||
const translation = this.cacheTranslations.find(item => {
|
const translation = cacheTranslations.find(item => {
|
||||||
return item.key === `msg-${this.msgId}` && item.lang === languageName;
|
return item.key === `msg-${msgId}` && item.language === cacheTranslationLanguage;
|
||||||
});
|
});
|
||||||
return translation ? translation : null;
|
return translation ? translation : null;
|
||||||
},
|
},
|
||||||
@ -63,6 +62,9 @@ export default {
|
|||||||
}
|
}
|
||||||
return `${Math.max(1, seconds)}″`
|
return `${Math.max(1, seconds)}″`
|
||||||
},
|
},
|
||||||
|
viewText(e) {
|
||||||
|
this.$emit('viewText', e);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -6,11 +6,11 @@
|
|||||||
<template v-if="translation">
|
<template v-if="translation">
|
||||||
<div class="content-divider">
|
<div class="content-divider">
|
||||||
<span></span>
|
<span></span>
|
||||||
<div class="divider-label">{{ translation.label }}</div>
|
<div class="divider-label translation-label" @click="viewText">{{ translation.label }}</div>
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
<DialogMarkdown v-if="msg.type === 'md'" :text="translation.value"/>
|
<DialogMarkdown v-if="msg.type === 'md'" :text="translation.content"/>
|
||||||
<pre v-else v-html="$A.formatTextMsg(translation.value, userId)"></pre>
|
<pre v-else v-html="$A.formatTextMsg(translation.content, userId)"></pre>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -18,7 +18,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import DialogMarkdown from "../DialogMarkdown.vue";
|
import DialogMarkdown from "../DialogMarkdown.vue";
|
||||||
import {languageName} from "../../../../language";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {DialogMarkdown},
|
components: {DialogMarkdown},
|
||||||
@ -27,11 +26,11 @@ export default {
|
|||||||
msg: Object,
|
msg: Object,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['cacheTranslations']),
|
...mapState(['cacheTranslations', 'cacheTranslationLanguage']),
|
||||||
|
|
||||||
translation() {
|
translation({cacheTranslations, msgId, cacheTranslationLanguage}) {
|
||||||
const translation = this.cacheTranslations.find(item => {
|
const translation = cacheTranslations.find(item => {
|
||||||
return item.key === `msg-${this.msgId}` && item.lang === languageName;
|
return item.key === `msg-${msgId}` && item.language === cacheTranslationLanguage;
|
||||||
});
|
});
|
||||||
return translation ? translation : null;
|
return translation ? translation : null;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -672,6 +672,7 @@ import DialogGroupWordChain from "./DialogGroupWordChain";
|
|||||||
import DialogGroupVote from "./DialogGroupVote";
|
import DialogGroupVote from "./DialogGroupVote";
|
||||||
import DialogComplaint from "./DialogComplaint";
|
import DialogComplaint from "./DialogComplaint";
|
||||||
import touchclick from "../../../directives/touchclick";
|
import touchclick from "../../../directives/touchclick";
|
||||||
|
import {languageList} from "../../../language";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "DialogWrapper",
|
name: "DialogWrapper",
|
||||||
@ -884,7 +885,8 @@ export default {
|
|||||||
'keyboardType',
|
'keyboardType',
|
||||||
'keyboardHeight',
|
'keyboardHeight',
|
||||||
'safeAreaBottom',
|
'safeAreaBottom',
|
||||||
'formOptions'
|
'formOptions',
|
||||||
|
'cacheTranslationLanguage'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
...mapGetters(['isLoad']),
|
...mapGetters(['isLoad']),
|
||||||
@ -2994,27 +2996,43 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const {id: msg_id} = this.operateItem
|
const {id: msg_id} = this.operateItem
|
||||||
if (this.isLoad(`msg-${msg_id}`)) {
|
const key = `msg-${msg_id}`
|
||||||
|
if (this.isLoad(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$store.dispatch("setLoad", `msg-${msg_id}`)
|
this.$store.dispatch("setLoad", key)
|
||||||
this.$store.dispatch("call", {
|
this.$store.dispatch("call", {
|
||||||
url: 'dialog/msg/translation',
|
url: 'dialog/msg/translation',
|
||||||
data: {
|
data: {
|
||||||
msg_id
|
msg_id,
|
||||||
|
language: this.cacheTranslationLanguage
|
||||||
},
|
},
|
||||||
}).then(({data}) => {
|
}).then(({data}) => {
|
||||||
this.$store.dispatch("saveTranslation", {
|
this.$store.dispatch("saveTranslation", Object.assign(data, {key}));
|
||||||
key: `msg-${msg_id}`,
|
|
||||||
value: data.content,
|
|
||||||
});
|
|
||||||
}).catch(({msg}) => {
|
}).catch(({msg}) => {
|
||||||
$A.messageError(msg);
|
$A.messageError(msg);
|
||||||
}).finally(_ => {
|
}).finally(_ => {
|
||||||
this.$store.dispatch("cancelLoad", `msg-${msg_id}`)
|
this.$store.dispatch("cancelLoad", key)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openTranslationMenu(event) {
|
||||||
|
const list = Object.keys(languageList).map(item => ({
|
||||||
|
label: languageList[item],
|
||||||
|
value: item
|
||||||
|
}))
|
||||||
|
this.$store.state.menuOperation = {
|
||||||
|
event,
|
||||||
|
list,
|
||||||
|
active: this.cacheTranslationLanguage,
|
||||||
|
scrollHide: true,
|
||||||
|
onUpdate: async (language) => {
|
||||||
|
await this.$store.dispatch("setTranslationLanguage", language);
|
||||||
|
this.onTranslation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onCopy(data) {
|
onCopy(data) {
|
||||||
if (!$A.isJson(data)) {
|
if (!$A.isJson(data)) {
|
||||||
return
|
return
|
||||||
@ -3097,10 +3115,18 @@ export default {
|
|||||||
this.onPositionId(data.reply_id, data.msg_id)
|
this.onPositionId(data.reply_id, data.msg_id)
|
||||||
},
|
},
|
||||||
|
|
||||||
onViewText({target, clientX}, el) {
|
onViewText(event, el) {
|
||||||
if (this.operateVisible) {
|
if (this.operateVisible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const {target, clientX} = event
|
||||||
|
|
||||||
|
// 点击切换翻译
|
||||||
|
if (target.classList.contains('translation-label')) {
|
||||||
|
this.operateItem = this.findMsgByElement(el)
|
||||||
|
this.openTranslationMenu(event)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 打开审批详情
|
// 打开审批详情
|
||||||
let approveElement = target;
|
let approveElement = target;
|
||||||
@ -3144,14 +3170,7 @@ export default {
|
|||||||
if (clientX - target.getBoundingClientRect().x > 18) {
|
if (clientX - target.getBoundingClientRect().x > 18) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let listElement = el.parentElement;
|
const dataMsg = this.findMsgByElement(el)
|
||||||
while (listElement) {
|
|
||||||
if (listElement.classList.contains('dialog-scroller')) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (listElement.classList.contains('dialog-view')) {
|
|
||||||
const dataId = listElement.getAttribute("data-id")
|
|
||||||
const dataMsg = this.allMsgs.find(item => item.id == dataId) || {}
|
|
||||||
if (dataMsg.userid != this.userId) {
|
if (dataMsg.userid != this.userId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3162,14 +3181,14 @@ export default {
|
|||||||
target.setAttribute('data-list', 'checked')
|
target.setAttribute('data-list', 'checked')
|
||||||
}
|
}
|
||||||
this.$store.dispatch("setLoad", {
|
this.$store.dispatch("setLoad", {
|
||||||
key: `msg-${dataId}`,
|
key: `msg-${dataMsg.id}`,
|
||||||
delay: 600
|
delay: 600
|
||||||
})
|
})
|
||||||
this.$store.dispatch("call", {
|
this.$store.dispatch("call", {
|
||||||
url: 'dialog/msg/checked',
|
url: 'dialog/msg/checked',
|
||||||
data: {
|
data: {
|
||||||
dialog_id: this.dialogId,
|
dialog_id: this.dialogId,
|
||||||
msg_id: dataId,
|
msg_id: dataMsg.id,
|
||||||
index: dataIndex,
|
index: dataIndex,
|
||||||
checked: dataClass === 'checked' ? 0 : 1
|
checked: dataClass === 'checked' ? 0 : 1
|
||||||
},
|
},
|
||||||
@ -3183,17 +3202,28 @@ export default {
|
|||||||
}
|
}
|
||||||
$A.modalError(msg)
|
$A.modalError(msg)
|
||||||
}).finally(_ => {
|
}).finally(_ => {
|
||||||
this.$store.dispatch("cancelLoad", `msg-${dataId}`)
|
this.$store.dispatch("cancelLoad", `msg-${dataMsg.id}`)
|
||||||
});
|
});
|
||||||
break;
|
|
||||||
}
|
|
||||||
listElement = listElement.parentElement;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
findMsgByElement(el) {
|
||||||
|
let element = el.parentElement;
|
||||||
|
while (element) {
|
||||||
|
if (element.classList.contains('dialog-scroller')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (element.classList.contains('dialog-view')) {
|
||||||
|
const dataId = element.getAttribute("data-id")
|
||||||
|
return this.allMsgs.find(item => item.id == dataId) || {}
|
||||||
|
}
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
onViewFile(data) {
|
onViewFile(data) {
|
||||||
if (this.operateVisible) {
|
if (this.operateVisible) {
|
||||||
return
|
return
|
||||||
|
|||||||
32
resources/assets/js/store/actions.js
vendored
32
resources/assets/js/store/actions.js
vendored
@ -826,6 +826,7 @@ export default {
|
|||||||
const cacheLoginEmail = await $A.IDBString("cacheLoginEmail");
|
const cacheLoginEmail = await $A.IDBString("cacheLoginEmail");
|
||||||
const cacheFileSort = await $A.IDBJson("cacheFileSort");
|
const cacheFileSort = await $A.IDBJson("cacheFileSort");
|
||||||
const cacheTaskBrowse = await $A.IDBArray("cacheTaskBrowse")
|
const cacheTaskBrowse = await $A.IDBArray("cacheTaskBrowse")
|
||||||
|
const cacheTranslationLanguage = await $A.IDBString("cacheTranslationLanguage")
|
||||||
const cacheTranslations = await $A.IDBArray("cacheTranslations")
|
const cacheTranslations = await $A.IDBArray("cacheTranslations")
|
||||||
const cacheEmojis = await $A.IDBArray("cacheEmojis")
|
const cacheEmojis = await $A.IDBArray("cacheEmojis")
|
||||||
const userInfo = await $A.IDBJson("userInfo")
|
const userInfo = await $A.IDBJson("userInfo")
|
||||||
@ -836,6 +837,7 @@ export default {
|
|||||||
await $A.IDBSet("cacheLoginEmail", cacheLoginEmail);
|
await $A.IDBSet("cacheLoginEmail", cacheLoginEmail);
|
||||||
await $A.IDBSet("cacheFileSort", cacheFileSort);
|
await $A.IDBSet("cacheFileSort", cacheFileSort);
|
||||||
await $A.IDBSet("cacheTaskBrowse", cacheTaskBrowse);
|
await $A.IDBSet("cacheTaskBrowse", cacheTaskBrowse);
|
||||||
|
await $A.IDBSet("cacheTranslationLanguage", cacheTranslationLanguage);
|
||||||
await $A.IDBSet("cacheTranslations", cacheTranslations);
|
await $A.IDBSet("cacheTranslations", cacheTranslations);
|
||||||
await $A.IDBSet("cacheEmojis", cacheEmojis);
|
await $A.IDBSet("cacheEmojis", cacheEmojis);
|
||||||
await $A.IDBSet("cacheVersion", state.cacheVersion)
|
await $A.IDBSet("cacheVersion", state.cacheVersion)
|
||||||
@ -867,6 +869,7 @@ export default {
|
|||||||
state.cacheTasks = await $A.IDBArray("cacheTasks")
|
state.cacheTasks = await $A.IDBArray("cacheTasks")
|
||||||
state.cacheProjectParameter = await $A.IDBArray("cacheProjectParameter")
|
state.cacheProjectParameter = await $A.IDBArray("cacheProjectParameter")
|
||||||
state.cacheTaskBrowse = await $A.IDBArray("cacheTaskBrowse")
|
state.cacheTaskBrowse = await $A.IDBArray("cacheTaskBrowse")
|
||||||
|
state.cacheTranslationLanguage = await $A.IDBString("cacheTranslationLanguage")
|
||||||
state.cacheTranslations = await $A.IDBArray("cacheTranslations")
|
state.cacheTranslations = await $A.IDBArray("cacheTranslations")
|
||||||
state.dialogMsgs = await $A.IDBArray("dialogMsgs")
|
state.dialogMsgs = await $A.IDBArray("dialogMsgs")
|
||||||
state.fileLists = await $A.IDBArray("fileLists")
|
state.fileLists = await $A.IDBArray("fileLists")
|
||||||
@ -874,6 +877,9 @@ export default {
|
|||||||
state.callAt = await $A.IDBArray("callAt")
|
state.callAt = await $A.IDBArray("callAt")
|
||||||
state.cacheEmojis = await $A.IDBArray("cacheEmojis")
|
state.cacheEmojis = await $A.IDBArray("cacheEmojis")
|
||||||
|
|
||||||
|
// TranslationLanguage
|
||||||
|
typeof languageList[state.cacheTranslationLanguage] === "undefined" && (state.cacheTranslationLanguage = languageName)
|
||||||
|
|
||||||
// 会员信息
|
// 会员信息
|
||||||
if (state.userInfo.userid) {
|
if (state.userInfo.userid) {
|
||||||
state.userId = state.userInfo.userid = $A.runNum(state.userInfo.userid)
|
state.userId = state.userInfo.userid = $A.runNum(state.userInfo.userid)
|
||||||
@ -3351,24 +3357,32 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* 保存翻译
|
* 保存翻译
|
||||||
* @param state
|
* @param state
|
||||||
* @param dispatch
|
* @param data {key, content, language}
|
||||||
* @param data {key, value}
|
|
||||||
*/
|
*/
|
||||||
saveTranslation({state, dispatch}, data) {
|
saveTranslation({state}, data) {
|
||||||
if (!$A.isJson(data)) {
|
if (!$A.isJson(data)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const item = state.cacheTranslations.find(item => item.key == data.key && item.lang == languageName)
|
const translation = state.cacheTranslations.find(item => item.key == data.key && item.language == data.language)
|
||||||
if (item) {
|
if (translation) {
|
||||||
item.value = data.value
|
translation.content = data.content
|
||||||
} else {
|
} else {
|
||||||
data.lang = languageName
|
const label = languageList[data.language] || data.language
|
||||||
data.label = languageList[languageName] || languageName
|
state.cacheTranslations.push(Object.assign(data, {label}))
|
||||||
state.cacheTranslations.push(data)
|
|
||||||
}
|
}
|
||||||
$A.IDBSave("cacheTranslations", state.cacheTranslations.slice(-200))
|
$A.IDBSave("cacheTranslations", state.cacheTranslations.slice(-200))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置翻译语言
|
||||||
|
* @param state
|
||||||
|
* @param language
|
||||||
|
*/
|
||||||
|
setTranslationLanguage({state}, language) {
|
||||||
|
state.cacheTranslationLanguage = language
|
||||||
|
$A.IDBSave('cacheTranslationLanguage', language);
|
||||||
|
},
|
||||||
|
|
||||||
/** *****************************************************************************************/
|
/** *****************************************************************************************/
|
||||||
/** ************************************* loads *********************************************/
|
/** ************************************* loads *********************************************/
|
||||||
/** *****************************************************************************************/
|
/** *****************************************************************************************/
|
||||||
|
|||||||
4
resources/assets/js/store/state.js
vendored
4
resources/assets/js/store/state.js
vendored
@ -234,5 +234,9 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 翻译
|
// 翻译
|
||||||
|
cacheTranslationLanguage: '',
|
||||||
cacheTranslations: [],
|
cacheTranslations: [],
|
||||||
|
|
||||||
|
// 下拉菜单操作
|
||||||
|
menuOperation: {}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1413,6 +1413,10 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user