no message

This commit is contained in:
kuaifan 2022-05-30 14:27:28 +08:00
parent 72f7cc927c
commit cb2ad20e36
30 changed files with 581 additions and 429 deletions

View File

@ -1,7 +1,7 @@
<template>
<div id="app">
<keep-alive>
<router-view class="child-view" :class="{'view-768': $store.state.windowMax768}"></router-view>
<router-view class="child-view"></router-view>
</keep-alive>
<Spinner/>
<RightBottom/>
@ -58,7 +58,7 @@ export default {
},
computed: {
...mapState(['ws', 'userId', 'userToken']),
...mapState(['ws', 'userId', 'userToken', 'windowMax768']),
},
watch: {

View File

@ -6,7 +6,6 @@
</div>
<ul ref="ganttItem"
class="gantt-item"
:style="ganttItemStyle"
@scroll="itemScrollListener"
@mouseenter="mouseType='item'">
<li v-for="(item, key) in lists" :key="key">
@ -103,7 +102,6 @@ export default {
}
},
computed: {
...mapState(['touchBackInProgress']),
monthNum() {
const {ganttWidth, dateWidth} = this;
return Math.floor(ganttWidth / dateWidth / 30) + 2
@ -232,13 +230,6 @@ export default {
return customStyle
}
},
ganttItemStyle() {
const style = {}
if (this.touchBackInProgress) {
style.overflow = 'hidden !important';
}
return style
},
},
methods: {
itemScrollListener(e) {
@ -376,265 +367,3 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.common-gantt {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: row;
align-items: self-start;
color: #747a81;
* {
box-sizing: border-box;
}
.gantt-left {
flex-grow:0;
flex-shrink:0;
height: 100%;
background-color: #ffffff;
position: relative;
display: flex;
flex-direction: column;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 1px;
background-color: rgba(237, 241, 242, 0.75);
}
.gantt-title {
height: 76px;
flex-grow: 0;
flex-shrink: 0;
background-color: #F9FAFB;
padding-left: 12px;
overflow: hidden;
.gantt-title-text {
line-height: 100px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 600;
}
}
.gantt-item {
transform: translateZ(0);
max-height: 100%;
overflow: auto;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
> li {
height: 40px;
border-bottom: 1px solid rgba(237, 241, 242, 0.75);
position: relative;
display: flex;
align-items: center;
padding-left: 12px;
&:hover {
.item-icon {
display: flex;
}
}
.item-overdue {
flex-grow:0;
flex-shrink:0;
color: #ffffff;
margin-right: 4px;
background-color: #ff0000;
padding: 1px 3px;
border-radius: 3px;
font-size: 12px;
line-height: 18px;
}
.item-title {
flex: 1;
padding-right: 12px;
cursor: default;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.complete {
text-decoration: line-through;
}
&.overdue {
font-weight: 600;
}
}
.item-icon {
display: none;
align-items: center;
justify-content: center;
width: 32px;
margin-right: 2px;
font-size: 16px;
color: #888888;
}
}
}
}
.gantt-right {
flex: 1;
height: 100%;
background-color: #ffffff;
position: relative;
overflow: hidden;
.gantt-chart {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
transform: translateZ(0);
.gantt-month {
display: flex;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
height: 26px;
line-height: 20px;
font-size: 14px;
background-color: #F9FAFB;
> li {
flex-grow: 0;
flex-shrink: 0;
height: 100%;
position: relative;
overflow: hidden;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 1px;
height: 100%;
background-color: rgba(237, 241, 242, 0.75);
}
.month-format {
overflow: hidden;
white-space: nowrap;
padding: 6px 6px 0;
}
}
}
.gantt-date {
display: flex;
align-items: center;
position: absolute;
top: 26px;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
cursor: move;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50px;
background-color: #F9FAFB;
}
> li {
flex-grow: 0;
flex-shrink: 0;
height: 100%;
position: relative;
overflow: hidden;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 1px;
height: 100%;
background-color: rgba(237, 241, 242, 0.75);
}
.date-format {
overflow: hidden;
white-space: nowrap;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 44px;
.format-day {
line-height: 28px;
font-size: 18px;
}
.format-week {
line-height: 16px;
font-weight: 300;
font-size: 13px;
}
}
}
}
.gantt-timeline {
position: absolute;
top: 76px;
left: 0;
right: 0;
bottom: 0;
z-index: 3;
overflow-x: hidden;
overflow-y: auto;
> li {
cursor: default;
height: 40px;
border-bottom: 1px solid rgba(237, 241, 242, 0.75);
position: relative;
.timeline-item {
position: absolute;
top: 0;
touch-action: none;
pointer-events: auto;
padding: 4px;
margin-top: 4px;
background: #e74c3c;
border-radius: 18px;
color: #fff;
display: flex;
align-items: center;
will-change: contents;
height: 32px;
.timeline-title {
touch-action: none;
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 4px;
margin-right: 10px;
}
.timeline-resizer {
height: 22px;
touch-action: none;
width: 8px;
background: rgba(255,255,255,0.1);
cursor: ew-resize;
flex-shrink: 0;
will-change: visibility;
position: absolute;
top: 5px;
right: 5px;
}
}
}
}
}
}
}
</style>

