单据样式修改

master
toesbieya 6 years ago
parent 2a53db1324
commit f82f538636
  1. 8
      vue/src/assets/styles/index.scss
  2. 3
      vue/src/bizComponents/CategoryTree/index.vue
  3. 3
      vue/src/bizComponents/DocumentHistory/index.vue
  4. 3
      vue/src/bizComponents/DocumentSteps/index.vue
  5. 4
      vue/src/bizComponents/UserSelector/SimpleMultipleUserSelector.vue
  6. 2
      vue/src/components/AbstractTable/index.vue
  7. 2
      vue/src/components/BottomTip/main.vue
  8. 3
      vue/src/components/Charts/PieChart.vue
  9. 2
      vue/src/components/ContextMenu/ContextMenuItem.vue
  10. 4
      vue/src/components/ContextMenu/index.vue
  11. 3
      vue/src/components/DialogForm/DialogFormItem.vue
  12. 4
      vue/src/components/DialogForm/index.vue
  13. 73
      vue/src/components/DropDownMenu/index.vue
  14. 66
      vue/src/components/DropDownMenu/style.scss
  15. 2
      vue/src/components/Empty/DefaultEmptyImage.vue
  16. 53
      vue/src/components/Empty/index.vue
  17. 47
      vue/src/components/Empty/style.scss
  18. 92
      vue/src/components/Guide/main.vue
  19. 69
      vue/src/components/Guide/style.scss
  20. 3
      vue/src/components/ImageViewer/main.vue
  21. 42
      vue/src/components/LinerProgress/index.vue
  22. 36
      vue/src/components/LinerProgress/style.scss
  23. 2
      vue/src/components/Link/index.vue
  24. 7
      vue/src/components/LoadingMask/index.vue
  25. 7
      vue/src/components/OrgTree/index.vue
  26. 10
      vue/src/components/PuzzleVerify/main.vue
  27. 5
      vue/src/components/RegionSelector/Tab/index.vue
  28. 3
      vue/src/components/SearchForm/SearchFormItem.vue
  29. 7
      vue/src/components/SearchForm/index.vue
  30. 6
      vue/src/components/SignautreBoard/main.vue
  31. 2
      vue/src/components/Skeleton/PageSkeleton.vue
  32. 3
      vue/src/components/Skeleton/index.vue
  33. 3
      vue/src/components/SvgIcon/index.vue
  34. 6
      vue/src/components/TinymceEditor/index.vue
  35. 7
      vue/src/components/ZoomControl/index.vue
  36. 13
      vue/src/layout/components/Header.vue
  37. 6
      vue/src/layout/components/Main.vue
  38. 4
      vue/src/layout/components/Navbar/components/Bell.vue
  39. 3
      vue/src/layout/components/Navbar/components/Breadcrumb.vue
  40. 85
      vue/src/layout/components/Navbar/components/Fullscreen.vue
  41. 7
      vue/src/layout/components/Navbar/components/Hamburger.vue
  42. 12
      vue/src/layout/components/Navbar/components/HeaderSearch.vue
  43. 4
      vue/src/layout/components/Navbar/components/SettingDrawer.vue
  44. 64
      vue/src/layout/components/Navbar/index.vue
  45. 52
      vue/src/layout/components/Navbar/style.scss
  46. 4
      vue/src/layout/components/Sidebar/components/Logo.vue
  47. 2
      vue/src/layout/components/Sidebar/components/SidebarItem.vue
  48. 3
      vue/src/layout/components/Sidebar/components/SidebarItemContent.vue
  49. 15
      vue/src/layout/components/Sidebar/index.vue
  50. 6
      vue/src/layout/components/TagsView/ScrollPane.vue
  51. 9
      vue/src/layout/components/TagsView/index.vue
  52. 10
      vue/src/layout/index.vue
  53. 8
      vue/src/views/app/403.vue
  54. 8
      vue/src/views/app/404.vue
  55. 18
      vue/src/views/app/login/LoginForm.vue
  56. 12
      vue/src/views/app/login/RegisterForm.vue
  57. 4
      vue/src/views/app/login/SetAnimation.vue
  58. 10
      vue/src/views/app/login/index.vue
  59. 1
      vue/src/views/app/redirect.vue
  60. 5
      vue/src/views/index/components/DailyFinishOrderStat.vue
  61. 5
      vue/src/views/index/components/DailyProfitStat.vue
  62. 3
      vue/src/views/index/components/PanelGroup/PanelGroupItem.vue
  63. 5
      vue/src/views/index/components/PanelGroup/index.vue
  64. 6
      vue/src/views/index/components/TotalProfitGoods.vue
  65. 1
      vue/src/views/index/index.vue
  66. 7
      vue/src/views/message/manage/EditDialog.vue
  67. 15
      vue/src/views/message/manage/index.vue
  68. 25
      vue/src/views/purchase/inbound/components/EditDialog.vue
  69. 12
      vue/src/views/purchase/inbound/components/OrderSelector.vue
  70. 6
      vue/src/views/purchase/inbound/index.vue
  71. 61
      vue/src/views/purchase/order/components/EditDialog.vue
  72. 2
      vue/src/views/purchase/order/components/SupplierSelector.vue
  73. 15
      vue/src/views/sell/order/components/CustomerSelector.vue
  74. 63
      vue/src/views/sell/order/components/EditDialog.vue
  75. 12
      vue/src/views/sell/order/components/StockSelector.vue
  76. 16
      vue/src/views/sell/order/index.vue
  77. 34
      vue/src/views/sell/outbound/components/EditDialog.vue
  78. 12
      vue/src/views/sell/outbound/components/OrderSelector.vue
  79. 11
      vue/src/views/sell/outbound/components/StockSelector.vue
  80. 16
      vue/src/views/sell/outbound/index.vue
  81. 11
      vue/src/views/stock/current/DetailDialog.vue
  82. 18
      vue/src/views/stock/current/index.vue
  83. 11
      vue/src/views/system/category/components/Form.vue
  84. 13
      vue/src/views/system/category/components/List.vue
  85. 1
      vue/src/views/system/category/index.vue
  86. 14
      vue/src/views/system/customer/EditDialog.vue
  87. 18
      vue/src/views/system/customer/index.vue
  88. 12
      vue/src/views/system/department/components/EditDialog.vue
  89. 7
      vue/src/views/system/department/components/OrgTreeView.vue
  90. 17
      vue/src/views/system/department/index.vue
  91. 11
      vue/src/views/system/monitor/components/Cpu.vue
  92. 9
      vue/src/views/system/monitor/components/Jvm.vue
  93. 9
      vue/src/views/system/monitor/components/Memory.vue
  94. 10
      vue/src/views/system/monitor/index.vue
  95. 26
      vue/src/views/system/resource/EditDialog.vue
  96. 8
      vue/src/views/system/resource/index.vue
  97. 13
      vue/src/views/system/role/components/EditDialog.vue
  98. 3
      vue/src/views/system/role/components/RoleResource.vue
  99. 16
      vue/src/views/system/role/index.vue
  100. 14
      vue/src/views/system/supplier/EditDialog.vue
  101. Some files were not shown because too many files have changed in this diff Show More

@ -198,4 +198,12 @@ a:hover {
}
}
.table-add-btn {
margin: 8px 0;
.el-button {
width: 100%;
}
}

