This commit is contained in:
kuaifan 2021-08-25 18:47:44 +08:00
parent dd585c62bc
commit 49cd58ad89
30 changed files with 400 additions and 157 deletions

View File

@ -2,7 +2,7 @@
namespace App\Http\Middleware;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use Closure;

View File

@ -93,7 +93,11 @@ class User extends AbstractModel
*/
public function getUserimgAttribute($value)
{
return $value ? Base::fillUrl($value) : url('images/other/avatar.png');
if ($value) {
return Base::fillUrl($value);
}
$name = ($this->userid - 1) % 21 + 1;
return url("images/avatar/default_{$name}.png");
}
/**

View File

@ -4,7 +4,7 @@ namespace App\Module;
use Exception;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
class Ihttp
{

View File

@ -2,7 +2,7 @@
namespace App\Services;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use App\Models\User;
use App\Models\WebSocket;

View File

@ -1,7 +1,7 @@
<?php
namespace App\Tasks;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use App\Module\Base;
use App\Module\Ihttp;

View File

@ -4,7 +4,7 @@ namespace App\Tasks;
use App\Models\WebSocket;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
/**

View File

@ -1,7 +1,7 @@
<?php
namespace App\Tasks;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use App\Models\WebSocket;
use App\Models\WebSocketTmpMsg;

View File

@ -2,7 +2,7 @@
namespace App\Tasks;
@error_reporting(E_ALL & ~E_NOTICE);
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
use App\Models\User;
use App\Models\WebSocketDialog;

6
cmd
View File

@ -33,12 +33,12 @@ supervisorctl_restart() {
}
check_docker() {
docker --help &> /dev/null
docker --version &> /dev/null
if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 未安装 Docker${Font}"
exit 1
fi
docker-compose --help &> /dev/null
docker-compose --version &> /dev/null
if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 未安装 Docker-compose${Font}"
exit 1
@ -46,7 +46,7 @@ check_docker() {
}
check_node() {
npm --help &> /dev/null
npm --version > /dev/null
if [ $? -ne 0 ]; then
echo -e "${Error} ${RedBG} 未安装nodejs${Font}"
exit 1

View File

@ -2,10 +2,10 @@
directory=/var/www
# 生产环境
command=php bin/laravels start -i
#command=php bin/laravels start -i
# 开发环境
#command=./bin/inotify ./app
command=./bin/inotify ./app
numprocs=1
autostart=true

View File

@ -13,6 +13,9 @@
"axios": "^0.21",
"cross-env": "^7.0.2",
"css-loader": "^5.2.6",
"echarts": "^5.1.1",
"electron": "^13.1.6",
"element-ui": "^2.15.2",
"file-loader": "^6.2.0",
"inquirer": "^8.1.1",
"internal-ip": "^6.2.0",
@ -24,33 +27,28 @@
"moment": "^2.29.1",
"nativefier": "^44.0.4",
"node-sass": "^4.11.0",
"notification-koro1": "^1.1.1",
"postcss": "^8.1.14",
"resolve-url-loader": "^4.0.0",
"sass": "^1.34.1",
"sass-loader": "^8.0.2",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"vue": "^2.6.12",
"vue-loader": "^15.9.7",
"vue-router": "^3.4.2",
"vue-template-compiler": "^2.6.11",
"vuex": "^3.6.2",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
},
"dependencies": {
"echarts": "^5.1.1",
"electron": "^13.1.6",
"element-ui": "^2.15.2",
"notification-koro1": "^1.1.1",
"tinymce": "^5.8.1",
"tui-calendar-hi": "^1.13.0-5",
"view-design-hi": "^4.6.1-2",
"view-design-hi": "^4.6.1-9",
"vue": "^2.6.12",
"vue-clipboard2": "^0.3.1",
"vue-emoji-picker": "^1.0.1",
"vue-kityminder-gg": "^1.3.6",
"vue-loader": "^15.9.7",
"vue-resize-observer": "^1.0.37",
"vue-router": "^3.4.2",
"vue-template-compiler": "^2.6.11",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0",
"xlsx": "^0.17.0"
}
}

View File

@ -1,15 +1,15 @@
<template>
<ETooltip
:content="text"
:content="tipText"
:placement="placement"
:theme="tooltipTheme"
:effect="tooltipTheme"
:delay="delay"
:disabled="!showTooltip"
:max-width="tooltipMaxWidth"
transfer>
<span ref="content" @mouseenter="handleTooltipIn" class="common-auto-tip" @click="onClick">
<template v-if="existSlot"><slot/></template>
<template v-else>{{text}}</template>
<template v-else>{{content}}</template>
</span>
</ETooltip>
</template>
@ -40,44 +40,22 @@
data() {
return {
slotText: '',
showTooltip: false // overflow
showTooltip: false, // overflow
tooltipContent: '',
}
},
mounted () {
this.updateConetne()
},
beforeUpdate () {
this.updateConetne()
},
activated() {
this.updateConetne()
},
computed: {
text() {
const {content, slotText} = this;
if (content) {
return content;
}
if (typeof slotText === 'undefined' || slotText.length < 1 || typeof slotText[0].text !== 'string') {
return '';
}
return slotText[0].text;
tipText() {
const {content, tooltipContent} = this;
return content || tooltipContent || "";
},
existSlot() {
const {slotText} = this;
return !(typeof slotText === 'undefined' || slotText.length < 1);
return !(typeof this.$slots.default === 'undefined' || this.$slots.default.length < 1);
},
},
methods: {
updateConetne () {
this.slotText = this.$slots.default;
},
handleTooltipIn () {
const $content = this.$refs.content;
let range = document.createRange();
@ -85,6 +63,14 @@
range.setEnd($content, $content.childNodes.length);
const rangeWidth = range.getBoundingClientRect().width;
this.showTooltip = Math.floor(rangeWidth) > Math.floor($content.offsetWidth);
if (this.showTooltip && this.existSlot) {
const tmpArray = this.$slots.default.map((e) => {
if (e.text) return e.text
if (e.elm.innerText) return e.elm.innerText
return ""
})
this.tooltipContent = tmpArray.join("");
}
range = null;
},
onClick(e) {

View File

@ -1,5 +1,6 @@
<template>
<div :class="['drawer-overlay', placement, value ? 'overlay-visible' : 'overlay-hide']" @click="mask">
<div :class="['drawer-overlay', placement, value ? 'overlay-visible' : 'overlay-hide']">
<div class="overlay-mask" @click="mask"></div>
<div class="overlay-body" :style="bodyStyle">
<div class="overlay-close">
<a href="javascript:void(0)" @click.stop="close">
@ -8,9 +9,7 @@
</svg>
</a>
</div>
<div class="overlay-content" @click.stop="">
<slot/>
</div>
<div class="overlay-content"><slot/></div>
</div>
</div>
</template>
@ -87,7 +86,12 @@
escClose(e) {
if (this.value && this.escClosable) {
if (e.keyCode === 27) {
this.close()
let show = false;
$A(".ivu-modal").each((i, e) => {
show = $(e).is(":visible");
return !show;
})
!show && this.close()
}
}
}

View File

@ -200,7 +200,7 @@
if (typeof items === 'string') {
items = [{'url': items}];
}
let lists = [];
let list = [];
$A.each(items, (index, item)=>{
if (typeof item === 'string') item = {'url': item};
if (item.url) {
@ -208,10 +208,10 @@
item.status = 'finished';
if (typeof item.path === 'undefined') item.path = item.url;
if (typeof item.thumb === 'undefined') item.thumb = item.url;
lists.push(item);
list.push(item);
}
});
return lists;
return list;
},
handleView (item) {
//

View File

@ -1,9 +1,19 @@
<template>
<svg viewBox="25 25 50 50" class="common-loading"><circle cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" class="common-path"></circle></svg>
<ETooltip :disabled="content == ''" :content="content">
<svg viewBox="25 25 50 50" class="common-loading">
<circle cx="50" cy="50" r="20" fill="none" stroke-width="5" stroke-miterlimit="10" class="common-path"></circle>
</svg>
</ETooltip>
</template>
<script>
export default {
name: 'Loading',
props: {
content: {
type: [String, Number],
default: ''
},
},
}
</script>

View File

@ -1,7 +1,8 @@
<template>
<div class="quick-edit">
<div v-if="isEdit" class="quick-input">
<Input ref="input" v-model="content" :disabled="isLoad" @on-blur="onBlur" @on-enter="onEnter"/>
<div class="quick-edit" :class="[alwaysIcon ? 'quick-always' : '']">
<div v-if="isEdit" v-clickoutside="onEnter" class="quick-input">
<TagInput v-if="isTag" ref="input" v-model="content" :disabled="isLoad" @on-enter="onEnter"/>
<Input v-else ref="input" v-model="content" :disabled="isLoad" @on-enter="onEnter"/>
<div v-if="isLoad" class="quick-loading"><Loading/></div>
</div>
<template v-else>
@ -12,8 +13,11 @@
</template>
<script>
import clickoutside from "../directives/clickoutside";
export default {
name: 'QuickEdit',
directives: {clickoutside},
props: {
value: {
@ -21,6 +25,14 @@ export default {
autoEdit: {
},
isTag: {
type: Boolean,
default: false
},
alwaysIcon: {
type: Boolean,
default: false
},
},
data() {
@ -59,10 +71,6 @@ export default {
})
},
onBlur() {
this.onEnter();
},
onEnter() {
if (this.content == this.value) {
this.isEdit = false;
@ -77,7 +85,7 @@ export default {
this.isEdit = false;
this.isLoad = false;
})
}
},
}
}
</script>

View File

@ -1,6 +1,46 @@
<template>
<div class="td-action" :style="tdStyle">
<div ref="action" @mouseenter="handleIn" class="td-action-container" v-resize="onResize"><slot></slot></div>
<div class="td-action" :style="tdStyle" :data-width="width" :data-height="height">
<div
ref="action"
class="td-action-container"
:class="{'td-action-menu':menu.length > 0}"
@mouseenter="handleIn"
v-resize="onResize">
<slot></slot>
<ETooltip
v-for="(item, key) in menu"
placement="top"
:key="key"
:disabled="!item.title"
:content="item.title"
:enterable="false"
:open-delay="600">
<EDropdown
v-if="item.children && item.children.length > 0"
size="medium"
trigger="click"
class="menu-dropdown"
@command="onClick">
<i class="aliicon menu-icon" v-html="item.icon" :style="item.style || {}"></i>
<EDropdownMenu slot="dropdown">
<EDropdownItem
v-for="(d, k) in item.children"
:key="k"
:command="d.action"
:divided="!!d.divided"
:style="d.style || {}">
<div>{{d.title}}</div>
</EDropdownItem>
</EDropdownMenu>
</EDropdown>
<i
v-else
class="aliicon menu-icon"
v-html="item.icon"
:style="item.style || {}"
@click="onClick(item.action)"></i>
</ETooltip>
</div>
</div>
</template>
@ -18,6 +58,10 @@ Vue.use(VueResizeObserver);
return {};
}
},
autoWidth: {
type: Boolean,
default: true
},
minWidth: {
type: Number,
default: 80
@ -26,6 +70,12 @@ Vue.use(VueResizeObserver);
type: String,
default: ''
},
menu: {
type: Array,
default: () => {
return [];
}
},
},
data() {
return {
@ -46,8 +96,16 @@ Vue.use(VueResizeObserver);
tdStyle() {
const style = {};
const {align} = this;
if (['left', 'center', 'right'].includes(align.toLowerCase())) {
style.textAlign = align;
switch (align.toLowerCase()) {
case 'left':
style.justifyContent = 'flex-start';
break;
case 'center':
style.justifyContent = 'center';
break;
case 'right':
style.justifyContent = 'flex-end';
break;
}
return style;
}
@ -65,6 +123,9 @@ Vue.use(VueResizeObserver);
})
},
onResize({ width, height }) {
if (!this.autoWidth) {
return;
}
$A(".ivu-table-column-" + this.column.__id).each((index, el) => {
let action = $A(el).find(".td-action-container")
if (action.length > 0) {
@ -81,7 +142,14 @@ Vue.use(VueResizeObserver);
if (this.column.maxWidth) {
newWidth = Math.min(this.column.maxWidth, newWidth);
}
newWidth != this.column.width && this.$set(this.column, 'width', newWidth)
if (newWidth != this.column.width) {
this.$nextTick(() => {
this.$set(this.column, 'width', newWidth);
})
}
},
onClick(action) {
this.$emit("action", action)
}
}
}

View File

@ -1,12 +1,22 @@
<template>
<div class="common-tag-input" @paste="pasteText($event)" @click="clickWrap">
<div class="common-tag-input" :class="{focus:isFocus}" @paste="pasteText($event)" @click="focus">
<div class="tags-item" v-for="(text, index) in disSource">
<span class="tags-content" @click.stop="">{{text}}</span><span class="tags-del" @click.stop="delTag(index)">&times;</span>
</div>
<textarea ref="myTextarea" class="tags-input" :style="{ minWidth: minWidth + 'px' }" :placeholder="tis || placeholder"
v-model="content" @keydown.enter="downEnter($event)" @keyup="addTag($event, content)"
@blur="addTag(false, content)" @keydown.delete="delTag(false)" :disabled="disabled" :readonly="readonly"></textarea>
<span ref="myPlaceholder" v-if="showPlaceholder || tis !== ''" class="tags-placeholder">{{tis || placeholder}}</span>
<textarea
ref="myTextarea"
class="tags-input"
v-model="content"
:style="{ minWidth: minWidth + 'px' }"
:placeholder="tis || placeholderText"
@keydown.enter="downEnter($event)"
@keydown.delete="delTag(false)"
@keyup="addTag($event, content)"
@focus="onFocus"
@blur="onBlur"
:disabled="disabled"
:readonly="readonly"/>
<span ref="myPlaceholder" v-if="showPlaceholder || tis !== ''" class="tags-placeholder">{{tis || placeholderText}}</span>
</div>
</template>
@ -53,6 +63,8 @@
content: '',
disSource: disSource,
isFocus: false
}
},
mounted() {
@ -82,9 +94,36 @@
temp += item;
});
this.$emit('input', temp);
this.$emit('on-change');
}
},
computed: {
placeholderText() {
if (this.disSource.length > 0) {
return ""
}
return this.placeholder
}
},
methods: {
focus(option) {
const $el = this.$refs.myTextarea;
$el.focus(option);
const { cursor } = option || {};
if (cursor) {
const len = $el.value.length;
switch (cursor) {
case 'start':
$el.setSelectionRange(0, 0);
break;
case 'end':
$el.setSelectionRange(len, len);
break;
default:
$el.setSelectionRange(0, len);
}
}
},
wayMinWidth() {
this.showPlaceholder = true;
this.$nextTick(() => {
@ -107,35 +146,46 @@
let content = (e.clipboardData || window.clipboardData).getData('text');
this.addTag(false, content)
},
clickWrap() {
this.$refs.myTextarea.focus();
},
downEnter(e) {
e.preventDefault();
},
onFocus() {
this.isFocus = true;
},
onBlur() {
this.isFocus = false;
this.addTag(false, this.content)
},
addTag(e, content) {
if (e.keyCode === 13 || e === false) {
if (e === false || e.keyCode === 13) {
if (content.trim() != '' && this.disSource.indexOf(content.trim()) === -1) {
this.disSource.push(content.trim());
}
this.content = '';
} else {
if (this.max > 0 && this.disSource.length >= this.max) {
this.content = '';
this.tis = '最多只能添加' + this.max + '个';
clearInterval(this.tisTimeout);
this.tisTimeout = setTimeout(() => { this.tis = ''; }, 2000);
return;
//
if (e.keyCode === 13) {
this.$nextTick(() => {
this.$emit("on-enter", e)
})
}
let temp = content.trim();
let cutPos = temp.length - this.cut.length;
if (temp != '' && temp.substring(cutPos) === this.cut) {
temp = temp.substring(0, cutPos);
if (temp.trim() != '' && this.disSource.indexOf(temp.trim()) === -1) {
this.disSource.push(temp.trim());
}
this.content = '';
return;
}
if (this.max > 0 && this.disSource.length >= this.max) {
this.content = '';
this.tis = '最多只能添加' + this.max + '个';
clearInterval(this.tisTimeout);
this.tisTimeout = setTimeout(() => { this.tis = ''; }, 2000);
return;
}
let temp = content.trim();
let cutPos = temp.length - this.cut.length;
if (temp != '' && temp.substring(cutPos) === this.cut) {
temp = temp.substring(0, cutPos);
if (temp.trim() != '' && this.disSource.indexOf(temp.trim()) === -1) {
this.disSource.push(temp.trim());
}
this.content = '';
}
},
delTag(index) {
@ -145,7 +195,8 @@
}
index = this.disSource.length - 1;
}
this.disSource.splice(index, 1)
this.disSource.splice(index, 1);
this.focus();
}
}
}

View File

@ -1,8 +1,10 @@
<template>
<ETooltip v-if="user"
class="common-avatar"
:open-delay="600"
:disabled="tooltipDisabled">
<ETooltip
v-if="user"
class="common-avatar"
:open-delay="600"
:disabled="tooltipDisabled"
:placement="tooltipPlacement">
<div slot="content" class="common-avatar-transfer">
<slot/>
<p>{{$L('昵称')}}: {{user.nickname}}</p>
@ -14,7 +16,7 @@
<div class="avatar-wrapper">
<div v-if="showIcon" :class="['avatar-box', userId === userid || user.online ? 'online' : '']" :style="boxStyle">
<em :style="spotStyle"></em>
<EAvatar v-if="showImg" :src="user.userimg" :size="avatarSize"/>
<EAvatar v-if="showImg" :class="{'avatar-default':isDefault}" :src="user.userimg" :size="avatarSize"/>
<EAvatar v-else :size="avatarSize" class="avatar-text">
<span :style="spotStyle">{{nickname}}</span>
</EAvatar>
@ -53,6 +55,10 @@
type: Boolean,
default: false
},
tooltipPlacement: {
type: String,
default: 'bottom'
},
borderWitdh: {
type: Number,
default: 0
@ -123,6 +129,11 @@
return !$A.rightExists(userimg, '/avatar.png');
},
isDefault() {
const {userimg} = this.user
return $A.strExists(userimg, '/avatar/default_');
},
nickname() {
const {nickname} = this.user;
if (!nickname) {

View File

@ -18,7 +18,7 @@
@on-set-default-options="setDefaultOptions">
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '')}}</div>
<Option
v-for="(item, key) in lists"
v-for="(item, key) in list"
:value="item.userid"
:key="key"
:label="item.nickname"
@ -85,7 +85,7 @@
loading: false,
openLoad: false,
values: [],
lists: []
list: []
}
},
mounted() {
@ -121,7 +121,7 @@
openChange(show) {
if (show && !this.openLoad) {
this.openLoad = true;
if (this.lists.length == this.values.length || this.lists.length <= 1) {
if (this.list.length == this.values.length || this.list.length <= 1) {
this.$nextTick(this.searchUser);
}
}
@ -130,7 +130,7 @@
setDefaultOptions(options) {
const userids = [];
options.forEach(({value, label}) => {
this.lists.push({
this.list.push({
userid: value,
nickname: label,
});
@ -148,9 +148,9 @@
this.$set(option, 'label', user.nickname)
this.$set(option, 'avatar', user.userimg)
}
this.lists.some((item, index) => {
this.list.some((item, index) => {
if (item.userid == user.userid) {
this.$set(this.lists, index, Object.assign(item, user));
this.$set(this.list, index, Object.assign(item, user));
}
});
}
@ -172,14 +172,14 @@
},
}).then(({data}) => {
this.loading = false;
this.lists = data;
this.list = data;
}).catch(({msg}) => {
this.loading = false;
this.lists = [];
this.list = [];
$A.messageWarning(msg);
});
} else {
this.lists = [];
this.list = [];
}
},

View File

@ -250,7 +250,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow v-if="tablePanel('showMy')" :list="myList" open-key="my" @command="dropTask" fast-add-task/>
<TaskRow v-if="tablePanel('showMy')" :list="myList" open-key="my" @command="dropTask" @on-priority="addTaskOpen" fast-add-task/>
</div>
<!--未完成任务-->
<div v-if="projectData.task_num > 0" :class="['project-table-body', !tablePanel('showUndone') ? 'project-table-hide' : '']">
@ -265,7 +265,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow v-if="tablePanel('showUndone')" :list="undoneList" open-key="undone" @command="dropTask"/>
<TaskRow v-if="tablePanel('showUndone')" :list="undoneList" open-key="undone" @command="dropTask" @on-priority="addTaskOpen"/>
</div>
<!--已完成任务-->
<div v-if="projectData.task_num > 0" :class="['project-table-body', !tablePanel('showCompleted') ? 'project-table-hide' : '']">
@ -280,7 +280,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow v-if="tablePanel('showCompleted')" :list="completedList" open-key="completed" @command="dropTask"/>
<TaskRow v-if="tablePanel('showCompleted')" :list="completedList" open-key="completed" @command="dropTask" @on-priority="addTaskOpen"/>
</div>
</div>

View File

@ -131,7 +131,7 @@
:open-key="openKey"
@command="dropTask"/>
</div>
<TaskAddSimple v-if="fastAddTask || parentId > 0" :parent-id="parentId" row-mode/>
<TaskAddSimple v-if="fastAddTask || parentId > 0" :parent-id="parentId" row-mode @on-priority="onPriority"/>
</div>
</template>
@ -218,6 +218,10 @@ export default {
this.$emit("command", task, command)
},
onPriority(data) {
this.$emit("on-priority", data)
},
getSublist(task) {
if (this.taskOpen[task.id] === true) {
this.$set(this.taskOpen, task.id, false);

View File

@ -13,9 +13,8 @@
<ul>
<li
v-for="(item, key) in menu"
v-if="!item.admin||userIsAdmin"
:key="key"
:class="classNameRoute(item.path)"
:class="classNameRoute(item.path, item.divided)"
@click="toggleRoute(item.path)">{{$L(item.name)}}</li>
</ul>
</div>
@ -34,13 +33,6 @@ export default {
data() {
return {
curPath: this.$route.path,
menu: [
{path: 'personal', admin: false, name: '个人设置'},
{path: 'password', admin: false, name: '密码设置'},
{path: 'system', admin: true, name: '系统设置'},
{path: 'priority', admin: true, name: '任务等级'},
],
}
},
mounted() {
@ -49,6 +41,20 @@ export default {
computed: {
...mapState(['userInfo', 'userIsAdmin']),
menu() {
let menu = [
{path: 'personal', name: '个人设置'},
{path: 'password', name: '密码设置'},
]
if (this.userIsAdmin) {
menu.push(...[
{path: 'system', name: '系统设置', divided: true},
{path: 'priority', name: '任务等级'},
])
}
return menu;
},
titleNameRoute() {
const {curPath, menu} = this;
let name = '';
@ -71,9 +77,10 @@ export default {
this.goForward({path: '/manage/setting/' + path});
},
classNameRoute(path) {
classNameRoute(path, divided) {
return {
"active": $A.leftExists(this.curPath, '/manage/setting/' + path)
"active": $A.leftExists(this.curPath, '/manage/setting/' + path),
"divided": !!divided
};
},
}

View File

@ -1,18 +1,18 @@
<template>
<div class="setting-item submit">
<Form ref="formDatum" :model="formDatum" :rules="ruleDatum" label-width="auto" @submit.native.prevent>
<Form ref="formData" :model="formData" :rules="ruleData" label-width="auto" @submit.native.prevent>
<FormItem :label="$L('头像')" prop="userimg">
<ImgUpload v-model="formDatum.userimg" :num="1"></ImgUpload>
<ImgUpload v-model="formData.userimg" :num="1"></ImgUpload>
<span class="form-tip">{{$L('建议尺寸200x200')}}</span>
</FormItem>
<FormItem :label="$L('邮箱')">
<Input v-model="userInfo.email" disabled></Input>
</FormItem>
<FormItem :label="$L('昵称')" prop="nickname">
<Input v-model="formDatum.nickname" :maxlength="20"></Input>
<Input v-model="formData.nickname" :maxlength="20"></Input>
</FormItem>
<FormItem :label="$L('职位/职称')" prop="profession">
<Input v-model="formDatum.profession" :maxlength="20"></Input>
<Input v-model="formData.profession" :maxlength="20"></Input>
</FormItem>
</Form>
<div class="setting-footer">
@ -31,13 +31,13 @@ export default {
return {
loadIng: 0,
formDatum: {
formData: {
userimg: '',
nickname: '',
profession: ''
},
ruleDatum: { },
ruleData: { },
}
},
mounted() {
@ -53,7 +53,7 @@ export default {
},
methods: {
initLanguage() {
this.ruleDatum = {
this.ruleData = {
nickname: [
{required: true, message: this.$L('请输入昵称!'), trigger: 'change'},
{type: 'string', min: 2, message: this.$L('昵称长度至少2位'), trigger: 'change'}
@ -62,16 +62,18 @@ export default {
},
initData() {
this.$set(this.formDatum, 'userimg', this.userInfo.userimg);
this.$set(this.formDatum, 'nickname', this.userInfo.nickname);
this.$set(this.formDatum, 'profession', this.userInfo.profession);
this.formDatum_bak = $A.cloneJSON(this.formDatum);
if (!$A.strExists(this.userInfo.userimg, '/avatar/default_')) {
this.$set(this.formData, 'userimg', this.userInfo.userimg);
}
this.$set(this.formData, 'nickname', this.userInfo.nickname);
this.$set(this.formData, 'profession', this.userInfo.profession);
this.formData_bak = $A.cloneJSON(this.formData);
},
submitForm() {
this.$refs.formDatum.validate((valid) => {
this.$refs.formData.validate((valid) => {
if (valid) {
let data = $A.cloneJSON(this.formDatum);
let data = $A.cloneJSON(this.formData);
if ($A.count(data.userimg) == 0) data.userimg = "";
this.loadIng++;
this.$store.dispatch("call", {
@ -90,7 +92,7 @@ export default {
},
resetForm() {
this.formDatum = $A.cloneJSON(this.formDatum_bak);
this.formData = $A.cloneJSON(this.formData_bak);
}
}
}

View File

@ -14,6 +14,15 @@
flex-direction: column;
justify-content: flex-end;
.overlay-mask {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 1;
}
.overlay-body {
display: flex;
flex-direction: column;
@ -21,6 +30,7 @@
height: 100%;
max-width: 100%;
max-height: 100%;
z-index: 2;
.overlay-close {
flex-shrink: 0;
@ -71,6 +81,8 @@
}
&.overlay-hide {
width: 100%;
height: 100%;
transition: opacity 0.2s ease;
.overlay-body {
.overlay-content {

View File

@ -4,6 +4,7 @@
max-width: 100%;
.quick-input {
flex: 1;
max-width: 100%;
position: relative;
.quick-loading {
position: absolute;
@ -33,9 +34,25 @@
font-size: 16px;
cursor: pointer;
}
&.quick-always {
.quick-icon {
display: inline-block;
opacity: 0.3;
transition: opacity 0.2s;
}
}
&:hover {
.quick-icon {
display: inline-block;
opacity: 1;
}
}
}
.ivu-table-row-hover {
.quick-edit {
.quick-icon {
display: inline-block;
opacity: 1;
}
}
}

View File

@ -11,8 +11,16 @@
cursor: text;
vertical-align: middle;
line-height: normal;
-webkit-transition: border .2s ease-in-out, background .2s ease-in-out, -webkit-box-shadow .2s ease-in-out;
transition: border .2s ease-in-out, background .2s ease-in-out, -webkit-box-shadow .2s ease-in-out;
transition: all .2s;
&:hover {
border-color: #a2d98d;
}
&.focus {
border-color: #a2d98d;
box-shadow: 0 0 0 2px rgba(139,207,112,.2)
}
.tags-item, .tags-input {
position: relative;
@ -62,7 +70,7 @@
left: 0;
top: 0;
z-index: -1;
color: #ffffff00;
color: rgba(255, 255, 255, 0);
}
}
.common-tag-input::after {
@ -71,3 +79,15 @@
height: 0;
clear: both;
}
.ivu-form-item-error {
.common-tag-input {
border-color: #ed4014;
&:hover {
border-color: #ed4014;
}
&.focus {
border-color: #ed4014;
box-shadow: 0 0 0 2px rgba(237,64,20,.2)
}
}
}

View File

@ -8,6 +8,9 @@
border-radius: 50%;
display: flex;
align-items: center;
.avatar-default {
background-color: transparent;
}
.avatar-text {
background-color: $primary-color;
> span {
@ -23,7 +26,7 @@
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #ff0000;
background-color: #ff9900;
border: 1px solid #ffffff;
transform-origin: right bottom;
z-index: 1;

View File

@ -104,16 +104,27 @@ body {
}
.td-action {
max-width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: middle;
display: flex;
align-items: center;
justify-content: center;
.td-action-container {
display: inline-block;
flex-shrink: 0;
a {
font-size: 12px;
padding: 0 5px;
}
&.td-action-menu {
display: flex;
align-items: center;
.menu-dropdown {
display: flex;
}
.menu-icon {
cursor: pointer;
font-size: 21px;
padding: 0 6px;
}
}
}
}
.ivu-table-row-hover {

View File

@ -40,10 +40,37 @@
padding: 0 20px;
margin: 5px 0;
position: relative;
&.active,
&:hover {
background-color: #F4F5F7;
}
&.divided {
position: relative;
margin-top: 10px;
padding-top: 10px;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
height: 1px;
background-color: #F4F4F5;
}
&:after {
content: "";
position: absolute;
top: 1px;
left: 0;
right: 0;
z-index: 2;
height: 9px;
background-color: #ffffff;
}
}
}
}
}