View File

@ -50,8 +50,13 @@ export default {
},
watch: {
show(s) {
this.$store.state.touchBackInProgress = s;
show(state) {
if (state) {
document.body.classList.add("touch-back");
} else {
document.body.classList.remove("touch-back");
}
this.$store.state.touchBackInProgress = state;
}
},

View File

@ -26,7 +26,7 @@
</div>
<div v-if="$Platform === 'mac'" class="notification-tip">{{$L('离最新版本只有一步之遥了重新启动应用即可完成更新')}}</div>
</div>
<MarkdownPreview class="notification-body overlay-y" :initialValue="updateNote"/>
<MarkdownPreview class="notification-body scrollbar-overlay" :initialValue="updateNote"/>
<div slot="footer" class="adaption">
<Button type="default" @click="updateShow=false">{{$L('稍后')}}</Button>
<Button type="primary" :loading="updateIng" @click="updateQuitAndInstall">{{$L($Platform === 'mac' ? '重新启动' : '立即升级')}}</Button>

View File

@ -0,0 +1,70 @@
const isSupportTouch = "ontouchend" in document;
// 长按指令
const longpress = {
bind: function (el, binding) {
if (!isSupportTouch) {
return
}
let delay = 500,
callback = binding.value;
if ($A.isJson(binding.value)) {
delay = binding.value.delay || 500;
callback = binding.value.callback;
}
if (typeof callback !== 'function') {
throw 'callback must be a function'
}
// 定义变量
let pressTimer = null
let isCall = false
// 创建计时器( 500秒后执行函数
el.__longpressStart__ = (e) => {
if (e.type === 'click' && e.button !== 0) {
return
}
isCall = false
if (pressTimer === null) {
pressTimer = setTimeout(() => {
isCall = true
callback(e, el)
}, delay)
}
}
// 取消计时器
el.__longpressCancel__ = (e) => {
if (pressTimer !== null) {
clearTimeout(pressTimer)
pressTimer = null
}
}
// 点击拦截
el.__longpressClick__ = (e) => {
if (isCall) {
e.preventDefault()
e.stopPropagation()
}
el.__longpressCancel__(e)
}
// 添加事件监听器
el.addEventListener('touchstart', el.__longpressStart__)
// 取消计时器
el.addEventListener('click', el.__longpressClick__)
el.addEventListener('touchmove', el.__longpressCancel__);
el.addEventListener('touchend', el.__longpressCancel__)
el.addEventListener('touchcancel', el.__longpressCancel__)
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('touchstart', el.__longpressStart__)
el.removeEventListener('click', el.__longpressClick__)
el.removeEventListener('touchmove', el.__longpressCancel__)
el.removeEventListener('touchend', el.__longpressCancel__)
el.removeEventListener('touchcancel', el.__longpressCancel__)
delete el.__longpressStart__;
delete el.__longpressClick__;
delete el.__longpressCancel__;
}
}
export default longpress

View File

@ -18,17 +18,29 @@ export default {
binding.value("up");
}
};
el.addEventListener(isSupportTouch ? 'touchstart' : 'mousedown', el.__touchMouseDown__);
document.addEventListener(isSupportTouch ? 'touchmove' : 'mousemove', el.__touchMouseMove__);
document.addEventListener(isSupportTouch ? 'touchend' : 'mouseup', el.__touchMouseUp__);
if (isSupportTouch) {
el.addEventListener('touchstart', el.__touchMouseDown__);
el.addEventListener('touchmove', el.__touchMouseMove__);
el.addEventListener('touchend', el.__touchMouseUp__);
} else {
el.addEventListener('mousedown', el.__touchMouseDown__);
document.addEventListener('mousemove', el.__touchMouseMove__);
document.addEventListener('mouseup', el.__touchMouseUp__);
}
},
update () {
},
unbind (el) {
el.removeEventListener(isSupportTouch ? 'touchstart' : 'mousedown', el.__touchMouseDown__);
document.removeEventListener(isSupportTouch ? 'touchmove' : 'mousemove', el.__touchMouseMove__);
document.removeEventListener(isSupportTouch ? 'touchend' : 'mouseup', el.__touchMouseUp__);
if (isSupportTouch) {
el.removeEventListener('touchstart', el.__touchMouseDown__);
el.removeEventListener('touchmove', el.__touchMouseMove__);
el.removeEventListener('touchend', el.__touchMouseUp__);
} else {
el.removeEventListener('mousedown', el.__touchMouseDown__);
document.removeEventListener('mousemove', el.__touchMouseMove__);
document.removeEventListener('mouseup', el.__touchMouseUp__);
}
delete el.__touchMouseDown__;
delete el.__touchMouseMove__;
delete el.__touchMouseUp__;

View File

@ -1077,6 +1077,17 @@
return {width: parseInt(tempWidth), height: parseInt(tempHeight)};
}
return {width, height};
},
/**
* 获取元素属性
* @param el
* @param attrName
* @param def
* @returns {Property<any>|string|string}
*/
getAttr(el, attrName, def = "") {
return el ? el.getAttribute(attrName) : def;
}
});