@ -16,12 +16,15 @@
export default {
name: "CategoryTree",
props: {filterNodeMethod: Function},
computed: {
data() {
return this.$store.state.dataCache.categoryTree
}
},
mounted() {
getAllCategories()
.then(data => this.$store.commit('dataCache/categories', data))

@ -1,11 +1,14 @@
<script type="text/jsx">
export default {
name: "DocumentHistory",
functional: true,
props: {
type: String,
data: {type: Array, default: () => []}
},
render(h, context) {
const {type, data = []} = context.props
if (type === 'add') return ''

@ -1,11 +1,14 @@
<script type="text/jsx">
export default {
name: "DocumentSteps",
functional: true,
props: {
status: Number,
type: String
},
render(h, context) {
let {status, type} = context.props
let firstStatus = type === 'add' ? 'finish' : 'success'

@ -14,20 +14,24 @@
export default {
name: "SimpleMultipleUserSelector",
props: {
value: Array,
disabled: Boolean
},
data() {
return {
data: []
}
},
methods: {
emit(v) {
this.$emit('input', v)
}
},
mounted() {
getUsers({page: 1, pageSize: 9999})
.then(({list}) => this.data = list)

@ -3,7 +3,9 @@
export default {
name: "AbstractTable",
functional: true,
render(h, context) {
const {data, children} = context
return (

@ -10,12 +10,14 @@
<script>
export default {
name: "BottomTip",
data() {
return {
value: false,
message: null
}
},
methods: {
handleAfterLeave() {
this.$destroy(true)

@ -7,10 +7,12 @@
export default {
mixins: [resize, logic],
props: {
title: String,
data: Array
},
watch: {
data: {
deep: true,
@ -19,6 +21,7 @@
}
}
},
methods: {
init(data) {
this.chart.setOption({

@ -1,7 +1,9 @@
<script type="text/jsx">
export default {
name: "ContextMenuItem",
functional: true,
render(h, context) {
return h('li', context.data, context.children)
}

@ -7,6 +7,7 @@
<script>
export default {
name: "ContextMenu",
props: {
value: {
type: Boolean,
@ -19,12 +20,14 @@
type: Number
}
},
data() {
return {
realLeft: '0px',
realTop: '0px'
}
},
watch: {
value(v) {
document.body[v ? 'addEventListener' : 'removeEventListener']('click', this.closeContextMenu)
@ -39,6 +42,7 @@
this.autoAdaptTop(v)
}
},
methods: {
closeContextMenu() {
this.$emit('input', false)

@ -1,8 +1,11 @@
<script type="text/jsx">
export default {
name: "DialogFormItem",
functional: true,
props: {full: Boolean, dense: Boolean, label: String, prop: String},
render(h, context) {
let {full, dense, label, prop} = context.props
let attrs = {xs: 24, sm: 12, lg: 8}

@ -7,6 +7,7 @@
v-on="$listeners"
>
<slot slot="title" name="title">{{title}}</slot>
<div class="dialog-form-container">
<loading-mask :show="loading"/>
<el-scrollbar>
@ -16,6 +17,7 @@
<div style="margin-bottom: 17px"/>
</el-scrollbar>
</div>
<slot slot="footer" name="footer"/>
</el-dialog>
</template>
@ -25,7 +27,9 @@
export default {
name: "DialogForm",
components: {LoadingMask},
props: {
value: Boolean,
appendToBody: Boolean,

@ -2,6 +2,7 @@
<div :class="{active:isActive}" class="share-dropdown-menu">
<div class="share-dropdown-menu-wrapper">
<span class="share-dropdown-menu-title" @click.self="clickTitle">{{ title }}</span>
<div v-for="(item,index) of items" :key="index" class="share-dropdown-menu-item">
<a v-if="item.href" :href="item.href" target="_blank">{{ item.title }}</a>
<span v-else>{{ item.title }}</span>
@ -14,6 +15,7 @@
//drop.js
export default {
name: 'DropdownMenu',
props: {
items: {
type: Array,
@ -26,11 +28,13 @@
default: 'vue'
}
},
data() {
return {
isActive: false
}
},
methods: {
clickTitle() {
this.isActive = !this.isActive
@ -39,71 +43,4 @@
}
</script>
<style lang="scss">
$n: 9; //items.length
$t: .1s;
.share-dropdown-menu {
width: 250px;
position: relative;
z-index: 1;
&-title {
width: 100%;
display: block;
cursor: pointer;
background: black;
color: white;
height: 60px;
line-height: 60px;
font-size: 20px;
text-align: center;
z-index: 2;
transform: translate3d(0, 0, 0);
}
&-wrapper {
position: relative;
}
&-item {
text-align: center;
position: absolute;
width: 100%;
background: #e0e0e0;
line-height: 60px;
height: 60px;
cursor: pointer;
font-size: 20px;
opacity: 1;
transition: transform 0.28s ease;
&:hover {
background: black;
color: white;
}
@for $i from 1 through $n {
&:nth-of-type(#{$i}) {
z-index: -1;
transition-delay: $i*$t;
transform: translate3d(0, -60px, 0);
}
}
}
&.active {
.share-dropdown-menu-wrapper {
z-index: 1;
}
.share-dropdown-menu-item {
@for $i from 1 through $n {
&:nth-of-type(#{$i}) {
transition-delay: ($n - $i)*$t;
transform: translate3d(0, ($i - 1)*60px, 0);
}
}
}
}
}
</style>
<style lang="scss" src="./style.scss"></style>

@ -0,0 +1,66 @@
$n: 9; //和items.length 相同
$t: .1s;
.share-dropdown-menu {
width: 250px;
position: relative;
z-index: 1;
&-title {
width: 100%;
display: block;
cursor: pointer;
background: black;
color: white;
height: 60px;
line-height: 60px;
font-size: 20px;
text-align: center;
z-index: 2;
transform: translate3d(0, 0, 0);
}
&-wrapper {
position: relative;
}
&-item {
text-align: center;
position: absolute;
width: 100%;
background: #e0e0e0;
line-height: 60px;
height: 60px;
cursor: pointer;
font-size: 20px;
opacity: 1;
transition: transform 0.28s ease;
&:hover {
background: black;
color: white;
}
@for $i from 1 through $n {
&:nth-of-type(#{$i}) {
z-index: -1;
transition-delay: $i*$t;
transform: translate3d(0, -60px, 0);
}
}
}
&.active {
.share-dropdown-menu-wrapper {
z-index: 1;
}
.share-dropdown-menu-item {
@for $i from 1 through $n {
&:nth-of-type(#{$i}) {
transition-delay: ($n - $i)*$t;
transform: translate3d(0, ($i - 1)*60px, 0);
}
}
}
}
}

@ -1,7 +1,9 @@
<script type="text/jsx">
export default {
name: 'DefaultEmptyImage',
functional: true,
render() {
return (
<svg width="184" height="152" viewBox="0 0 184 152" xmlns="http://www.w3.org/2000/svg">

@ -3,12 +3,15 @@
export default {
name: "AEmpty",
functional: true,
props: {
description: String,
image: [String, Object],
imageStyle: [String, Object]
},
render(h, context) {
const {description = '暂无数据', image, imageStyle} = context.props
const prefixCls = 'ant-empty'
@ -32,52 +35,4 @@
}
</script>
<style lang="scss">
.ant-empty {
padding: 20px;
margin: 0 8px;
font-size: 14px;
line-height: 22px;
text-align: center;
&-image {
height: 100px;
margin-bottom: 8px;
img {
height: 100%;
}
svg {
height: 100%;
margin: auto;
}
}
&-description {
margin: 0;
}
&-footer {
margin-top: 16px;
}
&-normal {
margin: 32px 0;
color: rgba(0, 0, 0, .25);
.ant-empty-image {
height: 40px;
}
}
&-small {
margin: 8px 0;
color: rgba(0, 0, 0, .25);
.ant-empty-image {
height: 35px;
}
}
}
</style>
<style lang="scss" src="./style.scss"></style>

@ -0,0 +1,47 @@
.ant-empty {
padding: 20px;
margin: 0 8px;
font-size: 14px;
line-height: 22px;
text-align: center;
&-image {
height: 100px;
margin-bottom: 8px;
img {
height: 100%;
}
svg {
height: 100%;
margin: auto;
}
}
&-description {
margin: 0;
}
&-footer {
margin-top: 16px;
}
&-normal {
margin: 32px 0;
color: rgba(0, 0, 0, .25);
.ant-empty-image {
height: 40px;
}
}
&-small {
margin: 8px 0;
color: rgba(0, 0, 0, .25);
.ant-empty-image {
height: 35px;
}
}
}

@ -2,6 +2,7 @@
<div>
<el-popover ref="popover" :value="showPopover" trigger="manual" width="300">
<div v-html="step.content" style="padding: 10px"/>
<div class="guide-popover-action">
<div class="action-close">
<el-button v-show="hasDone" size="small" @click="exit">
@ -11,6 +12,7 @@
{{step.closeBtnText}}
</el-button>
</div>
<div class="action-step">
<el-button v-show="showPrevBtn" class="prev-btn" size="small" @click="previous">
{{step.prevBtnText}}
@ -20,24 +22,27 @@
</el-button>
</div>
</div>
<div slot="reference" v-show="showStage" id="guide-stage" :style="stageStyle"/>
</el-popover>
<div v-show="showStage" id="guide-highlight-element-cover" :style="stageStyle" @click.prevent.stop/>
<div v-show="showOverlay" id="guide-overlay"/>
</div>
</template>
<script>
/*
* 由driver.js改造而来
* vue里交互型的导航不太行太多东西做不到换成引导手册吧
* */
/**
* 由driver.js改造而来
* vue里交互型的导航不太行太多东西做不到换成引导手册吧
*/
import {debounce, isEmpty} from "@/utils"
import {addHighlightClasses, getCalculatedPosition, inAppView, jump, removeHighlightClasses} from "./utils"
export default {
name: "Guide",
data() {
return {
steps: [],
@ -59,6 +64,7 @@
lastHighlightedElement: null
}
},
computed: {
showPopover() {
return !this.moving && this.showStage
@ -83,11 +89,13 @@
}
}
},
watch: {
isActive(v) {
v ? document.body.classList.add('overflow-hidden') : document.body.classList.remove('overflow-hidden')
}
},
methods: {
start(index = 0) {
if (!this.steps || this.steps.length === 0) throw new Error('请传入步骤')
@ -207,84 +215,16 @@
`backgroundColor:${this.step.stageBackground}`
}
},
mounted() {
this.resize = debounce(this.resize)
window.addEventListener('resize', this.resize)
},
beforeDestroy() {
window.removeEventListener('resize', this.resize)
}
}
</script>
<style lang="scss">
.guide-highlighted-element {
z-index: 1002 !important;
}
.guide-position-relative {
position: relative !important;
}
.guide-fix-stacking {
z-index: auto !important;
opacity: 1.0 !important;
transform: none !important;
filter: none !important;
perspective: none !important;
transform-style: flat !important;
will-change: unset !important;
}
.guide-popover-action {
position: relative;
height: 100%;
width: 100%;
.action-close {
display: inline-block;
}
.action-step {
display: inline-block;
right: 0;
position: absolute;
.prev-btn {
position: absolute;
right: 90px;
}
.next-btn {
}
}
}
#guide-stage {
position: absolute;
background: white;
transition: all 0.3s;
z-index: 1001 !important;
border-radius: 2px;
/*background: transparent !important;
outline: 5000px solid rgba(0, 0, 0, 0.75);*/
}
#guide-overlay {
background: black;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0.75;
z-index: 1000 !important;
}
#guide-highlight-element-cover {
position: absolute;
background: transparent !important;
z-index: 1003 !important;
}
</style>
<style lang="scss" src="./style.scss"></style>

@ -0,0 +1,69 @@
.guide-highlighted-element {
z-index: 1002 !important;
}
.guide-position-relative {
position: relative !important;
}
.guide-fix-stacking {
z-index: auto !important;
opacity: 1.0 !important;
transform: none !important;
filter: none !important;
perspective: none !important;
transform-style: flat !important;
will-change: unset !important;
}
.guide-popover-action {
position: relative;
height: 100%;
width: 100%;
.action-close {
display: inline-block;
}
.action-step {
display: inline-block;
right: 0;
position: absolute;
.prev-btn {
position: absolute;
right: 90px;
}
.next-btn {
}
}
}
#guide-stage {
position: absolute;
background: white;
transition: all 0.3s;
z-index: 1001 !important;
border-radius: 2px;
/*background: transparent !important;
outline: 5000px solid rgba(0, 0, 0, 0.75);*/
}
#guide-overlay {
background: black;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
opacity: 0.75;
z-index: 1000 !important;
}
#guide-highlight-element-cover {
position: absolute;
background: transparent !important;
z-index: 1003 !important;
}

@ -7,7 +7,9 @@
export default {
name: "ImageViewer",
components: {ElImageViewer: ImageViewer},
data() {
return {
value: false,
@ -15,6 +17,7 @@
urlList: []
}
},
methods: {
close() {
this.value = false

@ -2,8 +2,11 @@
//muse-uihttps://muse-ui.org/#/zh-CN/progress
export default {
name: "LinerProgress",
functional: true,
props: {show: Boolean},
render(h, context) {
if (context.props.show) {
return (
@ -17,41 +20,4 @@
}
</script>
<style lang="scss">
.liner-progress {
position: relative;
height: 4px;
display: block;
width: 100%;
margin: 0;
overflow: hidden;
.liner-progress-background {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $--color-primary;
opacity: .3;
}
.linear-progress-indeterminate {
position: absolute;
top: 0;
bottom: 0;
width: 40%;
background-color: $--color-primary;
animation: linear-progress-animate .84s cubic-bezier(.445, .05, .55, .95) infinite;
}
@keyframes linear-progress-animate {
0% {
left: -40%;
}
100% {
left: 100%;
}
}
}
</style>
<style lang="scss" src="./style.scss"></style>

@ -0,0 +1,36 @@
.liner-progress {
position: relative;
height: 4px;
display: block;
width: 100%;
margin: 0;
overflow: hidden;
.liner-progress-background {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: $--color-primary;
opacity: .3;
}
.linear-progress-indeterminate {
position: absolute;
top: 0;
bottom: 0;
width: 40%;
background-color: $--color-primary;
animation: linear-progress-animate .84s cubic-bezier(.445, .05, .55, .95) infinite;
}
@keyframes linear-progress-animate {
0% {
left: -40%;
}
100% {
left: 100%;
}
}
}

@ -3,7 +3,9 @@
export default {
name: 'Link',
functional: true,
render(h, context) {
let to = context.props.to
if (isExternal(to)) return (

@ -1,10 +1,11 @@
<script type="text/jsx">
export default {
name: "LoadingMask",
functional: true,
props: {
show: Boolean
},
props: {show: Boolean},
render(h, context) {
if (context.props.show === false) return ''
return (

@ -24,12 +24,14 @@
export default {
name: 'OrgTree',
components: {
OrgTreeNode: {
render,
functional: true
}
},
props: {
data: {
type: Object,
@ -55,12 +57,14 @@
default: false
}
},
data() {
return {
flatData: {},
dataCloned: {}
}
},
watch: {
data(newData) {
this._handleData(newData)
@ -74,6 +78,7 @@
this._toggleExpand(this.dataCloned, status)
}
},
computed: {
prop_id() {
return this.props.id
@ -88,6 +93,7 @@
return this.props.children
}
},
methods: {
_handleData(data) {
this._cloneData(data)
@ -169,6 +175,7 @@
this._updateExpandStatus()
}
},
mounted() {
this._handleData(this.data)
this._updateExpandStatus()

@ -9,18 +9,22 @@
<div class="puzzle-view" :style="`width:${width}px;height:${height}px;`">
<div v-show="!image.loading" style="width: 100%;height: 100%">
<img :src="image.src"/>
<canvas ref="puzzleBox" :height="height" :width="width"/>
<div class="puzzle-lost-box" :style="`left:${leftNum}px`">
<canvas ref="puzzleShadow" :style="sliderStyle" :height="height" :width="width"/>
<canvas ref="puzzleLost" :style="sliderStyle" :height="height" :width="width"/>
</div>
</div>
<transition name="fade">
<div v-show="image.loading" class="puzzle-image-loading">
<div class="puzzle-image-loading__icon"/>
<div class="puzzle-image-loading__text">加载中...</div>
</div>
</transition>
<div :class="resultTipClass">
{{stat==='success'?'验证通过':'请正确拼合图像'}}
</div>
@ -38,6 +42,7 @@
<a class="puzzle-text-container puzzle-close" @click="close">
<div class="puzzle-text-tip">关闭验证</div>
</a>
<a class="puzzle-text-container puzzle-refresh" @click="refresh">
<div class="puzzle-text-tip">刷新验证</div>
</a>
@ -54,6 +59,7 @@
* */
export default {
name: "PuzzleVerify",
props: {
//transition.scss
transition: {
@ -85,6 +91,7 @@
default: 80
}
},
data() {
return {
visible: false,
@ -107,6 +114,7 @@
}
}
},
computed: {
resultTipClass() {
const showResultTip = ['success', 'fail'].includes(this.stat)
@ -119,6 +127,7 @@
}
}
},
methods: {
close() {
this.visible = false
@ -295,6 +304,7 @@
this.$el.parentNode.removeChild(this.$el)
}
},
mounted() {
this.initImage().then(() => this.initCanvas())
},

@ -12,13 +12,16 @@
<template slot="empty">
<div class="rg-header">
<h3>行政区划选择</h3>
<button class="rg-removeall-button" type="button" title="清除已选" @click="removeAll">
<i class="el-icon-delete"/>
</button>
<button class="rg-done-button" type="button" title="完成" @click="done">
<i class="el-icon-check"/>
</button>
</div>
<div class="rg-search">
<input
ref="searchInput"
@ -29,6 +32,7 @@
@input="search"
>
</div>
<div class="rg-level-tabs">
<ul>
<li v-for="(tab,index) in selected" :key="tab.name" :class="{active:index+1 === currentLevel}">
@ -36,6 +40,7 @@
</li>
</ul>
</div>
<div v-loading="loading" class="rg-results-container">
<ul class="rg-results">
<li

@ -1,12 +1,15 @@
<script type="text/jsx">
export default {
name: "SearchFormItem",
inject: {
searchForm: {
default: () => ({width: 'auto'})
}
},
props: {label: String},
render() {
const {width} = this.searchForm
return (

@ -3,11 +3,13 @@
export default {
name: "SearchForm",
provide() {
return {
searchForm: this
}
},
props: {
labelWidth: {type: String, default: '120px'},
xs: {type: Number, default: 24},// <768px
@ -15,6 +17,7 @@
md: {type: Number, default: 8}, // >=998px
lg: {type: Number, default: 6} // >=1200px
},
data() {
return {
showCollapse: false,
@ -23,6 +26,7 @@
width: 'auto'
}
},
methods: {
handleCollapse() {
this.collapse = !this.collapse
@ -45,13 +49,16 @@
this.showCollapse = num < this.$slots.default.length
}
},
mounted() {
this.resize()
window.addEventListener('resize', this.resize)
},
beforeDestroy() {
window.removeEventListener('resize', this.resize)
},
render() {
const slots = this.$slots.default
const collapseChildren = []

@ -9,6 +9,7 @@
@touchmove.prevent="drawMove"
@touchend.prevent="drawEnd"
/>
<div class="signature-board__footer">
<el-button plain size="small" @click="clear"> </el-button>
<el-button plain size="small" @click="close"> </el-button>
@ -37,12 +38,14 @@
export default {
name: 'SignatureBoard',
props: {
image: String,
lineWidth: Number,
lineColor: String,
onConfirm: Function
},
data() {
return {
visible: false,
@ -52,6 +55,7 @@
startY: 0
}
},
methods: {
drawStart(e) {
const {x, y} = getEventPoint(e)
@ -125,9 +129,11 @@
this.visible = false
}
},
mounted() {
window.addEventListener('resize', this.resize)
},
beforeDestroy() {
this.clear()
window.removeEventListener('resize', this.resize)

@ -4,7 +4,9 @@
export default {
name: "PageSkeleton",
functional: true,
render() {
const single = (
<div class="page-skeleton">

@ -4,7 +4,9 @@
export default {
name: 'QSkeleton',
functional: true,
props: {
type: {
type: String,
@ -25,6 +27,7 @@
width: String,
height: String
},
render(h, context) {
const {type, animation, className, tag, dark, square, bordered, size, width, height} = context.props
const style = size !== undefined ? {width: size, height: size} : {width, height}

@ -3,7 +3,9 @@
export default {
name: 'SvgIcon',
functional: true,
props: {
icon: {
type: String,
@ -14,6 +16,7 @@
default: ''
}
},
render(h, context) {
const {listeners} = context
const {icon, className} = context.props

@ -21,6 +21,7 @@
export default {
name: "TinymceEditor",
props: {
value: String,
readonly: Boolean,
@ -33,6 +34,7 @@
default: '100%'
}
},
data() {
return {
id: 'tinymce-' + Date.now(),
@ -41,6 +43,7 @@
manualChange: false,
}
},
watch: {
value(value) {
if (!this.hasInit) return
@ -51,6 +54,7 @@
this.hasInit && this.getInstance().mode.set(value ? 'readonly' : 'design')
}
},
methods: {
getInstance() {
return window.tinymce.get(this.id)
@ -95,9 +99,11 @@
tinymce.destroy()
}
},
mounted() {
!this.readonly && this.init()
},
beforeDestroy() {
this.destroy()
},

@ -1,7 +1,9 @@
<template>
<div class="zoom-wrapper">
<el-button circle icon="el-icon-minus" size="small" title="缩小" type="info" @click="zoomOut"/>
<span class="zoom-number">{{ value }}%</span>
<el-button circle icon="el-icon-plus" size="small" title="放大" type="info" @click="zoomIn"/>
</div>
</template>
@ -9,6 +11,7 @@
<script>
export default {
name: "ZoomControl",
props: {
value: {
type: Number,
@ -27,16 +30,18 @@
default: 200
}
},
methods: {
zoomIn() {
const zoom = this.value + this.step
if (zoom <= this.max) this.$emit('input', zoom)
},
zoomOut() {
const zoom = this.value - this.step
if (zoom >= this.min) this.$emit('input', zoom)
}
},
}
}
</script>

@ -6,6 +6,7 @@
@mouseleave="mouseOutside=true"
>
<v-navbar @menu-show="navbarMenuShow=$event"/>
<tags-view v-if="useTagsView" @menu-show="tagsViewMenuShow=$event"/>
</header>
</template>
@ -17,7 +18,9 @@
export default {
name: "Header",
components: {VNavbar, TagsView},
data() {
return {
mouseOutside: true,
@ -26,11 +29,13 @@
appMain: null
}
},
computed: {
...mapState('setting', {
useTagsView: state => state.useTagsView,
headerAutoHidden: state => state.headerAutoHidden
}),
hideHeader() {
return this.mouseOutside
&& this.headerAutoHidden
@ -38,35 +43,43 @@
&& !this.navbarMenuShow
},
},
watch: {
useTagsView(v) {
!v && this.$store.dispatch('tagsView/delAllViews')
},
hideHeader(v) {
this.$store.commit('app/hasHeader', !v)
v ? this.addEvent() : this.removeEvent()
}
},
methods: {
moveEvent(e) {
if (e.clientY <= 15) this.mouseOutside = false
},
addEvent() {
this.appMain.addEventListener('mousemove', this.moveEvent)
},
removeEvent() {
this.appMain.removeEventListener('mousemove', this.moveEvent)
}
},
mounted() {
this.appMain = document.querySelector('.app-main')
if (this.headerAutoHidden) this.addEvent()
},
beforeDestroy() {
this.removeEvent()
}
}
</script>
<style lang="scss">
.has-tags-view .header-container {
height: calc(#{$nav-height} + #{$tags-view-height});

@ -33,28 +33,34 @@
export default {
name: 'AppMain',
computed: {
...mapState('app', {
scrollTop: state => state.scrollTop,
}),
...mapState('setting', {
showBackToTop: state => state.showBackToTop
}),
...mapState('tagsView', {
cachedViews: state => state.cachedViews,
transitionName: state => state.transitionName
}),
...mapState('iframe', {
showIframe: state => state.show,
currentIframe: state => state.current,
iframeList: state => state.list
})
},
watch: {
scrollTop(v) {
if (v >= 0) this.$refs.scrollbar.$refs.wrap.scrollTop = v
}
},
mounted() {
//footer
const FooterConstructor = Vue.extend(Footer)

@ -7,11 +7,13 @@
<script>
export default {
name: "Bell",
computed: {
hidden() {
return this.$store.state.message.unreadCount < 1
}
},
methods: {
jump() {
let target = '/message/user'
@ -19,11 +21,13 @@
this.$router.replace(target)
}
},
mounted() {
this.$store.dispatch('message/refresh')
}
}
</script>
<style>
.bell-badge .el-badge__content {
top: 15px !important;

@ -15,18 +15,21 @@
data: null
}
},
watch: {
$route(route) {
if (route.path.startsWith('/redirect')) return
this.getBreadcrumb()
}
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
this.data = this.$route.matched.filter(item => item.meta.title)
}
},
mounted() {
this.getBreadcrumb()
}

@ -1,85 +0,0 @@
<template>
<div @click="change">
<i :class="icon" class="navbar-icon"/>
</div>
</template>
<script>
//iview-admin https://admin.iviewui.com
export default {
name: "Fullscreen",
props: {
value: {
type: Boolean,
default: false
},
events: {
type: Array,
default: () => ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange']
}
},
computed: {
icon() {
return this.value ? 'el-icon-aim' : 'el-icon-full-screen'
}
},
methods: {
change() {
let main = document.body
if (this.value) {
if (document.exitFullscreen) {
document.exitFullscreen()
}
else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
}
else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen()
}
else if (document.msExitFullscreen) {
document.msExitFullscreen()
}
}
else {
if (main.requestFullscreen) {
main.requestFullscreen()
}
else if (main.mozRequestFullScreen) {
main.mozRequestFullScreen()
}
else if (main.webkitRequestFullScreen) {
main.webkitRequestFullScreen()
}
else if (main.msRequestFullscreen) {
main.msRequestFullscreen()
}
}
},
emit() {
this.$emit('input', !this.value)
this.$emit('on-change', !this.value)
},
bindEvent() {
this.events.forEach(e => document.addEventListener(e, this.emit))
},
removeEvent() {
this.events.forEach(e => document.removeEventListener(e, this.emit))
}
},
mounted() {
let isFullscreen =
document.fullscreenElement
|| document.mozFullScreenElement
|| document.webkitFullscreenElement
|| document.fullScreen
|| document.mozFullScreen
|| document.webkitIsFullScreen
isFullscreen = !!isFullscreen
this.bindEvent()
this.$emit('input', isFullscreen)
},
beforeDestroy() {
this.removeEvent()
}
}
</script>

@ -1,10 +1,11 @@
<script type="text/jsx">
export default {
name: 'Hamburger',
functional: true,
props: {
isActive: Boolean
},
props: {isActive: Boolean},
render(h, context) {
const {isActive} = context.props
return (

@ -1,6 +1,7 @@
<template>
<div :class="{'show':show}" class="header-search">
<i class="el-icon-search navbar-icon" title="快捷搜索" @click.stop="click"/>
<el-select
ref="headerSearchSelect"
v-model="search"
@ -27,6 +28,7 @@
export default {
name: 'HeaderSearch',
data() {
return {
search: '',
@ -36,36 +38,43 @@
fuse: null
}
},
computed: {
routes() {
return this.$store.state.resource.routes
}
},
watch: {
routes() {
this.searchPool = this.generateRoutes(this.routes)
this.initFuse(this.searchPool)
},
show(value) {
if (value) document.body.addEventListener('click', this.close)
else document.body.removeEventListener('click', this.close)
}
},
methods: {
click() {
this.show = !this.show
if (this.show) this.$refs.headerSearchSelect.focus()
},
close() {
this.$refs.headerSearchSelect.blur()
this.search = ''
this.options = []
this.show = false
},
change(val) {
this.close()
this.$router.push(val).catch(() => ({}))
},
initFuse(list) {
this.fuse = new Fuse(list, {
shouldSort: true,
@ -77,6 +86,7 @@
keys: ['title']
})
},
generateRoutes(routes, prefixTitle = []) {
let res = []
for (const route of routes) {
@ -94,10 +104,12 @@
}
return res
},
querySearch(query) {
this.options = query ? this.fuse.search(query) : []
}
},
mounted() {
this.searchPool = this.generateRoutes(this.routes)
this.initFuse(this.searchPool)

@ -25,14 +25,18 @@
export default {
name: "SettingDrawer",
props: {
value: Boolean
},
data: () => ({settings}),
methods: {
getValue(key) {
return this.$store.state.setting[key]
},
setValue(value, key) {
this.$store.commit(`setting/${key}`, value)
}

@ -59,35 +59,44 @@
export default {
name: 'navbar',
mixins: [GuideMixin.navbar],
components: {Hamburger, Breadcrumb, Search, Bell, SettingDrawer},
data() {
return {
fullscreen: false,
settingDrawer: false
}
},
computed: {
...mapState('user', {
avatar: state => state.avatar,
name: state => state.name,
prepare_logout: state => state.prepare_logout
}),
...mapState('setting', {
sidebarCollapse: state => state.sidebarCollapse,
showBreadcrumb: state => state.showBreadcrumb
}),
showSystemMonitor() {
return auth('/system/monitor')
},
showSystemResource() {
return auth('/system/resource')
}
},
methods: {
clickHamburger() {
this.$store.commit('setting/sidebarCollapse', !this.sidebarCollapse)
},
logout() {
if (this.prepare_logout) return
elConfirm('确认退出?')
@ -97,57 +106,4 @@
}
</script>
<style lang="scss">
.navbar {
height: $nav-height;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
.navbar-icon {
font-size: 18px;
cursor: pointer;
vertical-align: middle;
}
.right-menu {
float: right;
height: 100%;
line-height: $nav-height;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
position: relative;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
transition: background .3s;
cursor: pointer;
&:hover:not(#header-search) {
background: rgba(0, 0, 0, .025)
}
}
.avatar-container {
.avatar-wrapper {
margin-top: 5px;
position: relative;
.el-avatar {
position: relative;
top: 5px;
margin-right: 5px;
}
}
}
}
}
</style>
<style lang="scss" src="./style.scss"></style>

@ -0,0 +1,52 @@
.navbar {
height: $nav-height;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
.navbar-icon {
font-size: 18px;
cursor: pointer;
vertical-align: middle;
}
.right-menu {
float: right;
height: 100%;
line-height: $nav-height;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
position: relative;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #5a5e66;
vertical-align: text-bottom;
transition: background .3s;
cursor: pointer;
&:hover:not(#header-search) {
background: rgba(0, 0, 0, .025)
}
}
.avatar-container {
.avatar-wrapper {
margin-top: 5px;
position: relative;
.el-avatar {
position: relative;
top: 5px;
margin-right: 5px;
}
}
}
}
}

@ -2,7 +2,7 @@
<div :class="{'collapse':collapse}" class="sidebar-logo-container">
<router-link class="sidebar-logo-link" key="expand" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo">
<h1 v-if="!collapse" class="sidebar-title">{{ title }} </h1>
<h1 v-if="!collapse" class="sidebar-title">{{ title }}</h1>
</router-link>
</div>
</template>
@ -12,7 +12,9 @@
export default {
name: 'SidebarLogo',
props: {collapse: Boolean},
data() {
return {
title,

@ -61,12 +61,14 @@
export default {
functional: true,
props: {
item: Object,
isNest: Boolean,
showParent: Boolean,
collapse: Boolean
},
render(h, context) {
return renderNode(h, context.props)
}

@ -1,11 +1,14 @@
<script type="text/jsx">
export default {
name: "SidebarItemContent",
functional: true,
props: {
icon: String,
title: String
},
render(h, context) {
const {icon, title} = context.props
const vnodes = []

@ -6,19 +6,24 @@
export default {
name: 'sidebar',
components: {SidebarItem, Logo},
data() {
return {
mouseOutside: true
}
},
computed: {
...mapState('app', {
device: state => state.device
}),
...mapState('resource', {
routes: state => state.sidebarMenus
}),
...mapState('setting', {
showLogo: state => state.showLogo,
sidebarCollapse: state => state.sidebarCollapse,
@ -26,14 +31,17 @@
sidebarShowParent: state => state.sidebarShowParent,
sidebarAutoHidden: state => state.sidebarAutoHidden
}),
//pc
collapse() {
return this.sidebarCollapse && this.device === 'pc'
},
hideSidebar() {
return this.sidebarAutoHidden && this.mouseOutside
|| this.sidebarCollapse && this.device === 'mobile'
},
sidebarClass() {
return {
'sidebar-container': true,
@ -43,6 +51,7 @@
}
}
},
watch: {
//elMenuinitOpenedMenu()select
'$route.path'(nv, ov) {
@ -55,15 +64,18 @@
if (!item) menu.openedMenus = []
else this.select(item.index, item.indexPath, item, false)
},
hideSidebar(v) {
if (v) document.addEventListener('mousemove', this.moveEvent)
else document.removeEventListener('mousemove', this.moveEvent)
}
},
methods: {
moveEvent(e) {
if (e.clientX <= 15) this.mouseOutside = false
},
select(index, indexPath, item, jump = true) {
//
if (this.sidebarUniqueOpen && indexPath.length === 1) {
@ -84,14 +96,17 @@
else this.$router.push(index)
}
},
mounted() {
if (this.sidebarAutoHidden) {
document.addEventListener('mousemove', this.moveEvent)
}
},
beforeDestroy() {
document.removeEventListener('mousemove', this.moveEvent)
},
render() {
const menu = (
<el-menu

@ -9,12 +9,15 @@
export default {
name: 'ScrollPane',
data: () => ({rAF: null}),
computed: {
scrollWrapper() {
return this.$refs.scrollContainer.$refs.wrap
},
},
methods: {
handleScroll(e) {
const eventDelta = e.wheelDelta || -(e.detail || 0) * 40
@ -22,6 +25,7 @@
if (eventDelta < 0 && this.scrollWrapper.scrollWidth <= this.scrollWrapper.scrollLeft + this.scrollWrapper.clientWidth) return
this.smoothScroll(-eventDelta * 2)
},
moveToTarget(currentTag) {
const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth
@ -63,12 +67,14 @@
}
}
},
scrollLeft(val) {
this.scrollWrapper.scrollTo({
left: val,
behavior: 'smooth'
})
},
smoothScroll(val) {
if (this.rAF) window.cancelAnimationFrame(this.rAF)
let cost = 300, times = cost / 16, gap = val / times + 1

@ -16,6 +16,7 @@
<i v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)"/>
</router-link>
</scroll-pane>
<context-menu v-model="contextmenu.show" :left="contextmenu.left" :top="contextmenu.top">
<context-menu-item @click="refreshSelectedTag(selectedTag)">刷新</context-menu-item>
<context-menu-item v-show="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
@ -36,7 +37,9 @@
export default {
mixins: [shortcutsMixin, decideRouterTransitionMixin],
components: {ContextMenu, ContextMenuItem, ScrollPane},
data() {
return {
contextmenu: {
@ -49,24 +52,29 @@
scroller: null
}
},
computed: {
visitedViews() {
return this.$store.state.tagsView.visitedViews
},
routes() {
return this.$store.state.resource.routes
}
},
watch: {
$route(to, from) {
this.decideRouteTransition && this.decideRouteTransition(to, from)
this.addTags(to)
this.moveToCurrentTag()
},
'contextmenu.show'(v) {
this.$emit('menu-show', v)
}
},
methods: {
isActive(route) {
return route.path === this.$route.path
@ -165,6 +173,7 @@
this.selectedTag = tag
}
},
mounted() {
this.initTags()
this.addTags()

@ -22,35 +22,45 @@
export default {
name: 'Layout',
mixins: [ResizeHandler],
components: {VMain, VSidebar, VHeader},
computed: {
...mapState('app', {
device: state => state.device,
hasHeader: state => state.hasHeader
}),
...mapState('setting', {
useTagsView: state => state.useTagsView,
sidebarCollapse: state => state.sidebarCollapse
}),
...mapState('socket', {
online: state => state.online
}),
...mapState('user', {
isLogin: state => !isEmpty(state.id) && !isEmpty(state.token)
}),
showOfflineTip() {
return !this.online && this.isLogin
},
showSidebarMask() {
return !this.sidebarCollapse && this.device === 'mobile'
}
},
watch: {
showOfflineTip(v) {
v ? this.$bottomTip('与服务器失去连接') : this.$bottomTip.close()
}
},
methods: {
collapseSidebar() {
this.$store.commit('setting/sidebarCollapse', true)

@ -4,12 +4,14 @@
<div class="pic">
<img alt="403" height="428" src="static/img/403.gif" width="313">
</div>
<div class="bullshit">
<div class="bullshit__oops">Oops!</div>
<div class="bullshit__headline">没有访问权限</div>
<div class="bullshit__info">
请联系管理员或者点击下方按钮返回
</div>
<div class="bullshit__info">请联系管理员或者点击下方按钮返回</div>
<router-link class="bullshit__return-home" to="/index">返回首页</router-link>
</div>
</div>

@ -7,12 +7,14 @@
<img alt="404" class="pic__child mid" src="static/img/404_cloud.png">
<img alt="404" class="pic__child right" src="static/img/404_cloud.png">
</div>
<div class="bullshit">
<div class="bullshit__oops">Oops!</div>
<div class="bullshit__headline">没有找到该页面...</div>
<div class="bullshit__info">
请检查链接地址是否正确或者点击下方按钮返回
</div>
<div class="bullshit__info">请检查链接地址是否正确或者点击下方按钮返回</div>
<router-link class="bullshit__return-home" to="/index">返回首页</router-link>
</div>
</div>

@ -4,6 +4,7 @@
<span class="svg-container">
<svg-icon icon="user"/>
</span>
<el-input
ref="username"
v-model="form.username"
@ -13,12 +14,14 @@
type="text"
/>
</el-form-item>
<el-form-item prop="password">
<el-tooltip v-model="capsTooltip" :tabindex="-1" content="大写锁定已打开" manual placement="left">
<span class="svg-container">
<svg-icon icon="password"/>
</span>
</el-tooltip>
<el-input
ref="password"
v-model="form.password"
@ -29,10 +32,12 @@
placeholder="请输入密码"
@keyup.enter.native="login"
/>
<span @click="showPwd" class="show-pwd">
<svg-icon :icon="passwordType === 'password' ? 'eye' : 'eye-open'"/>
</span>
</el-form-item>
<el-button
:loading="loading"
class="submit-btn"
@ -41,11 +46,13 @@
>
{{loading ? '登 录 中...' : '登 录'}}
</el-button>
<div class="flex" style="margin-top: 20px">
<p class="other-ways">
其他方式登录
<svg-icon v-for="i in otherWays" :key="i" :icon="i" @click="thirdPartyLogin(i)"/>
</p>
<el-button type="text" @click="register">注册账户</el-button>
</div>
</el-form>
@ -58,6 +65,7 @@
export default {
name: "LoginForm",
data() {
return {
loading: false,
@ -77,11 +85,13 @@
otherWays: ['qq']
}
},
methods: {
showPwd() {
this.passwordType = this.passwordType === 'password' ? '' : 'password'
this.$nextTick(() => this.$refs.password.focus())
},
login() {
if (this.loading) return
this.$refs.form.validate(valid => {
@ -96,33 +106,41 @@
.catch(() => this.loading = false)
})
},
register() {
!this.loading && this.$router.push('/register')
},
success() {
elSuccess('登陆成功')
const redirect = this.$route.query.redirect || '/'
//0.2s
setTimeout(() => this.$router.push(redirect), 200)
},
thirdPartyLogin(channel) {
this.$message.info('假装可以第三方登录')
},
capsLockTip({keyCode}) {
if (keyCode === 20) this.capsTooltip = !this.capsTooltip
},
addCapsLockEvent() {
document.addEventListener('keyup', this.capsLockTip)
},
removeEvent() {
document.removeEventListener('keyup', this.addCapsLockEvent)
}
},
mounted() {
this.addCapsLockEvent()
if (isEmpty(this.form.username)) this.$refs.username.focus()
else this.$refs.password.focus()
},
beforeDestroy() {
this.removeEvent()
}

@ -6,6 +6,7 @@
</span>
<el-input ref="username" v-model="form.username" :maxlength="20" placeholder="请输入用户名"/>
</el-form-item>
<el-form-item prop="pwd">
<el-tooltip v-model="capsTooltip" :tabindex="-1" content="大写锁定已打开" manual placement="left">
<span class="svg-container">
@ -14,6 +15,7 @@
</el-tooltip>
<el-input v-model="form.pwd" placeholder="请输入密码" type="password" :maxlength="20"/>
</el-form-item>
<el-form-item prop="repwd">
<span class="svg-container">
<svg-icon icon="password"/>
@ -26,6 +28,7 @@
@keyup.enter.native="register"
/>
</el-form-item>
<el-button
:loading="loading"
class="submit-btn"
@ -34,6 +37,7 @@
>
{{loading ? '注 册 中...' : '注 册'}}
</el-button>
<div class="flex" style="margin-top: 20px">
<p/>
<el-button type="text" @click="login">已有账户登陆</el-button>
@ -49,6 +53,7 @@
export default {
name: "RegisterForm",
data() {
const validateName = (r, v, c) => {
checkName(this.form.username)
@ -82,6 +87,7 @@
loading: false
}
},
methods: {
register() {
if (this.loading) return
@ -96,23 +102,29 @@
.catch(() => this.loading = false)
})
},
login() {
!this.loading && this.$router.push('/login')
},
capsLockTip({keyCode}) {
if (keyCode === 20) this.capsTooltip = !this.capsTooltip
},
addEvent() {
document.addEventListener('keyup', this.capsLockTip)
},
removeEvent() {
document.removeEventListener('keyup', this.addCapsLockEvent)
}
},
mounted() {
this.addEvent()
this.$nextTick(() => this.$refs.username.focus())
},
beforeDestroy() {
this.removeEvent()
}

@ -11,13 +11,17 @@
{name: '流星雨', value: 'sparkRain'},
{name: '阳光', value: 'sunlight'},
]
export default {
name: "SetAnimation",
functional: true,
props: {
value: String,
customClass: String
},
render(h, context) {
const {value, customClass} = context.props
return (

@ -1,11 +1,13 @@
<template>
<div class="login-page">
<canvas id="login-background"/>
<div class="login-container" @click.stop>
<div class="title">
{{title}}
<set-animation :value="animation" custom-class="set-animation" @select="setAnimation"/>
</div>
<component :is="component"/>
</div>
</div>
@ -21,23 +23,28 @@
export default {
name: 'login',
components: {LoginForm, RegisterForm, SetAnimation},
data() {
return {
title,
animationInstance: null
}
},
computed: {
...mapState('app', {
device: state => state.device,
animation: state => state.loginBackgroundAnimation
}),
component() {
const formType = this.$route.path.substring(1)
return `${[...formType].join('')}-form`
}
},
methods: {
clearAnimation() {
if (this.animationInstance) {
@ -45,6 +52,7 @@
this.animationInstance = null
}
},
setAnimation(value) {
this.clearAnimation()
this.$store.commit('app/loginBackgroundAnimation', value)
@ -53,10 +61,12 @@
.then(_ => this.animationInstance = new _.default(document.getElementById('login-background')))
}
},
mounted() {
//
this.device !== 'mobile' && this.setAnimation(this.animation)
},
beforeDestroy() {
this.clearAnimation()
this.$message.closeAll()

@ -8,6 +8,7 @@
}
else this.$router.replace({path: '/' + params.path, query})
},
render: h => h()
}
</script>

@ -4,12 +4,14 @@
<script>
import {logic, resize} from "@/mixins/chart"
import {getDailyFinishOrder} from '@/api/statistic/index'
import {getDailyFinishOrder} from '@/api/statistic'
import {timeFormat} from "@/utils"
export default {
name: "DailyFinishOrderStat",
mixins: [resize, logic],
methods: {
init() {
if (this.loading) return
@ -28,6 +30,7 @@
})
.finally(() => this.loading = false)
},
setOptions({time, purchase, sell}) {
this.chart.setOption({
title: {

@ -4,12 +4,14 @@
<script>
import {logic, resize} from "@/mixins/chart"
import {getDailyProfitStat} from '@/api/statistic/index'
import {getDailyProfitStat} from '@/api/statistic'
import {timeFormat} from "@/utils"
export default {
name: "DailyProfitStat",
mixins: [resize, logic],
methods: {
init() {
if (this.loading) return
@ -30,6 +32,7 @@
})
.finally(() => this.loading = false)
},
setOptions({time, purchase, sell, profit}) {
this.chart.setOption({
title: {

@ -3,13 +3,16 @@
export default {
name: "PanelGroupItem",
functional: true,
props: {
icon: String,
color: String,
text: String,
value: Number
},
render(h, context) {
const {icon, color, text, value} = context.props
return (

@ -15,7 +15,9 @@
export default {
name: 'panelGroup',
components: {PanelGroupItem},
data() {
return {
loading: false,
@ -34,6 +36,7 @@
]
}
},
methods: {
init() {
if (this.loading) return
@ -46,10 +49,12 @@
})
.finally(() => this.loading = false)
},
jump({path}) {
if (!isEmpty(path) && auth(path)) this.$router.push(path)
}
},
mounted() {
this.init()
}

@ -14,7 +14,9 @@
export default {
name: "TotalProfitGoods",
components: {PieChart},
data() {
return {
loading: false,
@ -32,13 +34,16 @@
}
}
},
methods: {
getTitle(type) {
return this[type].title
},
getData(type) {
return this[type].data
},
init() {
if (this.loading) return
this.loading = true
@ -59,6 +64,7 @@
.finally(() => this.loading = false)
}
},
mounted() {
this.init()
}

@ -22,6 +22,7 @@
export default {
name: 'index',
components: {PanelGroup, DailyProfitStat, DailyFinishOrderStat, TotalProfitGoods}
}
</script>

@ -51,6 +51,7 @@
</dialog-form-item>
</el-row>
</el-form>
<template v-slot:footer>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button v-if="canSave" size="small" type="primary" @click="save"> </el-button>
@ -73,8 +74,11 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm, DialogFormItem, TinymceEditor, UserSelector},
props: {
value: {type: Boolean, default: false},
type: {type: String, default: 'see'},
@ -84,6 +88,7 @@
},
baseUrl: String
},
data() {
return {
loading: false,
@ -111,6 +116,7 @@
}
}
},
computed: {
title() {
if (isEmpty(this.type)) return ''
@ -142,6 +148,7 @@
&& this.form.status === 1
},
},
methods: {
open() {
if (this.type === 'add') return

@ -18,6 +18,7 @@
</el-select>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" icon="el-icon-plus" size="small" type="primary" @click="add"> </el-button>
@ -25,6 +26,7 @@
<el-button v-if="canUpdate" icon="el-icon-edit" size="small" type="primary" @click="edit"> </el-button>
<el-button v-if="canDel" icon="el-icon-delete" size="small" type="danger" @click="del"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @row-click="row=$event">
<el-table-column align="center" label="#" type="index" width="80"/>
@ -43,6 +45,7 @@
<template v-slot="{row}">{{row.ptime | timestamp2Date}}</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -75,8 +78,11 @@
export default {
name: "messageManagement",
mixins: [tableMixin],
components: {SearchForm, SearchFormItem, EditDialog},
data() {
return {
baseUrl: '/message/manage',
@ -90,17 +96,21 @@
regionDialog: false
}
},
computed: {
canAdd() {
return auth(this.baseUrl + '/add')
},
canUpdate() {
return auth(this.baseUrl + '/update')
},
canDel() {
return auth(this.baseUrl + '/del')
}
},
methods: {
transformStatus(status) {
switch (status) {
@ -112,6 +122,7 @@
return '已撤回'
}
},
search() {
if (this.config.loading) return
this.config.loading = true
@ -124,20 +135,24 @@
})
.finally(() => this.config.loading = false)
},
add() {
this.type = 'add'
this.editDialog = true
},
see() {
if (isEmpty(this.row)) return elError('请选择要查看的消息')
this.type = 'see'
this.editDialog = true
},
edit() {
if (isEmpty(this.row)) return elError('请选择要编辑的消息')
this.type = 'edit'
this.editDialog = true
},
del() {
if (isEmpty(this.row)) return elError('请选择要删除的消息')
if (this.row.status !== 0) return elError('只有状态为【拟定】时才能删除')

@ -4,6 +4,7 @@
{{title}}
<document-history :data="history" :type="type" @show="getHistory"/>
</template>
<el-form
ref="form"
:model="form"
@ -14,7 +15,7 @@
status-icon
>
<el-row :gutter="20">
<dialog-form-item label="单 号:" prop="id">
<dialog-form-item v-if="form.id" label="单 号:" prop="id">
<el-input :value="form.id" readonly/>
</dialog-form-item>
<dialog-form-item label="采购订单:" prop="pid">
@ -22,16 +23,16 @@
<el-button slot="append" :disabled="!canSave" @click="parentDialog=true">选择</el-button>
</el-input>
</dialog-form-item>
<dialog-form-item label="创建人:" prop="cname">
<dialog-form-item v-if="form.id" label="创建人:" prop="cname">
<el-input :value="form.cname" readonly/>
</dialog-form-item>
<dialog-form-item label="创建时间:" prop="ctime">
<dialog-form-item v-if="form.id" label="创建时间:" prop="ctime">
<el-date-picker :value="form.ctime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="审核人:" prop="vname">
<dialog-form-item v-if="form.status===2" label="审核人:" prop="vname">
<el-input :value="form.vname" readonly/>
</dialog-form-item>
<dialog-form-item label="审核时间:" prop="vtime">
<dialog-form-item v-if="form.status===2" label="审核时间:" prop="vtime">
<el-date-picker :value="form.vtime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="附 件:" full>
@ -54,6 +55,7 @@
</dialog-form-item>
</el-row>
</el-form>
<el-table :data="form.data">
<el-table-column align="center" label="#" type="index" width="80"/>
<el-table-column align="center" label="商 品" prop="cname"/>
@ -62,6 +64,7 @@
<el-input-number
v-if="canSave"
v-model="row.num"
controls-position="right"
:min="0"
size="small"
@change="(nv,ov)=>changeInboundNum(nv,ov,row)"
@ -70,8 +73,9 @@
</template>
</el-table-column>
</el-table>
<document-steps :status="form.status" :type="type"/>
<order-selector v-model="parentDialog" @select="selectParent"/>
<template v-slot:footer>
<span v-if="form.status===2" class="seal">已审核</span>
<el-button plain size="small" @click="closeDialog"> </el-button>
@ -81,6 +85,8 @@
<el-button v-if="canPass" size="small" type="success" @click="pass"> </el-button>
<el-button v-if="canReject" size="small" type="danger" @click="reject"> </el-button>
</template>
<order-selector v-model="parentDialog" @select="selectParent"/>
</dialog-form>
</template>
@ -95,8 +101,11 @@
export default {
name: "EditDialog",
mixins: [bizDocumentDialogMixin],
components: {OrderSelector},
data() {
return {
documentName: '采购入库单',
@ -113,11 +122,13 @@
parentSubList: []
}
},
methods: {
afterInit() {
if (this.type !== 'edit') return
return getParentSubById(this.form.pid).then(data => this.parentSubList = data)
},
selectParent(id, sub) {
this.parentSubList = sub
this.form.pid = id
@ -128,12 +139,14 @@
num: i.remain_num
}))
},
changeInboundNum(nv, ov, row) {
let parentSub = this.parentSubList.find(i => i.cid === row.cid)
if (!parentSub || nv > parentSub.remain_num) {
return elAlert(`${row.cname}的入库数量超出采购数量`, () => row.num = ov)
}
},
validate() {
if (this.type === 'edit' && isEmpty(this.form.id)) {
return '属性缺失,请关闭弹窗刷新重试'

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择采购订单"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"
@ -14,6 +14,7 @@
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button plain size="small" @click="closeDialog"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @expand-change="getSubList">
<el-table-column align="center" type="expand">
@ -73,9 +74,13 @@
export default {
name: "OrderSelector",
mixins: [dialogMixin, tableMixin],
components: {LinerProgress},
props: {value: Boolean},
data() {
return {
searchForm: {
@ -84,6 +89,7 @@
}
}
},
methods: {
search() {
if (!this.value || this.config.loading) return
@ -101,6 +107,7 @@
})
.finally(() => this.config.loading = false)
},
getSubList(row) {
if (row._loaded || row._loading) return
row._loading = true
@ -111,11 +118,13 @@
})
.finally(() => row._loading = false)
},
confirm(row) {
if (row._selection.length <= 0) return elError('请选择要入库的商品')
this.$emit('select', row.id, row._selection)
this.cancel()
},
cancel() {
this.closeDialog()
this.tableData = []
@ -123,6 +132,7 @@
}
}
</script>
<style lang="scss" scoped>
.el-table {
.nets-table-btn {

@ -39,6 +39,7 @@
</el-select>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" icon="el-icon-plus" size="small" type="primary" @click="add"> </el-button>
@ -48,6 +49,7 @@
<el-button v-if="canExport" icon="el-icon-download" size="small" type="info" @click="downloadExcel">
</el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table
:data="tableData"
@ -110,8 +112,11 @@
export default {
name: "purchaseInbound",
mixins: [documentTableMixin],
components: {EditDialog, SearchForm, SearchFormItem},
data() {
return {
baseUrl: '/purchase/inbound',
@ -133,6 +138,7 @@
},
}
},
methods: {
mergeSearchForm() {
return {

@ -4,6 +4,7 @@
{{title}}
<document-history :data="history" :type="type" @show="getHistory"/>
</template>
<el-form
ref="form"
:model="form"
@ -14,7 +15,7 @@
status-icon
>
<el-row :gutter="20">
<dialog-form-item label="单 号:" prop="id">
<dialog-form-item v-if="form.id" label="单 号:" prop="id">
<el-input :value="form.id" readonly/>
</dialog-form-item>
<dialog-form-item label="供应商:" prop="sname">
@ -22,19 +23,19 @@
<el-button slot="append" :disabled="!canSave" @click="supplierDialog=true">选择</el-button>
</el-input>
</dialog-form-item>
<dialog-form-item label="创建人:" prop="cname">
<dialog-form-item v-if="form.id" label="创建人:" prop="cname">
<el-input :value="form.cname" readonly/>
</dialog-form-item>
<dialog-form-item label="创建时间:" prop="ctime">
<dialog-form-item v-if="form.id" label="创建时间:" prop="ctime">
<el-date-picker :value="form.ctime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="审核人:" prop="vname">
<dialog-form-item v-if="form.status===2" label="审核人:" prop="vname">
<el-input :value="form.vname" readonly/>
</dialog-form-item>
<dialog-form-item label="审核时间:" prop="vtime">
<dialog-form-item v-if="form.status===2" label="审核时间:" prop="vtime">
<el-date-picker :value="form.vtime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="完成时间:" prop="ftime">
<dialog-form-item v-if="form.finish===2" label="完成时间:" prop="ftime">
<el-date-picker :value="form.ftime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="附 件:" full>
@ -57,12 +58,13 @@
</dialog-form-item>
</el-row>
</el-form>
<el-table ref="table" :data="form.data">
<el-table-column align="center" label="#" type="index" width="80"/>
<el-table-column align="center" label="商 品">
<template v-slot="{row}">
<category-selector
v-if="canSave"
v-if="row._editable"
v-model="row.cid"
:selected="selectedCategories"
@get-name="row.cname=$event"
@ -72,34 +74,49 @@
</el-table-column>
<el-table-column align="center" label="采购数量">
<template v-slot="{row}">
<el-input-number v-if="canSave" v-model="row.num" :min="0" size="small"/>
<el-input-number
v-if="row._editable"
v-model="row.num"
controls-position="right"
:min="0"
size="small"
/>
<span v-else>{{row.num}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="采购单价">
<template v-slot="{row}">
<el-input-number v-if="canSave" v-model="row.price" :min="0" size="small"/>
<el-input-number
v-if="row._editable"
v-model="row.price"
controls-position="right"
:min="0"
size="small"
/>
<span v-else>{{row.price}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="剩余未入库" prop="remain_num"/>
<el-table-column v-if="form.id" align="center" label="剩余未入库" prop="remain_num"/>
<el-table-column v-if="form.id" align="center" label="入库情况" width="120">
<template slot-scope="{row}">
<template v-slot="{row}">
<span :class="{success:row.remain_num===0}" class="dot"/>
{{row.remain_num===0?'已全部入库':'未全部入库'}}
</template>
</el-table-column>
<el-table-column v-if="canSave" align="center" width="80">
<el-button slot="header" icon="el-icon-plus" size="small" type="text" @click="addSub"/>
<el-button
slot-scope="d"
icon="el-icon-delete"
size="small" type="text"
@click="delSub(d.row,d.$index)"
/>
<el-table-column v-if="canSave" align="center" label="操作" width="140">
<template v-if="canSave" v-slot="{row,$index}">
<el-button v-if="!row._editable" type="text" @click="()=>row._editable=true">编辑</el-button>
<el-button v-else type="text" @click="()=>row._editable=false">保存</el-button>
<el-button type="text" @click="()=>delSub(row,$index)">删除</el-button>
</template>
</el-table-column>
<div v-if="canSave" slot="append" class="table-add-btn">
<el-button plain type="dashed" size="small" icon="el-icon-plus" @click="addSub">添加采购商品</el-button>
</div>
</el-table>
<document-steps :status="form.status" :type="type"/>
<template v-slot:footer>
<span v-if="form.status===2" class="seal">已审核</span>
<span v-if="form.finish===2" class="seal">已完成</span>
@ -162,7 +179,8 @@
cid: null,
cname: null,
num: 0,
price: 0
price: 0,
_editable: true
})
},
delSub(row, index) {
@ -184,6 +202,9 @@
index++
}
return null
},
afterInit() {
this.form.data.forEach(item => item.__editable = false)
}
}
}

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择供应商"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择客户"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"
@ -23,9 +23,11 @@
添加客户
</el-button>
</el-row>
<el-scrollbar>
<el-row class="table-container">
<liner-progress :show="config.loading"/>
<abstract-table :data="tableData" @row-click="row=$event" @row-dblclick="dbclick">
<el-table-column align="center" label="#" type="index" width="80"/>
<el-table-column align="center" label="客 户" prop="name" show-overflow-tooltip/>
@ -43,6 +45,7 @@
</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -66,9 +69,13 @@
export default {
name: "CustomerSelector",
mixins: [dialogMixin, tableMixin],
components: {LinerProgress},
props: {value: Boolean},
data() {
return {
searchForm: {
@ -76,11 +83,13 @@
}
}
},
computed: {
canGoToSysCustomerPage() {
return auth('/system/customer')
}
},
methods: {
search() {
if (!this.value || this.config.loading) return
@ -93,18 +102,22 @@
})
.finally(() => this.config.loading = false)
},
dbclick(row) {
this.row = row
this.confirm()
},
confirm() {
if (!this.row) return elError('请选择一个客户')
this.$emit('select', this.row)
},
cancel() {
this.closeDialog()
this.tableData = []
},
goToSysCustomerPage() {
this.closeDialog()
this.$emit('jump')

@ -4,6 +4,7 @@
{{title}}
<document-history :data="history" :type="type" @show="getHistory"/>
</template>
<el-form
ref="form"
:model="form"
@ -14,7 +15,7 @@
status-icon
>
<el-row :gutter="20">
<dialog-form-item label="单 号:" prop="id">
<dialog-form-item v-if="form.id" label="单 号:" prop="id">
<el-input :value="form.id" readonly/>
</dialog-form-item>
<dialog-form-item label="客 户:" prop="customer_name">
@ -22,19 +23,19 @@
<el-button slot="append" :disabled="!canSave" @click="customerDialog=true">选择</el-button>
</el-input>
</dialog-form-item>
<dialog-form-item label="创建人:" prop="cname">
<dialog-form-item v-if="form.id" label="创建人:" prop="cname">
<el-input :value="form.cname" readonly/>
</dialog-form-item>
<dialog-form-item label="创建时间:" prop="ctime">
<dialog-form-item v-if="form.id" label="创建时间:" prop="ctime">
<el-date-picker :value="form.ctime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="审核人:" prop="vname">
<dialog-form-item v-if="form.status===2" label="审核人:" prop="vname">
<el-input :value="form.vname" readonly/>
</dialog-form-item>
<dialog-form-item label="审核时间:" prop="vtime">
<dialog-form-item v-if="form.status===2" label="审核时间:" prop="vtime">
<el-date-picker :value="form.vtime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="完成时间:" prop="ftime">
<dialog-form-item v-if="form.finish===2" label="完成时间:" prop="ftime">
<el-date-picker :value="form.ftime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="附 件:" full>
@ -57,36 +58,56 @@
</dialog-form-item>
</el-row>
</el-form>
<el-table ref="table" :data="form.data">
<el-table-column align="center" label="#" type="index" width="80"/>
<el-table-column align="center">
<template slot="header">
商品
<el-button v-if="canSave" size="small" type="text" icon="el-icon-plus" @click="stockDialog=true"/>
</template>
<template v-slot="{row}">{{row.cname}}</template>
</el-table-column>
<el-table-column align="center" label="商品" prop="cname"/>
<el-table-column align="center" label="销售数量">
<template v-slot="{row}">
<el-input-number v-if="canSave" v-model="row.num" :min="0" size="small"/>
<el-input-number
v-if="canSave"
v-model="row.num"
controls-position="right"
:min="0"
size="small"
/>
<span v-else>{{row.num}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="销售单价">
<template v-slot="{row}">
<el-input-number v-if="canSave" v-model="row.price" :min="0" size="small"/>
<el-input-number
v-if="canSave"
v-model="row.price"
controls-position="right"
:min="0"
size="small"
/>
<span v-else>{{row.price}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="剩余未出库" prop="remain_num"/>
<el-table-column v-if="form.id" align="center" label="出库情况" width="120">
<template slot-scope="{row}">
<template v-slot="{row}">
<span :class="{success:row.remain_num===0}" class="dot"/>
{{row.remain_num===0?'已全部出库':'未全部出库'}}
</template>
</el-table-column>
<div v-if="canSave" slot="append" class="table-add-btn">
<el-button
plain
type="dashed"
size="small"
icon="el-icon-plus"
@click="stockDialog=true"
>
添加销售商品
</el-button>
</div>
</el-table>
<document-steps :status="form.status" :type="type"/>
<template v-slot:footer>
<span v-if="form.status===2" class="seal">已审核</span>
<span v-if="form.finish===2" class="seal">已完成</span>
@ -99,6 +120,7 @@
</template>
<stock-selector v-model="stockDialog" @select="selectStock"/>
<customer-selector v-model="customerDialog" @select="selectCustomer" @jump="closeDialog"/>
</dialog-form>
</template>
@ -114,8 +136,11 @@
export default {
name: "EditDialog",
mixins: [bizDocumentDialogMixin],
components: {StockSelector, CustomerSelector},
data() {
return {
documentName: '销售订单',
@ -136,21 +161,25 @@
stockDialog: false
}
},
computed: {
selectedCategories() {
return this.form.data.map(i => i.cid)
}
},
methods: {
selectCustomer(row) {
this.form.customer_id = row.id
this.form.customer_name = row.name
this.customerDialog = false
},
selectStock(stocks) {
this.form.data = stocks.map(i => ({cid: i.cid, cname: i.cname, num: i.total_num, price: 0}))
this.stockDialog = false
},
addSub() {
this.form.data.push({
cid: null,
@ -160,9 +189,11 @@
remain_num: 0
})
},
delSub(row, index) {
this.form.data.splice(index, 1)
},
validate() {
if (this.form.data.length <= 0) return '销售商品不能为空'
if (this.type === 'edit' && isEmpty(this.form.id)) {

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择库存商品"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"
@ -15,8 +15,10 @@
<el-button size="small" type="primary" @click="confirm"> </el-button>
<el-button plain size="small" @click="closeDialog"> </el-button>
</el-row>
<el-row class="table-container">
<liner-progress :show="config.loading"/>
<el-table
ref="table"
:data="tableData"
@ -28,6 +30,7 @@
<el-table-column align="center" label="商品分类" prop="cname" show-overflow-tooltip/>
<el-table-column align="center" label="库存数量" prop="total_num" show-overflow-tooltip/>
</el-table>
<el-pagination
background
:current-page="searchForm.page"
@ -50,14 +53,19 @@
export default {
name: "StockSelector",
mixins: [dialogMixin, tableMixin],
components: {LinerProgress},
props: {value: Boolean},
data() {
return {
selection: []
}
},
methods: {
search() {
if (!this.value || this.config.loading) return
@ -70,10 +78,12 @@
})
.finally(() => this.config.loading = false)
},
confirm() {
if (this.selection.length <= 0) return elError('请选择商品')
this.$emit('select', this.selection)
},
cancel() {
this.closeDialog()
this.$refs.table.clearSelection()

@ -55,15 +55,24 @@
/>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" icon="el-icon-plus" size="small" type="primary" @click="add"> </el-button>
<el-button icon="el-icon-view" size="small" type="primary" @click="see"> </el-button>
<el-button v-if="canUpdate" icon="el-icon-edit" size="small" type="primary" @click="edit"> </el-button>
<el-button v-if="canDel" icon="el-icon-delete" size="small" type="danger" @click="del"> </el-button>
<el-button v-if="canExport" icon="el-icon-download" size="small" type="info" @click="downloadExcel">
<el-button
v-if="canExport"
icon="el-icon-download"
size="small"
type="info"
@click="downloadExcel"
>
</el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @row-click="row=$event" @expand-change="getSubList">
<el-table-column align="center" type="expand">
@ -105,6 +114,7 @@
<template v-slot="{row}">{{row.ftime | timestamp2Date}}</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -134,8 +144,11 @@
export default {
name: "sellOrder",
mixins: [documentTableMixin],
components: {EditDialog, SearchForm, SearchFormItem},
data() {
return {
baseUrl: '/sell/order',
@ -163,6 +176,7 @@
}
}
},
methods: {
mergeSearchForm() {
return {

@ -4,6 +4,7 @@
{{title}}
<document-history :data="history" :type="type" @show="getHistory"/>
</template>
<el-form
ref="form"
:model="form"
@ -14,7 +15,7 @@
status-icon
>
<el-row :gutter="20">
<dialog-form-item label="单 号:" prop="id">
<dialog-form-item v-if="form.id" label="单 号:" prop="id">
<el-input :value="form.id" readonly/>
</dialog-form-item>
<dialog-form-item label="销售订单:" prop="pid">
@ -22,16 +23,16 @@
<el-button slot="append" :disabled="!canSave" @click="parentDialog=true">选择</el-button>
</el-input>
</dialog-form-item>
<dialog-form-item label="创建人:" prop="cname">
<dialog-form-item v-if="form.id" label="创建人:" prop="cname">
<el-input :value="form.cname" readonly/>
</dialog-form-item>
<dialog-form-item label="创建时间:" prop="ctime">
<dialog-form-item v-if="form.id" label="创建时间:" prop="ctime">
<el-date-picker :value="form.ctime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="审核人:" prop="vname">
<dialog-form-item v-if="form.status===2" label="审核人:" prop="vname">
<el-input :value="form.vname" readonly/>
</dialog-form-item>
<dialog-form-item label="审核时间:" prop="vtime">
<dialog-form-item v-if="form.status===2" label="审核时间:" prop="vtime">
<el-date-picker :value="form.vtime" format="yyyy-MM-dd HH:mm:ss" readonly type="date"/>
</dialog-form-item>
<dialog-form-item label="附 件:" full>
@ -54,6 +55,7 @@
</dialog-form-item>
</el-row>
</el-form>
<el-table :data="displayTableData">
<el-table-column align="center" type="expand">
<el-table slot-scope="{row}" :data="row.data" border show-summary :summary-method="summaryStock(row)">
@ -63,10 +65,11 @@
出库数量
<el-button v-if="canSave" type="text" size="small" @click="openStock(row)">选择库存</el-button>
</template>
<template slot-scope="d">
<template v-slot="d">
<el-input-number
v-if="canSave"
v-model="d.row.num"
controls-position="right"
:min="0"
size="small"
@change="(nv,ov)=>changeOutboundNum(nv,ov,d.row,row)"
@ -83,9 +86,9 @@
<el-table-column align="center" label="出库数量" prop="num" width="150"/>
<el-table-column align="center" label="订单剩余未出库数量" prop="remain_num" width="250"/>
</el-table>
<document-steps :status="form.status" :type="type"/>
<order-selector v-model="parentDialog" @select="selectParent"/>
<stock-selector v-model="stockDialog" :cid="row?row.cid:null" @select="selectStock"/>
<template v-slot:footer>
<span v-if="form.status===2" class="seal">已审核</span>
<el-button plain size="small" @click="closeDialog"> </el-button>
@ -95,6 +98,10 @@
<el-button v-if="canPass" size="small" type="success" @click="pass"> </el-button>
<el-button v-if="canReject" size="small" type="danger" @click="reject"> </el-button>
</template>
<order-selector v-model="parentDialog" @select="selectParent"/>
<stock-selector v-model="stockDialog" :cid="row?row.cid:null" @select="selectStock"/>
</dialog-form>
</template>
@ -112,8 +119,11 @@
export default {
name: "EditDialog",
mixins: [bizDocumentDialogMixin],
components: {OrderSelector, StockSelector},
data() {
return {
documentName: '销售出库单',
@ -132,6 +142,7 @@
displayTableData: []
}
},
methods: {
afterInit() {
if (this.type === 'add') return
@ -142,6 +153,7 @@
])
.then(([r1, r2]) => this.buildDisplayTableData(r1, r2))
},
//
buildDisplayTableData(orderSubList, stockList) {
this.displayTableData = []
@ -170,14 +182,17 @@
})
}
},
selectParent(id, sub) {
this.form.pid = id
this.displayTableData = sub.map(i => ({...i, num: 0, data: []}))
},
openStock(row) {
this.row = row
this.stockDialog = true
},
selectStock(stocks) {
let res = []
let outboundNum = 0
@ -199,6 +214,7 @@
this.row.data = res
this.stockDialog = false
},
summaryStock(row) {
return ({data}) => {
let sum = ['合计', 0, '', '']
@ -209,6 +225,7 @@
return sum
}
},
changeOutboundNum(nv, ov, row, displayTableRow) {
if (nv > row.max_num) {
return elAlert(`${row.cname}的出库数量超出库存数量`, () => row.num = ov)
@ -226,6 +243,7 @@
return elAlert(`${displayTableRow.cname}的出库数量超出销售数量`, () => row.num = ov)
}
},
validate() {
if (this.type === 'edit' && isEmpty(this.form.id)) {
return '属性缺失,请关闭弹窗刷新重试'

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择销售订单"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"
@ -14,6 +14,7 @@
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button plain size="small" @click="closeDialog"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @expand-change="getSubList">
<el-table-column align="center" type="expand">
@ -73,9 +74,13 @@
export default {
name: "OrderSelector",
mixins: [dialogMixin, tableMixin],
components: {LinerProgress},
props: {value: Boolean},
data() {
return {
searchForm: {
@ -84,6 +89,7 @@
}
}
},
methods: {
search() {
if (!this.value || this.config.loading) return
@ -101,6 +107,7 @@
})
.finally(() => this.config.loading = false)
},
getSubList(row) {
if (row._loaded || row._loading) return
row._loading = true
@ -111,11 +118,13 @@
})
.finally(() => row._loading = false)
},
confirm(row) {
if (row._selection.length <= 0) return elError('请选择要出库的商品')
this.$emit('select', row.id, row._selection)
this.cancel()
},
cancel() {
this.closeDialog()
this.tableData = []
@ -123,6 +132,7 @@
}
}
</script>
<style lang="scss" scoped>
.el-table {
.nets-table-btn {

@ -4,7 +4,7 @@
:visible="value"
append-to-body
title="选择库存商品"
width="50%"
width="70%"
top="50px"
@close="cancel"
@open="search"
@ -15,8 +15,10 @@
<el-button size="small" type="primary" @click="confirm"> </el-button>
<el-button plain size="small" @click="closeDialog"> </el-button>
</el-row>
<el-row class="table-container">
<liner-progress :show="loading"/>
<el-table
ref="table"
:data="tableData"
@ -43,13 +45,17 @@
export default {
name: "StockSelector",
mixins: [dialogMixin],
components: {LinerProgress},
props: {
value: Boolean,
cid: Number,
row: Object
},
data() {
return {
loading: false,
@ -57,6 +63,7 @@
selection: []
}
},
methods: {
search() {
if (!this.value || this.loading) return
@ -66,10 +73,12 @@
.then(data => this.tableData = data)
.finally(() => this.loading = false)
},
confirm() {
if (this.selection.length <= 0) return elError('请选择商品')
this.$emit('select', this.selection)
},
cancel() {
this.closeDialog()
this.$refs.table.clearSelection()

@ -39,15 +39,24 @@
</el-select>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" icon="el-icon-plus" size="small" type="primary" @click="add"> </el-button>
<el-button icon="el-icon-view" size="small" type="primary" @click="see"> </el-button>
<el-button v-if="canUpdate" icon="el-icon-edit" size="small" type="primary" @click="edit"> </el-button>
<el-button v-if="canDel" icon="el-icon-delete" size="small" type="danger" @click="del"> </el-button>
<el-button v-if="canExport" icon="el-icon-download" size="small" type="info" @click="downloadExcel">
<el-button
v-if="canExport"
icon="el-icon-download"
size="small"
type="info"
@click="downloadExcel"
>
</el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @row-click="row=$event" @expand-change="getSubList">
<el-table-column align="center" type="expand">
@ -77,6 +86,7 @@
</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -106,8 +116,11 @@
export default {
name: "sellOutbound",
mixins: [documentTableMixin],
components: {EditDialog, SearchForm, SearchFormItem},
data() {
return {
baseUrl: '/sell/outbound',
@ -129,6 +142,7 @@
}
}
},
methods: {
mergeSearchForm() {
return {

@ -1,6 +1,7 @@
<template>
<dialog-form :value="value" :loading="false" :title="title" width="70%" @close="cancel" @open="search">
<liner-progress :show="loading"/>
<abstract-table :data="tableData" border show-summary :summary-method="summary" :span-method="span">
<el-table-column align="center" label="采购订单" show-overflow-tooltip>
<router-link
@ -41,15 +42,20 @@
export default {
name: "DetailDialog",
mixins: [dialogMixin],
components: {AbstractTable, LinerProgress, DialogForm},
props: {value: Boolean, title: String, cid: Number},
data() {
return {
loading: false,
tableData: []
}
},
methods: {
summary({data}) {
let sum = ['合计', '', '', '', 0, 0]
@ -59,11 +65,13 @@
})
return sum
},
span({row, column, rowIndex, columnIndex}) {
if (columnIndex === 0 || columnIndex === 1) {
return row._span
}
},
search() {
this.tableData = []
if (!this.value || isEmpty(this.cid) || this.loading) return
@ -75,6 +83,7 @@
})
.finally(() => this.loading = false)
},
prepareData(data) {
data.sort((a, b) => {
if (a.cgddid > b.cgddid) return -1
@ -98,6 +107,7 @@
}
}
},
cancel() {
this.closeDialog()
this.tableData = []
@ -105,6 +115,7 @@
}
}
</script>
<style lang="scss" scoped>
.el-table {
a {

@ -33,10 +33,12 @@
/>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button icon="el-icon-download" size="small" type="info" @click="downloadExcel"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" show-summary :summary-method="summary">
<el-table-column align="center" label="#" type="index" width="80"/>
@ -49,6 +51,7 @@
</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -80,8 +83,11 @@
export default {
name: "currentStock",
mixins: [tableMixin],
components: {SearchForm, SearchFormItem, CategoryTree, DetailDialog},
data() {
return {
searchForm: {
@ -113,14 +119,17 @@
}
}
},
computed: {
title() {
return this.row ? `库存详细(${this.row.cname})` : ''
},
cid() {
return this.row ? this.row.cid : null
}
},
methods: {
summary({data}) {
let sum = ['合计', '', '', 0]
@ -129,13 +138,16 @@
})
return sum
},
filterNode(value, data) {
if (isEmpty(value)) return true
return data.name.includes(value)
},
filter(v) {
this.$refs.tree.$refs.tree.filter(v)
},
mergeSearchForm() {
return {
...this.searchForm,
@ -143,6 +155,7 @@
endTime: this.temp.ctime ? this.temp.ctime[1] + 86400000 : null
}
},
search() {
if (this.config.loading) return
this.config.loading = true
@ -153,26 +166,31 @@
})
.finally(() => this.config.loading = false)
},
downloadExcel() {
exportExcel(baseUrl + '/export', this.mergeSearchForm(), this.excel)
},
nodeClick(obj) {
const ids = getNodeId(obj.children)
ids.unshift(obj.id)
this.searchForm.cids = ids.join(',')
this.temp.cname = obj.name
},
clearCidSearch() {
this.searchForm.cids = null
this.temp.cname = null
let tree = this.$refs.tree.$refs.tree
tree.setCurrentKey()
},
more(row) {
this.row = row
this.detailDialog = true
}
},
created() {
this.filter = debounce(this.filter, 500)
}

@ -43,6 +43,7 @@
export default {
props: ['list'],
data() {
let typeValidate = (r, v, c) => {
if (v === 1 && this.hasChildren) c('该分类下已有子节点')
@ -69,10 +70,12 @@
}
}
},
computed: {
show() {
return this.list() && (this.type === 'add' || ['see', 'edit'].includes(this.type) && this.list().currentCategory)
},
confirmMessage() {
switch (this.type) {
case 'add':
@ -84,6 +87,7 @@
}
}
},
methods: {
add(parent) {
this.title = '添加新分类'
@ -94,12 +98,14 @@
this.form.type = 0
this.hasChildren = false
},
see(current, parent) {
this.title = `分类信息(${current.name})`
this.parentObj = parent
this.type = 'see'
mergeObj(this.form, current)
},
edit(current, parent) {
this.title = `编辑分类(${current.name})`
this.parentObj = parent
@ -107,6 +113,7 @@
mergeObj(this.form, current)
this.hasChildren = current.children.length > 0
},
confirm() {
this.$refs.form.validate(v => {
if (!v) return
@ -118,11 +125,13 @@
})
})
},
cancel() {
this.type = 'none'
this.clearForm()
this.$nextTick(() => this.$refs.form.clearValidate())
},
clearForm() {
this.form.id = null
this.form.pid = 0
@ -132,6 +141,7 @@
this.hasChildren = false
}
},
mounted() {
waitUntilSuccess(
() => !isEmpty(this.list()),
@ -140,6 +150,7 @@
}
}
</script>
<style lang="scss" scoped>
.edit-form {
width: 85%;

@ -22,7 +22,9 @@
export default {
components: {ContextMenuItem, ContextMenu, CategoryTree},
props: ['form'],
data() {
return {
loading: false,
@ -35,12 +37,14 @@
}
}
},
computed: {
canAdd() {
return !this.currentCategory
|| this.currentCategory.type === 0 && this.currentCategory.level < this.maxLevel
}
},
methods: {
get() {
this.loading = true
@ -50,16 +54,20 @@
.then(data => this.$store.commit('dataCache/categories', data))
.finally(() => this.loading = false)
},
add() {
this.$emit('add', this.currentCategory)
},
see(obj, node) {
this.currentCategory = {...obj, level: node.level}
this.$emit('see', this.currentCategory, node.parent ? node.parent.data : null)
},
edit() {
this.$emit('edit', this.currentCategory, this.currentCategory.parent)
},
del() {
if (isEmpty(this.currentCategory)) return elError('请选择要删除的分类')
if (this.currentCategory.children.length > 0) {
@ -73,10 +81,12 @@
})
.then(() => this.commitSuccess('删除成功'))
},
commitSuccess(msg) {
elSuccess(msg)
this.get()
},
openContextMenu(e, obj, node) {
e.preventDefault()
this.currentCategory = obj ? {
@ -91,6 +101,7 @@
this.contextmenu.show = true
}
},
mounted() {
this.$el.querySelector(".el-card__body").addEventListener('contextmenu', this.openContextMenu)
waitUntilSuccess(
@ -98,11 +109,13 @@
() => this.form().$on('commit-success', this.commitSuccess)
)
},
beforeDestroy() {
this.$el.querySelector(".el-card__body").removeEventListener('contextmenu', this.openContextMenu)
}
}
</script>
<style scoped>
.card-container {
min-width: 250px;

@ -17,6 +17,7 @@
export default {
name: "categorySetting",
components: {CategoryList, EditForm}
}
</script>

@ -45,6 +45,7 @@
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button v-if="canEdit" size="small" type="primary" @click="confirm"> </el-button>
@ -62,8 +63,11 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm, RegionSelector},
props: {
value: {type: Boolean, default: false},
type: {type: String, default: 'see'},
@ -72,6 +76,7 @@
default: () => ({})
},
},
data() {
return {
loading: false,
@ -96,6 +101,7 @@
}
}
},
computed: {
title() {
if (isEmpty(this.type)) return ''
@ -108,6 +114,7 @@
return '编辑客户'
}
},
confirmMessage() {
switch (this.type) {
case 'add':
@ -118,31 +125,38 @@
return ''
}
},
canEdit() {
return ['add', 'edit'].includes(this.type)
}
},
methods: {
clearRegion() {
this.form.region = null
this.form.region_name = null
},
selectRegion(obj) {
this.form.region = obj.id
this.form.region_name = obj.fullname
},
open() {
if (this.type !== 'add') mergeObj(this.form, this.data)
},
clearForm() {
resetObj(this.form)
this.form.status = 1
this.$nextTick(() => this.$refs.form.clearValidate())
},
cancel() {
this.closeDialog()
this.clearForm()
},
confirm() {
if (this.loading) return
this.$refs.form.validate(v => {

@ -39,12 +39,14 @@
/>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" size="small" type="primary" @click="add"> </el-button>
<el-button v-if="canUpdate" size="small" type="primary" @click="edit"> </el-button>
<el-button v-if="canDel" size="small" type="danger" @click="del"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @row-click="row=$event">
<el-table-column align="center" label="#" type="index" width="80"/>
@ -72,6 +74,7 @@
@current-change="pageChange"
/>
</el-row>
<edit-dialog v-model="editDialog" :data="row" :type="type" @success="success"/>
</el-card>
</template>
@ -91,8 +94,11 @@
export default {
name: "customerManagement",
mixins: [tableMixin],
components: {SearchForm, SearchFormItem, EditDialog, RegionSelector},
data() {
return {
searchForm: {
@ -110,29 +116,36 @@
editDialog: false
}
},
computed: {
canAdd() {
return auth(baseUrl + '/add')
},
canUpdate() {
return auth(baseUrl + '/update')
},
canDel() {
return auth(baseUrl + '/del')
}
},
methods: {
getLimitRegion() {
return getLimitRegion()
},
clearSidSearch() {
this.searchForm.region = null
this.temp.region_name = null
},
selectRegion(obj, ids) {
this.searchForm.region = ids.join(',')
this.temp.region_name = obj.fullname
},
mergeSearchForm() {
return {
...this.searchForm,
@ -140,6 +153,7 @@
endTime: this.temp.ctime ? this.temp.ctime[1] + 86400000 : null
}
},
search() {
if (this.config.loading) return
this.config.loading = true
@ -152,15 +166,18 @@
})
.finally(() => this.config.loading = false)
},
add() {
this.type = 'add'
this.editDialog = true
},
edit() {
if (isEmpty(this.row)) return elError('请选择要编辑的客户')
this.type = 'edit'
this.editDialog = true
},
del() {
if (isEmpty(this.row)) return elError('请选择要删除的客户')
if (this.config.operating) return
@ -172,6 +189,7 @@
.then(() => this.success('删除成功'))
.finally(() => this.config.operating = false)
},
success(msg) {
elSuccess(msg)
this.editDialog = false

@ -21,6 +21,7 @@
</el-radio-group>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button size="small" type="primary" @click="confirm"> </el-button>
@ -37,13 +38,17 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm},
props: {
value: {type: Boolean, default: false},
type: {type: String, default: 'add'},
data: {type: Object, default: () => ({})},
},
data() {
return {
loading: false,
@ -59,6 +64,7 @@
}
}
},
computed: {
title() {
if (!this.data || isEmpty(this.type)) return ''
@ -69,6 +75,7 @@
return `编辑部门【${this.data.name}`
}
},
confirmMessage() {
if (!this.data || isEmpty(this.type)) return ''
switch (this.type) {
@ -80,12 +87,14 @@
return ''
}
},
parentName() {
if (!this.data) return ''
if (this.type === 'add') return this.data.fullname
else return this.data.parentName
}
},
methods: {
open() {
this.$nextTick(() => {
@ -97,6 +106,7 @@
else this.form.pid = this.data.id
})
},
clearForm() {
this.form.id = null
this.form.pid = null
@ -104,10 +114,12 @@
this.form.status = 1
this.$nextTick(() => this.$refs.form.clearValidate())
},
cancel() {
this.closeDialog()
this.clearForm()
},
confirm() {
if (this.loading) return
this.$refs.form.validate(v => {

@ -18,13 +18,16 @@
export default {
name: "OrgTreeView",
components: {OrgTree},
props: {
data: {type: Object, default: () => ({})},
horizontal: Boolean,
collapsable: Boolean,
zoom: {type: Number, default: 1},
},
data() {
return {
orgTreeOffsetLeft: 0,
@ -37,6 +40,7 @@
expandAll: true
}
},
computed: {
orgTreeStyle() {
return {
@ -46,6 +50,7 @@
}
}
},
methods: {
mousedownView(event) {
this.canMove = true
@ -56,12 +61,14 @@
document.addEventListener('mousemove', this.mousemoveView)
document.addEventListener('mouseup', this.mouseupView)
},
mousemoveView(event) {
if (!this.canMove) return
const {pageX, pageY} = event
this.orgTreeOffsetLeft = this.oldMarginLeft + pageX - this.initPageX
this.orgTreeOffsetTop = this.oldMarginTop + pageY - this.initPageY
},
mouseupView() {
this.canMove = false
document.removeEventListener('mousemove', this.mousemoveView)

@ -5,6 +5,7 @@
组织结构树演示详情见iview-admin
</a>
</div>
<div class="department-outer">
<div class="view-box">
<org-tree-view
@ -16,11 +17,13 @@
@wheel.native.prevent="wheel"
/>
</div>
<div class="tooltip-box">
<el-radio-group v-model="horizontal" fill="#909399" size="small" style="margin-right: 20px">
<el-radio-button :label="true"> </el-radio-button>
<el-radio-button :label="false"> </el-radio-button>
</el-radio-group>
<el-button
circle
icon="el-icon-refresh"
@ -30,9 +33,11 @@
type="info"
@click="search"
/>
<zoom-control v-model="zoom" :max="200" :min="20"/>
</div>
</div>
<context-menu
v-if="canAdd||canUpdate||canDel"
v-model="contextmenu.show"
@ -43,6 +48,7 @@
<context-menu-item v-show="canUpdate" @click="update">编辑部门</context-menu-item>
<context-menu-item v-show="canDel" @click="del">删除部门</context-menu-item>
</context-menu>
<edit-dialog v-model="editDialog" :data="currentNode" :type="type" @success="search"/>
</el-card>
</template>
@ -63,7 +69,9 @@
export default {
name: "departmentManagement",
components: {OrgTreeView, ZoomControl, ContextMenu, ContextMenuItem, EditDialog},
data() {
return {
loading: false,
@ -80,20 +88,25 @@
}
}
},
computed: {
realZoom() {
return this.zoom / 100
},
canAdd() {
return auth(baseUrl + '/add')
},
canUpdate() {
return auth(baseUrl + '/update')
},
canDel() {
return auth(baseUrl + '/del')
},
},
methods: {
openMenu(e, obj) {
e.preventDefault()
@ -103,6 +116,7 @@
this.contextmenu.top = e.clientY - top
this.contextmenu.show = true
},
wheel(e) {
const eventDelta = e.wheelDelta || -(e.detail || 0)
const zoom = this.zoom + eventDelta / 12 * 2
@ -115,10 +129,12 @@
this.type = 'add'
this.editDialog = true
},
update() {
this.type = 'edit'
this.editDialog = true
},
del() {
if (this.loading || !this.currentNode) return
if (this.currentNode.id === 1) return elError('根节点不能删除')
@ -149,6 +165,7 @@
.finally(() => this.loading = false)
}
},
mounted() {
this.search()
}

@ -2,6 +2,7 @@
<el-card class="chart-card">
<div slot="header">
<span><b>cpu监控</b></span>
<span class="title-span">
当前使用率
<count-to
@ -11,6 +12,7 @@
suffix="%"
/>
</span>
<span class="title-span">
峰值
<count-to
@ -21,6 +23,7 @@
/>
</span>
</div>
<div class="line-chart"/>
</el-card>
</template>
@ -31,11 +34,15 @@
export default {
name: "Cpu",
mixins: [resize, logic],
components: {CountTo},
props: {
data: Object
},
data() {
return {
options: {
@ -91,6 +98,7 @@
}
}
},
watch: {
data: {
deep: true,
@ -100,13 +108,16 @@
}
}
},
methods: {
init() {
this.chart.setOption(this.options)
},
$_getChartDom() {
return this.$el.querySelector('.line-chart')
},
setOptions({xData, vData} = {}) {
this.chart.setOption({
xAxis: {data: xData},

@ -22,6 +22,7 @@
/>
</span>
</div>
<div class="line-chart"/>
</el-card>
</template>
@ -32,11 +33,15 @@
export default {
name: "Jvm",
mixins: [resize, logic],
components: {CountTo},
props: {
data: Object
},
data() {
return {
options: {
@ -92,6 +97,7 @@
}
}
},
watch: {
data: {
deep: true,
@ -101,13 +107,16 @@
}
}
},
methods: {
init() {
this.chart.setOption(this.options)
},
$_getChartDom() {
return this.$el.querySelector('.line-chart')
},
setOptions({xData, vData} = {}) {
this.chart.setOption({
xAxis: {data: xData},

@ -22,6 +22,7 @@
/>
</span>
</div>
<div class="line-chart"/>
</el-card>
</template>
@ -32,11 +33,15 @@
export default {
name: "Memory",
mixins: [resize, logic],
components: {CountTo},
props: {
data: Object
},
data() {
return {
options: {
@ -92,6 +97,7 @@
}
}
},
watch: {
data: {
deep: true,
@ -101,13 +107,16 @@
}
}
},
methods: {
init() {
this.chart.setOption(this.options)
},
$_getChartDom() {
return this.$el.querySelector('.line-chart')
},
setOptions({xData, vData} = {}) {
this.chart.setOption({
xAxis: {data: xData},

@ -4,7 +4,9 @@
<span>启动时间{{operatingInfo.bootedTime}}</span>
<span style="margin-left: 20px">运行时间{{operatingInfo.upTime|timePass}}</span>
</div>
<cpu-info :data="cpuInfo"/>
<el-row :gutter="40" style="margin-top: 32px">
<el-col :span="12">
<memory-info :data="memoryInfo"/>
@ -26,7 +28,9 @@
export default {
name: "systemMonitor",
components: {CpuInfo, MemoryInfo, JvmInfo},
data() {
return {
loading: false,
@ -79,6 +83,7 @@
}
}
},
methods: {
getData() {
if (this.loading) return
@ -94,10 +99,12 @@
})
.finally(() => this.loading = false)
},
handleOperatingInfo(info) {
this.operatingInfo.bootedTime = timeFormat(null, new Date(info.bootedTime * 1000))
this.operatingInfo.upTime = info.upTime
},
handleCpuInfo(info) {
let used = (Number)(sub(100, info.idle).toFixed(2))
this.cpuInfo.name = info.name
@ -111,6 +118,7 @@
this.cpuInfo.xData.push(this.time)
this.cpuInfo.vData.push(used)
},
handleMemoryInfo(info) {
info.utilizationRate = (Number)(info.utilizationRate.toFixed(2))
this.memoryInfo.total = info.total
@ -125,6 +133,7 @@
this.memoryInfo.xData.push(this.time)
this.memoryInfo.vData.push(info.utilizationRate)
},
handleJvmInfo(info) {
info.utilizationRate = (Number)(info.utilizationRate.toFixed(2))
this.jvmInfo.total = info.total
@ -140,6 +149,7 @@
this.jvmInfo.vData.push(info.utilizationRate)
},
},
mounted() {
this.getData()
this.refreshTimer = setInterval(() => this.getData(), 40000)

@ -15,12 +15,25 @@
<el-input :value="form.url" readonly/>
</el-form-item>
<el-form-item label="总频率:" prop="total_rate">
<el-input-number v-model="form.total_rate" :min="1" :step="1" step-strictly size="small"/>
<el-input-number
v-model="form.total_rate"
controls-position="right"
:min="1"
:step="1"
step-strictly size="small"
/>
</el-form-item>
<el-form-item label="单个IP频率:" prop="ip_rate">
<el-input-number v-model="form.ip_rate" :min="1" :step="1" step-strictly size="small"/>
<el-input-number
v-model="form.ip_rate"
controls-position="right"
:min="1"
:step="1"
step-strictly size="small"
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button size="small" type="primary" @click="confirm"> </el-button>
@ -36,12 +49,16 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm},
props: {
value: {type: Boolean, default: false},
data: {type: Object, default: () => ({})},
},
data() {
return {
loading: false,
@ -58,15 +75,18 @@
}
}
},
methods: {
open() {
this.$nextTick(() => mergeObj(this.form, this.data))
},
cancel() {
this.closeDialog()
resetObj(this.form)
this.$nextTick(() => this.$refs.form.clearValidate())
},
confirm() {
if (this.loading) return
this.$refs.form.validate(v => {
@ -76,7 +96,7 @@
.then(({msg}) => this.$emit('success', msg))
.finally(() => this.loading = false)
})
},
}
}
}
</script>

@ -4,6 +4,7 @@
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canUpdate" icon="el-icon-edit" size="small" type="primary" @click="edit"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table :data="tableData" @row-click="row=$event">
<el-table-column label="名称" prop="fullName" show-overflow-tooltip/>
@ -31,18 +32,23 @@
export default {
name: "resourceManagement",
mixins: [tableMixin],
components: {SearchForm, SearchFormItem, EditDialog},
data() {
return {
editDialog: false
}
},
computed: {
canUpdate() {
return auth(baseUrl + '/update')
}
},
methods: {
search() {
if (this.config.loading) return
@ -53,10 +59,12 @@
.then(data => this.tableData = data)
.finally(() => this.config.loading = false)
},
edit() {
if (!this.row) return elError('请选择要编辑的资源')
this.editDialog = true
},
success(msg) {
elSuccess(msg)
this.editDialog = false

@ -28,6 +28,7 @@
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-dropdown placement="top" style="float: left" @command="treeCommand">
<el-button plain size="small">
@ -55,13 +56,17 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm},
props: {
value: {type: Boolean, default: false},
type: {type: String, default: 'add'},
data: {type: Object, default: () => ({})},
},
data() {
return {
loading: false,
@ -77,6 +82,7 @@
}
}
},
computed: {
title() {
if (isEmpty(this.type)) return ''
@ -87,6 +93,7 @@
return '编辑角色'
}
},
confirmMessage() {
switch (this.type) {
case 'add':
@ -97,14 +104,17 @@
return ''
}
},
resource() {
return this.$store.state.resource.tree
}
},
methods: {
treeCommand({action, level}) {
elTreeControl(this.$refs.tree, action, level)
},
open() {
this.$nextTick(() => {
if (this.type === 'edit') {
@ -113,6 +123,7 @@
}
})
},
clearForm() {
this.form.id = null
this.form.name = null
@ -121,10 +132,12 @@
this.$refs.tree.setCheckedKeys([])
this.$nextTick(() => this.$refs.form.clearValidate())
},
cancel() {
this.closeDialog()
this.clearForm()
},
confirm() {
if (this.loading) return
this.$refs.form.validate(v => {

@ -3,11 +3,14 @@
export default {
name: "RoleResource",
functional: true,
props: {
ids: {type: Array, default: () => []},
map: {type: Object, default: () => ({})}
},
render(h, context) {
const {ids, map} = context.props
let tree = []

@ -23,12 +23,14 @@
/>
</search-form-item>
</search-form>
<el-row class="button-group">
<el-button icon="el-icon-search" size="small" type="success" @click="search"> </el-button>
<el-button v-if="canAdd" icon="el-icon-plus" size="small" type="primary" @click="add"> </el-button>
<el-button v-if="canUpdate" icon="el-icon-edit" size="small" type="primary" @click="edit"> </el-button>
<el-button v-if="canDel" icon="el-icon-delete" size="small" type="danger" @click="del"> </el-button>
</el-row>
<el-row v-loading="config.loading" class="table-container">
<abstract-table
:data="tableData"
@ -50,6 +52,7 @@
</template>
</el-table-column>
</abstract-table>
<el-pagination
background
:current-page="searchForm.page"
@ -79,8 +82,11 @@
export default {
name: "roleManagement",
mixins: [tableMixin],
components: {SearchForm, SearchFormItem, EditDialog, RoleResource},
data() {
return {
searchForm: {
@ -94,16 +100,20 @@
editDialog: false
}
},
computed: {
canAdd() {
return auth(baseUrl + '/add')
},
canUpdate() {
return auth(baseUrl + '/update')
},
canDel() {
return auth(baseUrl + '/del')
},
resourceMap() {
const resource = this.$store.state.resource
if (resource.data.length <= 0) return {}
@ -113,6 +123,7 @@
}, {})
}
},
methods: {
mergeSearchForm() {
return {
@ -121,6 +132,7 @@
endTime: this.temp.ctime ? this.temp.ctime[1] + 86400000 : null,
}
},
search() {
if (this.config.loading) return
this.config.loading = true
@ -136,16 +148,19 @@
})
.finally(() => this.config.loading = false)
},
add() {
this.row = null
this.type = 'add'
this.editDialog = true
},
edit() {
if (!this.row) return elError('请选择要编辑的角色')
this.type = 'edit'
this.editDialog = true
},
del() {
if (!this.row) return elError('请选择要删除的角色')
if (this.row.status === 1) return elError('不能删除已启用的角色')
@ -161,6 +176,7 @@
})
.finally(() => this.config.operating = false)
},
success(msg) {
elSuccess(msg)
this.editDialog = false

@ -45,6 +45,7 @@
/>
</el-form-item>
</el-form>
<template v-slot:footer>
<el-button plain size="small" @click="closeDialog"> </el-button>
<el-button v-if="canEdit" size="small" type="primary" @click="confirm"> </el-button>
@ -62,8 +63,11 @@
export default {
name: "EditDialog",
mixins: [dialogMixin],
components: {DialogForm, RegionSelector},
props: {
value: {type: Boolean, default: false},
type: {type: String, default: 'see'},
@ -72,6 +76,7 @@
default: () => ({})
},
},
data() {
return {
loading: false,
@ -96,6 +101,7 @@
}
}
},
computed: {
title() {
if (isEmpty(this.type)) return ''
@ -108,6 +114,7 @@
return '编辑供应商'
}
},
confirmMessage() {
switch (this.type) {
case 'add':
@ -118,31 +125,38 @@
return ''
}
},
canEdit() {
return ['add', 'edit'].includes(this.type)
}
},
methods: {
clearRegion() {
this.form.region = null
this.form.region_name = null
},
selectRegion(obj) {
this.form.region = obj.id
this.form.region_name = obj.fullname
},
open() {
if (this.type !== 'add') mergeObj(this.form, this.data)
},
clearForm() {
resetObj(this.form)
this.form.status = 1
this.$nextTick(() => this.$refs.form.clearValidate())
},
cancel() {
this.closeDialog()
this.clearForm()
},
confirm() {
if (this.loading) return
this.$refs.form.validate(v => {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save