View File

@ -135,7 +135,7 @@
</template>
</DropdownMenu>
</Dropdown>
<ul :class="overlayClass" @scroll="handleClickTopOperateOutside">
<ul :class="listClassName" @scroll="operateVisible = false">
<li @click="toggleRoute('dashboard')" :class="classNameRoute('dashboard')">
<i class="taskfont">&#xe6fb;</i>
<div class="menu-title">{{$L('仪表盘')}}</div>
@ -156,14 +156,15 @@
<i class="taskfont">&#xe6f3;</i>
<div class="menu-title">{{$L('文件')}}</div>
</li>
<li ref="projectWrapper" class="menu-project">
<ul :class="overlayClass" @scroll="handleClickTopOperateOutside">
<li class="menu-project">
<ul ref="projectWrapper" :class="listClassName" @scroll="operateVisible = false">
<li
v-for="(item, key) in projectLists"
:ref="`project_${item.id}`"
:key="key"
:class="classNameProject(item)"
@click="toggleRoute('project', {projectId: item.id})"
@contextmenu.prevent.stop="handleRightClick($event, item)">
@contextmenu.prevent.stop="handleContextmenu($event, item)">
<div class="project-h1">
<em @click.stop="toggleOpenMenu(item.id)"></em>
<div class="title">{{item.name}}</div>
@ -183,24 +184,24 @@
</p>
</div>
</li>
<li v-if="loadIng > 0" class="loading"><Loading/></li>
</ul>
<Loading v-if="loadIng > 0"/>
<div class="top-operate" :style="topOperateStyles">
<Dropdown
trigger="custom"
:visible="topOperateVisible"
transfer-class-name="page-file-dropdown-menu"
@on-clickoutside="handleClickTopOperateOutside"
transfer>
<DropdownMenu slot="list">
<DropdownItem @click.native="handleTopClick">
{{ $L(topOperateItem.top_at ? '取消置顶' : '置顶该项目') }}
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</li>
</ul>
<div class="operate-position" :style="operateStyles">
<Dropdown
trigger="custom"
:visible="operateVisible"
@on-clickoutside="operateVisible = false"
transfer>
<div :style="{height: operateStyles.height}"></div>
<DropdownMenu slot="list">
<DropdownItem @click.native="handleTopClick">
{{ $L(operateItem.top_at ? '取消置顶' : '置顶该项目') }}
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
<div
v-if="projectTotal > 20"
class="manage-project-search">
@ -226,7 +227,7 @@
<div class="manage-box-main">
<keep-alive>
<router-view class="manage-box-view overlay"></router-view>
<router-view class="manage-box-view"></router-view>
</keep-alive>
</div>
@ -437,9 +438,9 @@ export default {
reportTabs: "my",
reportUnreadNumber: 0,
topOperateStyles: {},
topOperateVisible: false,
topOperateItem: {},
operateStyles: {},
operateVisible: false,
operateItem: {},
}
},
@ -620,10 +621,10 @@ export default {
return data;
},
overlayClass() {
listClassName() {
return {
'overlay-y': true,
'overlay-none': this.topOperateVisible === true,
'scrollbar-overlay': true,
'scrollbar-hidden': this.operateVisible === true,
}
},
@ -805,7 +806,7 @@ export default {
return {
"active": this.routeName === 'manage-project' && this.$route.params.projectId == item.id,
"open-menu": this.openMenu[item.id] === true,
"operate": item.id == this.topOperateItem.id && this.topOperateVisible
"operate": item.id == this.operateItem.id && this.operateVisible
};
},
@ -963,34 +964,31 @@ export default {
}, typeof timeout === "number" ? timeout : 1000)
},
handleRightClick(event, item) {
this.handleClickTopOperateOutside();
this.topOperateItem = item;
handleContextmenu(event, item) {
this.operateVisible = false;
this.operateItem = $A.isJson(item) ? item : {};
this.$nextTick(() => {
const projectWrap = this.$refs.projectWrapper;
const projectBounding = projectWrap.getBoundingClientRect();
this.topOperateStyles = {
left: `${event.clientX - projectBounding.left}px`,
top: `${event.clientY - projectBounding.top}px`
};
this.topOperateVisible = true;
const dialogRect = this.$refs[`project_${item.id}`][0].getBoundingClientRect();
const wrapRect = this.$refs.projectWrapper.getBoundingClientRect();
this.operateStyles = {
left: `${event.clientX - wrapRect.left}px`,
top: `${dialogRect.top}px`,
height: dialogRect.height + 'px',
}
this.operateVisible = true;
})
},
handleClickTopOperateOutside() {
this.topOperateVisible = false;
},
handleTopClick() {
this.$store.dispatch("call", {
url: 'project/top',
data: {
project_id: this.topOperateItem.id,
project_id: this.operateItem.id,
},
}).then(({data}) => {
this.$store.dispatch("saveProject", data);
this.$nextTick(() => {
let active = this.$refs.projectWrapper.querySelector(".active")
const active = this.$refs.projectWrapper.querySelector(".active")
if (active) {
$A.scrollToView(active, {
behavior: 'instant',

View File

@ -1,6 +1,6 @@
<template>
<div class="chat-emoji-wrapper">
<ul class="chat-emoji-box overlay-y" :class="[type, 'no-dark-content']">
<ul class="chat-emoji-box scrollbar-overlay" :class="[type, 'no-dark-content']">
<li v-for="item in list" @click="onSelect(item)">
<img v-if="item.type === 'emoticon'" :src="item.src" :title="item.name" :alt="item.name"/>
<span v-else v-html="item.html" :title="item.name"></span>

View File

@ -65,13 +65,13 @@
popper-class="dialog-wrapper-read-poptip"
placement="left-end">
<div class="read-poptip-content">
<ul class="read overlay-y">
<ul class="read scrollbar-overlay">
<li class="read-title"><em>{{ readList.length }}</em>{{ $L('已读') }}</li>
<li v-for="item in readList">
<UserAvatar :userid="item.userid" :size="26" showName/>
</li>
</ul>
<ul class="unread overlay-y">
<ul class="unread scrollbar-overlay">
<li class="read-title"><em>{{ unreadList.length }}</em>{{ $L('未读') }}</li>
<li v-for="item in unreadList">
<UserAvatar :userid="item.userid" :size="26" showName/>

View File

@ -65,10 +65,7 @@
</slot>
<DynamicScroller
ref="scroller"
class="dialog-scroller"
:class="{
'overlay-y': !touchBackInProgress
}"
class="dialog-scroller scrollbar-overlay"
:disabled="touchBackInProgress"
:items="allMsgs"
:min-item-size="58"

View File

@ -92,7 +92,7 @@
</div>
</div>
</div>
<div v-if="tabTypeActive === 'column'" class="project-column" :style="columnStyle">
<div v-if="tabTypeActive === 'column'" class="project-column">
<Draggable
:list="columnList"
:animation="150"
@ -138,7 +138,7 @@
<Icon class="last" type="md-add" @click="addTopShow(column.id, true)" />
</div>
</div>
<div :ref="'column_' + column.id" class="column-task overlay-y">
<div :ref="'column_' + column.id" class="column-task scrollbar-overlay">
<div v-if="!!columnTopShow[column.id]" class="task-item additem">
<TaskAddSimple
:column-id="column.id"
@ -230,7 +230,7 @@
</li>
</Draggable>
</div>
<div v-else-if="tabTypeActive === 'table'" class="project-table overlay-y" :style="columnStyle">
<div v-else-if="tabTypeActive === 'table'" class="project-table scrollbar-overlay">
<div class="project-table-head">
<Row class="task-row">
<Col span="12"># {{$L('任务名称')}}</Col>
@ -538,7 +538,6 @@ export default {
computed: {
...mapState([
'windowWidth',
'touchBackInProgress',
'userId',
'cacheDialogs',
@ -575,14 +574,6 @@ export default {
return style
},
columnStyle() {
const style = {}
if (this.touchBackInProgress) {
style.overflow = 'hidden !important';
}
return style
},
userWaitRemove() {
const {userids, useridbak} = this.userData;
if (!userids) {

View File

@ -27,7 +27,7 @@
<div class="taskflow-config-table">
<div class="taskflow-config-table-left-container">
<div class="taskflow-config-table-column-header left-header">{{$L('配置项')}}</div>
<div :ref="`overlay_${data.id}`" class="taskflow-config-table-column-body overlay-y">
<div :ref="`overlay_${data.id}`" class="taskflow-config-table-column-body scrollbar-overlay">
<div class="taskflow-config-table-block">
<div class="taskflow-config-table-block-title">{{$L('设置状态为')}}</div>
<div class="taskflow-config-table-block-item">
@ -113,7 +113,7 @@
</EDropdown>
</div>
</div>
<div :ref="`overlay_${data.id}`" class="taskflow-config-table-column-body overlay-y">
<div :ref="`overlay_${data.id}`" class="taskflow-config-table-column-body scrollbar-overlay">
<div class="taskflow-config-table-block">
<div class="taskflow-config-table-block-title"></div>
<RadioGroup v-model="item.status">

View File

@ -135,7 +135,7 @@
</div>
</div>
</div>
<div class="scroller overlay-y">
<div class="scroller scrollbar-overlay">
<div class="title">
<Input
v-model="taskDetail.name"

View File

@ -32,7 +32,7 @@
</div>
</li>
</ul>
<div class="dashboard-list overlay-y">
<div class="dashboard-list scrollbar-overlay">
<template
v-for="column in columns"
v-if="column.list.length > 0">

View File

@ -27,7 +27,7 @@
<ScrollerY
ref="list"
class="messenger-list"
:class="overlayClass"
:class="listClassName"
@on-scroll="listScroll"
static>
<ul
@ -45,11 +45,13 @@
:class="{
top: dialog.top_at,
active: dialog.id == dialogId,
operate: dialog.id == topOperateItem.id && topOperateVisible,
operate: dialog.id == operateItem.id && operateVisible,
completed: $A.dialogCompleted(dialog)
}"
:data-id="dialog.id"
@click="openDialog(dialog.id)"
@contextmenu.prevent.stop="handleRightClick($event, dialog)">
v-longpress="handleLongpress"
@contextmenu.prevent.stop="handleContextmenu($event, dialog)">
<template v-if="dialog.type=='group'">
<i v-if="dialog.group_type=='project'" class="taskfont icon-avatar project">&#xe6f9;</i>
<i v-else-if="dialog.group_type=='task'" class="taskfont icon-avatar task">&#xe6f4;</i>
@ -99,21 +101,22 @@
<li class="loaded">{{$L('共' + contactsFilter.length + '位联系人')}}</li>
</template>
</ul>
<div class="top-operate" :style="topOperateStyles">
<div class="operate-position" :style="operateStyles">
<Dropdown
trigger="custom"
:visible="topOperateVisible"
transfer-class-name="page-file-dropdown-menu"
@on-clickoutside="handleClickTopOperateOutside"
transfer>
:transfer="true"
:placement="$isDesktop ? 'bottom' : 'top'"
:visible="operateVisible"
@on-clickoutside="operateVisible = false">
<div :style="{userSelect:operateVisible ? 'none' : 'auto', height: operateStyles.height}"></div>
<DropdownMenu slot="list">
<DropdownItem @click.native="handleTopClick">
{{ $L(topOperateItem.top_at ? '取消置顶' : '置顶该聊天') }}
{{ $L(operateItem.top_at ? '取消置顶' : '置顶该聊天') }}
</DropdownItem>
<DropdownItem @click.native="updateRead('read')" v-if="$A.getDialogUnread(topOperateItem) > 0">
<DropdownItem @click.native="handleReadClick('read')" v-if="$A.getDialogUnread(operateItem) > 0">
{{ $L('标记已读') }}
</DropdownItem>
<DropdownItem @click.native="updateRead('unread')" v-else>
<DropdownItem @click.native="handleReadClick('unread')" v-else>
{{ $L('标记未读') }}
</DropdownItem>
</DropdownMenu>
@ -149,9 +152,11 @@
import {mapState} from "vuex";
import DialogWrapper from "./components/DialogWrapper";
import ScrollerY from "../../components/ScrollerY";
import longpress from "../../directives/longpress";
export default {
components: {ScrollerY, DialogWrapper},
directives: {longpress},
data() {
return {
tabActive: 'dialog',
@ -171,9 +176,9 @@ export default {
contactsCurrentPage: 1,
contactsHasMorePages: false,
topOperateStyles: {},
topOperateVisible: false,
topOperateItem: {},
operateItem: {},
operateStyles: {},
operateVisible: false,
}
},
@ -300,10 +305,10 @@ export default {
}
},
overlayClass() {
listClassName() {
return {
'overlay-y': true,
'overlay-none': this.topOperateVisible === true,
'scrollbar-overlay': true,
'scrollbar-hidden': this.operateVisible === true,
}
}
},
@ -371,7 +376,7 @@ export default {
}
break;
}
this.topOperateVisible = false;
this.operateVisible = false;
},
onActive(type) {
@ -389,6 +394,9 @@ export default {
},
openDialog(dialogId) {
if (this.operateVisible) {
return
}
if (dialogId > 0) {
this.goForward({name: 'manage-messenger', params: {dialogId}});
} else {
@ -507,18 +515,18 @@ export default {
scrollIntoActive() {
this.$nextTick(() => {
if (this.$isDesktop && this.$refs.list) {
let active = this.$refs.list.querySelector(".active")
const active = this.$refs.list.querySelector(".active")
if (active) {
$A.scrollToView(active, {
behavior: 'instant',
scrollMode: 'if-needed',
});
} else {
let dialog = this.cacheDialogs.find(({id}) => id == this.dialogId)
const dialog = this.cacheDialogs.find(({id}) => id == this.dialogId)
if (dialog && this.dialogActive) {
this.dialogActive = '';
this.$nextTick(() => {
let active = this.$refs.list.querySelector(".active")
const active = this.$refs.list.querySelector(".active")
if (active) {
$A.scrollToView(active, {
behavior: 'instant',
@ -532,29 +540,44 @@ export default {
})
},
handleRightClick(event, item) {
this.handleClickTopOperateOutside();
this.topOperateItem = $A.isJson(item) ? item : {};
this.$nextTick(() => {
const dialogWrap = this.$refs.dialogWrapper;
const dialogBounding = dialogWrap.getBoundingClientRect();
this.topOperateStyles = {
left: `${event.clientX - dialogBounding.left}px`,
top: `${event.clientY - dialogBounding.top + 100 - this.$refs.list.scrollInfo().scrollY}px`
};
this.topOperateVisible = true;
})
handleLongpress(touchEvent, el) {
if (this.$isDesktop) {
return
}
const dialogId = $A.getAttr(el, 'data-id')
const dialogItem = this.dialogList.find(item => item.id == dialogId)
if (dialogItem) {
this.handleTopOperateShow(touchEvent.touches[0], dialogItem)
}
},
handleClickTopOperateOutside() {
this.topOperateVisible = false;
handleContextmenu(event, dialog) {
if (!this.$isDesktop) {
return
}
this.handleTopOperateShow(event, dialog);
},
handleTopOperateShow(event, dialog) {
this.operateVisible = false;
this.operateItem = $A.isJson(dialog) ? dialog : {};
this.$nextTick(() => {
const dialogRect = this.$refs[`dialog_${dialog.id}`][0].getBoundingClientRect();
const wrapRect = this.$refs.dialogWrapper.getBoundingClientRect();
this.operateStyles = {
left: `${event.clientX - wrapRect.left}px`,
top: `${dialogRect.top}px`,
height: dialogRect.height + 'px',
}
this.operateVisible = true;
})
},
handleTopClick() {
this.$store.dispatch("call", {
url: 'dialog/top',
data: {
dialog_id: this.topOperateItem.id,
dialog_id: this.operateItem.id,
},
}).then(({data}) => {
this.$store.dispatch("saveDialog", data);
@ -564,11 +587,11 @@ export default {
});
},
updateRead(type) {
handleReadClick(type) {
this.$store.dispatch("call", {
url: 'dialog/msg/mark',
data: {
dialog_id: this.topOperateItem.id,
dialog_id: this.operateItem.id,
type: type
},
}).then(({data}) => {

View File

@ -33,7 +33,9 @@
</div>
<div class="setting-content">
<div class="setting-content-title">{{$L(titleNameRoute)}}</div>
<div class="setting-content-view"><router-view class="setting-router-view"></router-view></div>
<div class="setting-content-view">
<router-view class="setting-router-view"></router-view>
</div>
</div>
</div>
</div>

View File

@ -9,4 +9,3 @@
@import "pages/_";
@import "dark";

View File

@ -1,6 +1,7 @@
@import "auto-tip";
@import "circle";
@import "drawer-overlay";
@import "gantt-view";
@import "img-update";
@import "loading";
@import "mobile";

View File

@ -0,0 +1,290 @@
.common-gantt {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: row;
align-items: self-start;
color: #747a81;
* {
box-sizing: border-box;
}
.gantt-left {
flex-grow: 0;
flex-shrink: 0;
height: 100%;
background-color: #ffffff;
position: relative;
display: flex;
flex-direction: column;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 1px;
background-color: rgba(237, 241, 242, 0.75);
}
.gantt-title {
height: 76px;
flex-grow: 0;
flex-shrink: 0;
background-color: #F9FAFB;
padding-left: 12px;
overflow: hidden;
.gantt-title-text {
line-height: 100px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 600;
}
}
.gantt-item {
transform: translateZ(0);
max-height: 100%;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
> li {
height: 40px;
border-bottom: 1px solid rgba(237, 241, 242, 0.75);
position: relative;
display: flex;
align-items: center;
padding-left: 12px;
&:hover {
.item-icon {
display: flex;
}
}
.item-overdue {
flex-grow: 0;
flex-shrink: 0;
color: #ffffff;
margin-right: 4px;
background-color: #ff0000;
padding: 1px 3px;
border-radius: 3px;
font-size: 12px;
line-height: 18px;
}
.item-title {
flex: 1;
padding-right: 12px;
cursor: default;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.complete {
text-decoration: line-through;
}
&.overdue {
font-weight: 600;
}
}
.item-icon {
display: none;
align-items: center;
justify-content: center;
width: 32px;
margin-right: 2px;
font-size: 16px;
color: #888888;
}
}
}
}
.gantt-right {
flex: 1;
height: 100%;
background-color: #ffffff;
position: relative;
overflow: hidden;
.gantt-chart {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
transform: translateZ(0);
.gantt-month {
display: flex;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
height: 26px;
line-height: 20px;
font-size: 14px;
background-color: #F9FAFB;
> li {
flex-grow: 0;
flex-shrink: 0;
height: 100%;
position: relative;
overflow: hidden;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 1px;
height: 100%;
background-color: rgba(237, 241, 242, 0.75);
}
.month-format {
overflow: hidden;
white-space: nowrap;
padding: 6px 6px 0;
}
}
}
.gantt-date {
display: flex;
align-items: center;
position: absolute;
top: 26px;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
cursor: move;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50px;
background-color: #F9FAFB;
}
> li {
flex-grow: 0;
flex-shrink: 0;
height: 100%;
position: relative;
overflow: hidden;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
width: 1px;
height: 100%;
background-color: rgba(237, 241, 242, 0.75);
}
.date-format {
overflow: hidden;
white-space: nowrap;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 44px;
.format-day {
line-height: 28px;
font-size: 18px;
}
.format-week {
line-height: 16px;
font-weight: 300;
font-size: 13px;
}
}
}
}
.gantt-timeline {
position: absolute;
top: 76px;
left: 0;
right: 0;
bottom: 0;
z-index: 3;
overflow-x: hidden;
overflow-y: auto;
> li {
cursor: default;
height: 40px;
border-bottom: 1px solid rgba(237, 241, 242, 0.75);
position: relative;
.timeline-item {
position: absolute;
top: 0;
touch-action: none;
pointer-events: auto;
padding: 4px;
margin-top: 4px;
background: #e74c3c;
border-radius: 18px;
color: #fff;
display: flex;
align-items: center;
will-change: contents;
height: 32px;
.timeline-title {
touch-action: none;
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 4px;
margin-right: 10px;
}
.timeline-resizer {
height: 22px;
touch-action: none;
width: 8px;
background: rgba(255, 255, 255, 0.1);
cursor: ew-resize;
flex-shrink: 0;
will-change: visibility;
position: absolute;
top: 5px;
right: 5px;
}
}
}
}
}
}
}

View File

@ -46,7 +46,6 @@
.notification-body {
max-height: 210px;
overflow-x: hidden;
overflow-y: auto;
margin-bottom: 16px;
.markdown-preview {
margin: -20px -12px;

View File

@ -6,7 +6,7 @@
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
overflow-y: overlay;
.app-scroller-bottom {
height: 0;
margin: 0;

View File

@ -1,6 +1,17 @@
body {
overflow: hidden;
&.touch-back {
.dialog-wrapper .vue-recycle-scroller.direction-vertical:not(.page-mode),
.common-gantt .gantt-left .gantt-item,
.project-panel .project-column,
.project-panel .project-table,
.scrollbar-overlay,
.ivu-modal-wrap {
overflow: hidden;
}
}
.form-tip {
color: #999999;
line-height: 22px;

View File

@ -9,6 +9,10 @@
background-color: #ffffff;
z-index: 1;
.vue-recycle-scroller.direction-vertical:not(.page-mode) {
overflow-y: overlay;
}
.dialog-nav {
display: flex;
align-items: center;
@ -823,7 +827,6 @@
.unread {
flex: 1;
max-height: 300px;
overflow: auto;
> li {
min-height: 26px;

View File

@ -380,7 +380,6 @@
display: flex;
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
.task-list {
> div:last-child {
margin-bottom: 16px;
@ -614,7 +613,7 @@
.project-table {
height: 100%;
margin-top: 18px;
overflow: auto;
overflow-x: auto;
.task-row {
background-color: #ffffff;
border-bottom: 1px solid #F4F4F5;
@ -1082,7 +1081,6 @@
}
}
.project-table {
overflow-x: auto;
.project-table-head,
.project-table-body {
min-width: 768px;

View File

@ -152,7 +152,6 @@
padding-left: 8px;
padding-right: 36px;
overflow-x: hidden;
overflow-y: auto;
.title {
margin-top: 18px;
.ivu-input {

View File

@ -105,7 +105,6 @@
width: 100%;
margin-top: 48px;
padding-bottom: 6%;
overflow: auto;
.dashboard-ref {
height: 0;
}
@ -298,8 +297,8 @@
}
}
.dashboard-list {
overflow: visible !important;
padding-bottom: 2px;
overflow: visible;
.dashboard-ul {
margin-bottom: 36px;
user-select: none;

View File

@ -22,7 +22,7 @@
margin-top: 16px;
display: flex;
flex-direction: column;
overflow: hidden !important;
overflow: hidden;
> li {
flex-shrink: 0;
display: flex;
@ -67,7 +67,6 @@
width: 100%;
> ul {
width: 100%;
overflow: auto;
> li {
display: flex;
flex-direction: column;
@ -174,23 +173,31 @@
&.operate {
border-color: $primary-color;
}
&.loading {
display: flex;
align-items: center;
justify-content: center;
padding: 6px;
.common-loading {
margin: 6px;
width: 22px;
height: 22px;
}
}
}
}
.common-loading {
margin: 6px;
width: 22px;
height: 22px;
}
.top-operate {
position: absolute;
top: 0;
right: 0;
opacity: 0;
display: flex;
}
}
}
}
.operate-position {
position: absolute;
top: 0;
right: 0;
width: 1px;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.manage-project-search {
width: 80%;
padding: 0 3px;
@ -400,14 +407,14 @@
.page-manage {
.manage-box-menu {
> ul {
overflow: auto !important;
&.overlay-y {
overflow-y: overlay !important;
overflow: auto;
&.scrollbar-overlay {
overflow-y: overlay;
}
> li {
&.menu-project {
> ul {
overflow: visible !important;
overflow: visible;
}
}
}

View File

@ -89,7 +89,6 @@
height: 0;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
> ul {
&.dialog {
> li {
@ -336,12 +335,14 @@
}
}
}
.top-operate {
.operate-position {
position: absolute;
top: 0;
right: 0;
width: 1px;
opacity: 0;
display: flex;
visibility: hidden;
pointer-events: none;
}
}
.messenger-menu {
@ -447,15 +448,23 @@
opacity: 0;
}
.messenger-list {
flex: 1;
height: 0;
width: 100%;
overflow-x: hidden;
overflow-y: auto;
> ul {
user-select: none;
&.dialog {
> li {
.user-avatar {
.common-avatar {
&:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
}
}
}
.dialog-split {
display: block;
position: absolute;

View File

@ -1,5 +1,6 @@
.overlay-y {
overflow-y: overlay !important;
.scrollbar-overlay {
overflow-y: auto;
overflow-y: overlay;
/* 滚动条美化 */
&::-webkit-scrollbar {
@ -38,11 +39,9 @@
background: rgba(0, 0, 0, 0);
}
}
.overlay-none {
.scrollbar-hidden {
&::-webkit-scrollbar {
display: none;
}
}
.overlay-hidden {
overflow: hidden !important;
}