Compare commits

..

No commits in common. 'main' and 'liran_branch' have entirely different histories.

@ -1,114 +0,0 @@
<template>
<div class="app-wrapper" :class="classObj">
<sidebar class="sidebar-container"></sidebar>
<div class="main-container">
<navbar></navbar>
<app-main></app-main>
</div>
</div>
</template>
<script>
import { Navbar, Sidebar, AppMain } from './components'
import ResizeMixin from './mixin/ResizeHandler'
export default {
name: 'layout',
components: {
Navbar,
Sidebar,
AppMain
},
mixins: [ResizeMixin],
computed: {
sidebar() {
return this.$store.state.app.sidebar
},
device() {
return this.$store.state.app.device
},
classObj() {
return {
hideSidebar: !this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@import "src/styles/mixin.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
}
</style>
#abc
<template>
<!-- 最外层的 `div` 元素类名为 `app-wrapper`并且通过 `:class="classObj"` 进行动态类名绑定根据 `classObj` 计算属性返回的对象来决定应用哪些类名用于实现根据不同条件动态改变样式的功能 -->
<div class="app-wrapper" :class="classObj">
<!-- 使用名为 `sidebar` 的自定义组件类名为 `sidebar-container`通常这个组件用于展示页面的侧边栏内容比如导航菜单等功能模块 -->
<sidebar class="sidebar-container"></sidebar>
<!-- 一个 `div` 元素类名为 `main-container`作为主要内容区域的容器用于包裹页面中除侧边栏之外的核心展示内容 -->
<div class="main-container">
<!-- 使用名为 `navbar` 的自定义组件用于展示页面顶部的导航栏包含诸如页面切换功能操作入口等元素 -->
<navbar></navbar>
<!-- 使用名为 `app-main` 的自定义组件用于承载页面的主体内容例如数据展示操作表单等具体业务相关的内容展示 -->
<app-main></app-main>
</div>
</div>
</template>
<script>
// `./components` `Navbar``Sidebar``AppMain`
import { Navbar, Sidebar, AppMain } from './components';
// `./mixin/ResizeHandler` `ResizeMixin``mixins` Vue.js `ResizeMixin` 使
import ResizeMixin from './mixin/ResizeHandler';
export default {
name: 'layout',
components: {
// `components` `Navbar``Sidebar``AppMain` 使 Vue.js 使
Navbar,
Sidebar,
AppMain
},
mixins: [ResizeMixin],
computed: {
sidebar() {
// `sidebar`访 Vuex `$store` `app` `sidebar` 使
return this.$store.state.app.sidebar;
},
device() {
// `device` `$store` `app` `mobile`便
return this.$store.state.app.device;
},
classObj() {
// `classObj` `hideSidebar` `!this.sidebar.opened``withoutAnimation` `this.sidebar.withoutAnimation``mobile` `this.device === 'mobile'`
return {
hideSidebar:!this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device ==='mobile'
};
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
// 使 `@import` `src/styles/mixin.scss` SCSS `mixin`便
@import "src/styles/mixin.scss";
.app-wrapper {
// 使 `clearfix` `mixin.scss` `clearfix`
@include clearfix;
// `relative`便
position: relative;
// `100%`
height: 100%;
// `100%`使
width: 100%;
}
</style>

@ -1,43 +0,0 @@
<template>
<section class="app-main">
<transition name="fade" mode="out-in">
<!-- <router-view :key="key"></router-view> -->
<router-view></router-view>
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
// key() {
// return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date()
// }
}
}
</script>
#abc
<template>
<!-- 使用 `section` 元素作为容器类名为 `app-main`通常这个元素会用于承载页面的主体内容部分在整个页面布局结构中扮演重要角色例如展示各种业务模块数据展示区域等 -->
<section class="app-main">
<!-- 使用 Vue.js `<transition>` 组件设置过渡效果的名称为 `fade`过渡模式为 `out-in`这种过渡模式意味着旧元素先执行离开过渡淡出完成后新元素再执行进入过渡淡入用于在路由视图切换时不同页面组件切换时实现平滑的过渡动画效果 -->
<transition name="fade" mode="out-in">
<!-- 原本此处使用 `:key` 绑定了一个计算属性 `key`目前代码中该计算属性被注释掉了用于给 `<router-view>` 组件添加一个唯一标识当路由变化且 `key` 值改变时会强制重新渲染 `<router-view>` 对应的组件实现更有效的组件更新和过渡效果展示现在虽然没有绑定 `key` `<router-view>` 组件依然用于渲染与当前路由匹配的组件内容也就是展示具体的页面内容部分 -->
<router-view></router-view>
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
// `key` `<router-view>` `key`
// `this.$route.name` `key` `$route.name` `key` `$route.name` `+new Date()` `key` `<router-view>` `$route.name` `$route` `key` `<transition>`
// key() {
// return this.$route.name!== undefined? this.$route.name + +new Date() : this.$route + +new Date()
// }
}
}
</script>

@ -1,235 +0,0 @@
<template>
<el-menu class="navbar" mode="horizontal">
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
<breadcrumb></breadcrumb>
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img class="user-avatar" :src="avatar">
<i class="el-icon-caret-bottom"></i>
</div>
<el-dropdown-menu class="user-dropdown" slot="dropdown">
<router-link class="inlineBlock" to="/">
<el-dropdown-item>
首页
</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span @click="logout" style="display:block;">退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-menu>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
export default {
components: {
Breadcrumb,
Hamburger
},
computed: {
...mapGetters([
'sidebar',
'avatar'
])
},
methods: {
toggleSideBar() {
this.$store.dispatch('ToggleSideBar')
},
logout() {
this.$store.dispatch('LogOut').then(() => {
location.reload() // vue-router bug
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.navbar {
height: 50px;
line-height: 50px;
border-radius: 0px !important;
.hamburger-container {
line-height: 58px;
height: 50px;
float: left;
padding: 0 10px;
}
.screenfull {
position: absolute;
right: 90px;
top: 16px;
color: red;
}
.avatar-container {
height: 50px;
display: inline-block;
position: absolute;
right: 35px;
.avatar-wrapper {
cursor: pointer;
margin-top: 5px;
position: relative;
.user-avatar {
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
</style>
#abc
<template>
<!-- 使用 Element UI `el-menu` 组件创建一个水平模式`mode="horizontal"`的导航栏类名为 `navbar`用于构建页面顶部的导航菜单结构 -->
<el-menu class="navbar" mode="horizontal">
<!-- 使用名为 `hamburger` 的自定义组件类名为 `hamburger-container`通过属性绑定传递 `toggleClick` 方法用于切换侧边栏显示状态以及 `isActive` 属性与侧边栏是否打开状态相关通常这个组件会以汉堡菜单图标形式呈现点击可展开或收起侧边栏 -->
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
<!-- 使用名为 `breadcrumb` 的自定义组件用于展示面包屑导航显示当前页面在整个页面层级结构中的位置路径信息方便用户知晓所在页面的层级关系 -->
<breadcrumb></breadcrumb>
<!-- 使用 Element UI `el-dropdown` 下拉菜单组件类名为 `avatar-container`设置触发下拉菜单的方式为点击`trigger="click"`用于创建一个包含用户头像等相关操作选项的下拉菜单 -->
<el-dropdown class="avatar-container" trigger="click">
<!-- 一个 `div` 元素类名为 `avatar-wrapper`作为用户头像及其相关元素的容器用于包裹头像图片和下拉箭头图标等 -->
<div class="avatar-wrapper">
<!-- 使用 `img` 图片元素通过 `:src` 绑定 `avatar` 变量在计算属性中通过 Vuex `getters` 获取用于显示用户头像图片资源设置类名为 `user-avatar`用于展示用户的头像 -->
<img class="user-avatar" :src="avatar">
<!-- 使用 Element UI 的图标组件 `el-icon-caret-bottom`展示一个向下的箭头图标用于提示用户该区域可点击展开下拉菜单增强视觉提示效果 -->
<i class="el-icon-caret-bottom"></i>
</div>
<!-- `el-dropdown-menu` 组件类名为 `user-dropdown`通过 `slot="dropdown"` 插槽与外层的 `el-dropdown` 组件关联用于定义下拉菜单中具体的菜单项内容 -->
<el-dropdown-menu class="user-dropdown" slot="dropdown">
<!-- 使用 `router-link` 组件创建一个路由链接类名为 `inlineBlock`链接到根路径`/`点击可导航到首页并且将 `el-dropdown-item` 作为子元素包裹在其中用于在下拉菜单中展示首页这一菜单项 -->
<router-link class="inlineBlock" to="/">
<el-dropdown-item>
首页
</el-dropdown-item>
</router-link>
<!-- `el-dropdown-item` 组件设置了 `divided` 属性可能用于添加分割线样式区分不同菜单项内部包含一个 `span` 元素点击该 `span` 元素会触发 `logout` 方法用于执行退出登录的操作在下拉菜单中展示退出这一菜单项 -->
<el-dropdown-item divided>
<span @click="logout" style="display:block;">退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-menu>
</template>
<script>
// `vuex` `mapGetters` Vuex `getters` 便 Vuex
import { mapGetters } from 'vuex';
// `@/components/` `Breadcrumb`
import Breadcrumb from '@/components/Breadcrumb';
// `@/components/` `Hamburger`
import Hamburger from '@/components/Hamburger';
export default {
components: {
// `components` `Breadcrumb` `Hamburger` 使 Vue.js 使
Breadcrumb,
Hamburger
},
computed: {
// 使 `mapGetters` Vuex `sidebar` `avatar` `getters` `this.sidebar` `this.avatar` `sidebar` `avatar`
...mapGetters([
'sidebar',
'avatar'
])
},
methods: {
toggleSideBar() {
// `toggleSideBar` `$store.dispatch` Vuex `ToggleSideBar` `action` Vuex `store`
this.$store.dispatch('ToggleSideBar')
},
logout() {
// `logout` 退 `$store.dispatch` Vuex `LogOut` `store` `LogOut` `.then` `location.reload` `vue-router` `bug`退
this.$store.dispatch('LogOut').then(() => {
location.reload(); // vue-router bug
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
// `navbar`
.navbar {
// `50px`使
height: 50px;
// `50px`使
line-height: 50px;
// `el-menu` `0px`使`!important`
border-radius: 0px!important;
// `hamburger-container`
.hamburger-container {
// `58px`使
line-height: 58px;
// `50px`
height: 50px;
// 使便
float: left;
// `0 10px`
padding: 0 10px;
}
// `screenfull` 使
.screenfull {
// `absolute`使便
position: absolute;
// `90px` 使
right: 90px;
// `16px`
top: 16px;
//
color: red;
}
// `avatar-container`
.avatar-container {
// `50px`使
height: 50px;
// `inline-block`使
display: inline-block;
// `absolute`便便
position: absolute;
// `35px` 使
right: 35px;
// `avatar-wrapper`
.avatar-wrapper {
// `cursor: pointer`
cursor: pointer;
// `5px`使
margin-top: 5px;
// `relative`便
position: relative;
// `user-avatar`
.user-avatar {
// `40px`使
width: 40px;
// `40px`
height: 40px;
// `10px`使
border-radius: 10px;
}
// `el-icon-caret-bottom`
.el-icon-caret-bottom {
// `absolute`使 `avatar-wrapper`
position: absolute;
// `-20px` 使
right: -20px;
// `25px` 使
top: 25px;
// `12px`使
font-size: 12px;
}
}
}
}
</style>

@ -1,154 +0,0 @@
<template>
<div class="menu-wrapper">
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path"
:key="item.children[0].name">
<el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}">
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{item.children[0].meta.title}}</span>
</el-menu-item>
</router-link>
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<template slot="title">
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span>
</template>
<template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
<!--支持外链功能-->
<a v-else-if="child.path.startsWith('http')" v-bind:href="child.path" target="_blank" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
</el-menu-item>
</a>
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
</el-menu-item>
</router-link>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'SidebarItem',
props: {
routes: {
type: Array
},
isNest: {
type: Boolean,
default: false
}
},
methods: {
hasOneShowingChildren(children) {
const showingChildren = children.filter(item => {
return !item.hidden
})
if (showingChildren.length === 1) {
return true
}
return false
}
}
}
</script>
#abc
<template>
<!-- 最外层的 `div` 元素类名为 `menu-wrapper`它充当整个侧边栏菜单的包裹容器起到组织和定位内部菜单元素的作用使得菜单在页面布局中有一个明确的范围和样式框架 -->
<div class="menu-wrapper">
<!-- 使用 `v-for` 指令对 `routes` 数组进行循环遍历`routes` 数组应该是从父组件传入的数据包含了侧边栏菜单各个层级的路由配置信息等内容同时结合 `v-if` 指令进行条件判断只有当当前遍历到的 `item` 元素的 `hidden` 属性为 `false`意味着该菜单项需要显示出来而非隐藏并且 `item` 具有 `children` 属性表示这个菜单项包含子菜单才会渲染内部对应的菜单结构内容以此实现根据数据动态生成侧边栏菜单的功能有选择性地展示有效的菜单项及其子菜单 -->
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<!-- 使用 `router-link` 组件创建一个路由链接这是 Vue Router 用于实现页面导航的组件通过 `v-if` 指令添加了复杂的条件判断只有当满足以下几个条件时才会渲染这个路由链接
- `hasOneShowingChildren(item.children)` 方法返回 `true`即当前菜单项`item`的子菜单数组`item.children`经过筛选后只有一个需要显示的子项`hasOneShowingChildren` 方法会在后续的 `methods` 部分详细介绍作用是筛选出未隐藏的子项并判断数量是否为 1
- `!item.children[0].children` `true`也就是当前菜单项的第一个子菜单项`item.children[0]`不存在它自己的子菜单说明是一个没有下一级嵌套的子菜单项
- `!item.alwaysShow` `true`可能表示该菜单项不是那种始终要显示特定链接形式的特殊菜单项具体含义需结合整体业务逻辑判断
`:to` 属性绑定了一个拼接后的路由路径由当前菜单项`item` `path` 属性和它第一个子菜单项`item.children[0]` `path` 属性通过 `+` 号拼接而成用于指定点击这个路由链接后要跳转到的页面路径`:key` 属性绑定了第一个子菜单项`item.children[0]` `name` 属性 Vue 的虚拟 DOM 渲染机制中`key` 可以帮助更高效准确地识别每个列表项这里的路由链接作为一种列表项便于在数据变化时进行精准的更新复用以及重新排序等操作优化渲染性能 -->
<router-link v-if="hasOneShowingChildren(item.children) &&!item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path"
:key="item.children[0].name">
<!-- 使用 Element UI `el-menu-item` 组件来表示一个菜单项它是侧边栏菜单中的具体可点击选项`:index` 属性绑定了同样是由当前菜单项`item` `path` 和其第一个子菜单项`item.children[0]` `path` 拼接而成的字符串这个 `index` 属性在菜单的选中状态管理等方面可能会起到标识作用例如确定哪个菜单项当前处于激活状态等`:class` 属性通过对象语法绑定了一个类名控制逻辑根据 `!isNest``isNest` 是从父组件传入的布尔类型属性用于判断当前菜单项是否处于嵌套菜单的情境中默认值为 `false`的值来决定是否添加 `submenu-title-noDropdown` 类名从而实现根据不同的菜单层级或状态应用不同的样式比如改变外观样式以体现是否是嵌套菜单下的标题样式等 -->
<el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}">
<!-- 使用 `svg-icon` 自定义组件从代码上下文推测应该是用于展示 SVG 格式的图标通过 `v-if` 指令进行条件判断只有当当前菜单项的第一个子菜单项`item.children[0]` `meta` 对象中存在 `icon` 属性通常 `meta` 对象用于存放菜单项的一些额外元数据比如图标标题等相关信息才会将该 `icon` 属性的值作为图标类名传递给 `svg-icon` 组件进而展示对应的图标用于增强菜单项的可视化效果让用户更直观地识别菜单项对应的功能或页面类型等 -->
<svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon>
<!-- 使用 `span` 元素来展示菜单项的标题文本内容同样通过 `v-if` 指令判断只有当当前菜单项的第一个子菜单项`item.children[0]` `meta` 对象中存在 `title` 属性时才会将该 `title` 属性的值作为文本内容渲染到 `span` 元素中显示在菜单项上明确告知用户该菜单项所代表的含义或对应的页面名称等信息通过 `slot="title"` 属性将这个 `span` 元素放置在 `el-menu-item` 组件指定的标题插槽位置确保文本正确显示在菜单项的合适位置上 -->
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{item.children[0].meta.title}}</span>
</el-menu-item>
</router-link>
<!-- 使用 Element UI `el-submenu` 组件来创建一个包含子菜单的菜单项容器通过 `v-else` 指令意味着当不满足上面 `router-link` 组件的渲染条件时即当前菜单项的子菜单情况不符合前面所描述的那种只有一个无子菜单的显示子项的情况就会渲染这个 `el-submenu` 组件用于展示更复杂的具有多个子菜单项或者嵌套子菜单的菜单结构`:index` 属性绑定了当前菜单项`item` `name` 属性或者 `path` 属性优先使用 `name`如果 `name` 不存在则使用 `path`用于在菜单体系中标识这个子菜单的唯一性便于菜单状态管理展开与折叠控制等操作能准确对应到这个子菜单上`:key` 属性绑定了当前菜单项`item` `name` 属性同样是为了在 Vue 的虚拟 DOM 渲染机制中给这个组件实例一个唯一标识方便进行高效的更新和复用操作提升渲染性能 -->
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<!-- 使用 `template` 元素并通过 `slot="title"` 属性定义了 `el-submenu` 组件的标题部分内容的插槽用于自定义子菜单标题的展示样式和内容包括图标和标题文本等信息这些内容会展示在子菜单展开按钮等位置方便用户直观地识别这个子菜单所代表的功能分类或相关页面集合等 -->
<template slot="title">
<!-- 与前面类似使用 `svg-icon` 自定义组件展示图标通过 `v-if` 指令判断当前菜单项`item` `meta` 对象中是否存在 `icon` 属性如果存在则将该 `icon` 属性的值作为图标类名传递给 `svg-icon` 组件展示对应的图标增强子菜单标题的可视化效果帮助用户快速识别该子菜单相关信息 -->
<svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
<!-- 使用 `span` 元素展示子菜单标题的文本内容通过 `v-if` 指令判断当前菜单项`item` `meta` 对象中是否存在 `title` 属性如果存在则将该 `title` 属性的值作为文本渲染到 `span` 元素中显示在子菜单标题位置明确告知用户这个子菜单所涉及的内容范围等信息通过 `slot="title"` 将这个 `span` 元素放置在 `template` 元素指定的标题插槽位置确保文本正确显示在子菜单标题的合适位置上 -->
<span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span>
</template>
<!-- 再次使用 `v-for` 指令对当前菜单项`el-submenu` 对应的 `item` `children` 数组即子菜单的各个子项进行循环遍历同时结合 `v-if` 指令进行条件判断只有当子项的 `hidden` 属性为 `false`表示该子项需要显示出来而非隐藏才会渲染内部对应的菜单相关组件用于动态生成子菜单下的具体菜单项内容实现有选择性地展示有效的子菜单项过滤掉不需要显示的子项 -->
<template v-for="child in item.children" v-if="!child.hidden">
<!-- 使用名为 `sidebar-item` 的自定义组件也就是当前正在定义的这个组件自身通过递归调用自身来处理嵌套菜单的情况通过 `:is-nest="true"` 属性传递一个布尔值表示当前处于嵌套菜单的状态因为这里是在处理子菜单中的子菜单项属于嵌套层级情况同时添加 `nest-menu` 类名从代码结构推测这个类名应该是用于应用一些特定的样式实现嵌套菜单相关的外观样式控制比如缩进字体大小调整等具体样式定义需查看对应的 CSS 代码通过 `:routes="[child]"` 属性将当前子项`child`作为一个只包含一个元素的数组传递给 `sidebar-item` 组件目的是让 `sidebar-item` 组件以这个子项为基础数据递归地处理它可能存在的子菜单情况如果 `child` 本身也有 `children` 属性即还有下一层级的子菜单的话`:key` 属性绑定当前子项`child` `path` 属性用于在 Vue 的虚拟 DOM 渲染机制中给这个 `sidebar-item` 组件实例一个唯一标识便于进行高效的更新复用以及重新排序等操作优化渲染性能实现多级嵌套菜单的递归构建和渲染功能 -->
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
<!-- 使用 `a` 元素超链接来创建一个外部链接菜单项通过 `v-else-if` 指令进行条件判断当当前子项`child` `path` 属性是以 `http` 开头时表明这是一个指向外部网页的链接就会渲染这个 `a` 元素通过 `v-bind:href` 指令将当前子项`child` `path` 属性绑定为超链接的 `href` 属性值即链接地址同时设置 `target="_blank"` 属性使得点击这个链接时会在新的浏览器标签页中打开对应的外部网页`:key` 属性绑定当前子项`child` `name` 属性用于在 Vue 的虚拟 DOM 渲染机制中给这个 `a` 元素一个唯一标识方便进行高效的更新操作确保在数据变化时能正确渲染这个外部链接菜单项 -->
<a v-else-if="child.path.startsWith('http')" v-bind:href="child.path" target="_blank" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
</el-menu-item>
</a>
<!-- 使用 `router-link` 组件创建一个内部路由链接菜单项通过 `v-else` 指令当不满足上面 `sidebar-item` `a` 元素的渲染条件时即既不是嵌套菜单情况也不是外部链接情况而是内部页面路由链接的常规情况就会渲染这个 `router-link` 组件`:to` 属性绑定了由当前菜单项`el-submenu` 对应的 `item` `path` 属性和当前子项`child` `path` 属性通过 `+` 号拼接而成的字符串作为路由路径用于指定点击这个路由链接后要跳转到的内部页面路径`:key` 属性绑定当前子项`child` `name` 属性用于在 Vue 的虚拟 DOM 渲染机制中给这个 `router-link` 组件一个唯一标识方便进行高效的更新操作确保在数据变化时能正确渲染这个内部路由链接菜单项实现内部页面之间的导航功能 -->
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path">
<svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
<span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
</el-menu-item>
</router-link>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'SidebarItem',
props: {
// `routes` `Array` `path``meta``children`
routes: {
type: Array
},
// `isNest` `Boolean` `false`
isNest: {
type: Boolean,
default: false
}
},
methods: {
hasOneShowingChildren(children) {
// `hasOneShowingChildren` `children` `item.children`
const showingChildren = children.filter(item => {
// 使 JavaScript `filter` `children` `filter` `true` `hidden` `false` `showingChildren`
return!item.hidden
})
if (showingChildren.length === 1) {
// `showingChildren` `1` `1` `true`
return true
}
return false
// `showingChildren` `1` `false`使
}
}
}
</script>

@ -1,89 +0,0 @@
<template>
<scroll-bar>
<el-menu
mode="vertical"
:show-timeout="200"
:default-active="$route.path"
:collapse="isCollapse"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<sidebar-item :routes="routes"></sidebar-item>
</el-menu>
</scroll-bar>
</template>
<script>
import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'
import ScrollBar from '@/components/ScrollBar'
export default {
components: { SidebarItem, ScrollBar },
computed: {
...mapGetters([
'sidebar',
'routers'
]),
routes() {
// return this.$router.options.routes
return this.routers
},
isCollapse() {
return !this.sidebar.opened
}
}
}
</script>
#abc
<template>
<!-- 使用名为 `scroll-bar` 的自定义组件可能是用于实现滚动条相关功能的组件比如自定义滚动条样式添加滚动交互逻辑等该组件作为外层容器包裹内部的 `el-menu` 组件以便为菜单提供滚动功能如果有相应实现的话 -->
<scroll-bar>
<!-- 使用 Element UI `el-menu` 菜单组件设置菜单模式为 `vertical`垂直方向展示`:show-timeout` 属性设置为 `200`表示菜单展开或收起时过渡动画的显示时长单位可能是毫秒`:default-active` 属性绑定为 `$route.path`意味着会根据当前路由的路径来自动设置默认激活的菜单项与当前页面匹配的菜单项处于激活状态`:collapse` 属性绑定 `isCollapse` 变量在计算属性中定义与侧边栏是否折叠相关用于控制菜单是否折叠显示同时设置了背景颜色文本颜色以及激活状态下的文本颜色用于定义菜单的整体外观颜色风格 -->
<el-menu
mode="vertical"
:show-timeout="200"
:default-active="$route.path"
:collapse="isCollapse"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<!-- 使用名为 `sidebar-item` 的自定义组件 `script` 部分有导入和注册用于根据传入的路由配置信息动态生成侧边栏菜单的具体内容通过 `:routes` 属性传递 `routes` 变量在计算属性中定义包含了菜单相关的路由配置数据用于递归地构建完整的侧边栏菜单结构展示各个菜单项及其嵌套子菜单等内容 -->
<sidebar-item :routes="routes"></sidebar-item>
</el-menu>
</scroll-bar>
</template>
<script>
// `vuex` `mapGetters` Vuex `getters` 便 Vuex 便使
import { mapGetters } from 'vuex';
// `SidebarItem`
import SidebarItem from './SidebarItem';
// `@/components/` `ScrollBar` `el-menu`
import ScrollBar from '@/components/ScrollBar';
export default {
components: {
// `components` `SidebarItem` `ScrollBar` 使 Vue.js 使
SidebarItem,
ScrollBar
},
computed: {
// 使 `mapGetters` Vuex `sidebar` `routers` `getters` `this.sidebar` `this.routers` `sidebar` `routers`
...mapGetters([
'sidebar',
'routers'
]),
routes() {
// `routes` `return this.$router.options.routes` `this.routers` `mapGetters` Vuex `sidebar-item`
return this.routers;
},
isCollapse() {
// `isCollapse` `this.sidebar.opened` `sidebar.opened` `false` `isCollapse` `true` `false` `el-menu` `:collapse`
return!this.sidebar.opened;
}
}
}
</script>

@ -1,3 +0,0 @@
export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'

@ -1,41 +0,0 @@
import store from '@/store'
const { body } = document
const WIDTH = 1024
const RATIO = 3
export default {
watch: {
$route(route) {
if (this.device === 'mobile' && this.sidebar.opened) {
store.dispatch('CloseSideBar', { withoutAnimation: false })
}
}
},
beforeMount() {
window.addEventListener('resize', this.resizeHandler)
},
mounted() {
const isMobile = this.isMobile()
if (isMobile) {
store.dispatch('ToggleDevice', 'mobile')
store.dispatch('CloseSideBar', { withoutAnimation: true })
}
},
methods: {
isMobile() {
const rect = body.getBoundingClientRect()
return rect.width - RATIO < WIDTH
},
resizeHandler() {
if (!document.hidden) {
const isMobile = this.isMobile()
store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop')
if (isMobile) {
store.dispatch('CloseSideBar', { withoutAnimation: true })
}
}
}
}
}

@ -1,386 +0,0 @@
<template>
<div>
<el-card class="login-form-layout">
<el-form autoComplete="on"
:model="loginForm"
:rules="loginRules"
ref="loginForm"
label-position="left">
<div style="text-align: center">
<svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon>
</div>
<h2 class="login-title color-main">mall-admin-web</h2>
<el-form-item prop="username">
<el-input name="username"
type="text"
v-model="loginForm.username"
autoComplete="on"
placeholder="请输入用户名">
<span slot="prefix">
<svg-icon icon-class="user" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input name="password"
:type="pwdType"
@keyup.enter.native="handleLogin"
v-model="loginForm.password"
autoComplete="on"
placeholder="请输入密码">
<span slot="prefix">
<svg-icon icon-class="password" class="color-main"></svg-icon>
</span>
<span slot="suffix" @click="showPwd">
<svg-icon icon-class="eye" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<el-form-item style="margin-bottom: 60px;text-align: center">
<el-button style="width: 45%" type="primary" :loading="loading" @click.native.prevent="handleLogin">
登录
</el-button>
<el-button style="width: 45%" type="primary" @click.native.prevent="handleTry">
获取体验账号
</el-button>
</el-form-item>
</el-form>
</el-card>
<img :src="login_center_bg" class="login-center-layout">
<el-dialog
title="公众号二维码"
:visible.sync="dialogVisible"
:show-close="false"
:center="true"
width="30%">
<div style="text-align: center">
<span class="font-title-large"><span class="color-main font-extra-large">关注公众号</span>回复<span class="color-main font-extra-large">体验</span>获取体验账号</span>
<br>
<img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg" width="160" height="160" style="margin-top: 10px">
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogConfirm"></el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {isvalidUsername} from '@/utils/validate';
import {setSupport,getSupport,setCookie,getCookie} from '@/utils/support';
import login_center_bg from '@/assets/images/login_center_bg.png'
export default {
name: 'login',
data() {
const validateUsername = (rule, value, callback) => {
if (!isvalidUsername(value)) {
callback(new Error('请输入正确的用户名'))
} else {
callback()
}
};
const validatePass = (rule, value, callback) => {
if (value.length < 3) {
callback(new Error('密码不能小于3位'))
} else {
callback()
}
};
return {
loginForm: {
username: '',
password: '',
},
loginRules: {
username: [{required: true, trigger: 'blur', validator: validateUsername}],
password: [{required: true, trigger: 'blur', validator: validatePass}]
},
loading: false,
pwdType: 'password',
login_center_bg,
dialogVisible:false,
supportDialogVisible:false
}
},
created() {
this.loginForm.username = getCookie("username");
this.loginForm.password = getCookie("password");
if(this.loginForm.username === undefined||this.loginForm.username==null||this.loginForm.username===''){
this.loginForm.username = 'admin';
}
if(this.loginForm.password === undefined||this.loginForm.password==null){
this.loginForm.password = '';
}
},
methods: {
showPwd() {
if (this.pwdType === 'password') {
this.pwdType = ''
} else {
this.pwdType = 'password'
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
// let isSupport = getSupport();
// if(isSupport===undefined||isSupport==null){
// this.dialogVisible =true;
// return;
// }
this.loading = true;
this.$store.dispatch('Login', this.loginForm).then(() => {
this.loading = false;
setCookie("username",this.loginForm.username,15);
setCookie("password",this.loginForm.password,15);
this.$router.push({path: '/'})
}).catch(() => {
this.loading = false
})
} else {
console.log('参数验证不合法!');
return false
}
})
},
handleTry(){
this.dialogVisible =true
},
dialogConfirm(){
this.dialogVisible =false;
setSupport(true);
},
dialogCancel(){
this.dialogVisible = false;
setSupport(false);
}
}
}
</script>
<style scoped>
.login-form-layout {
position: absolute;
left: 0;
right: 0;
width: 360px;
margin: 140px auto;
border-top: 10px solid #409EFF;
}
.login-title {
text-align: center;
}
.login-center-layout {
background: #409EFF;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
margin-top: 200px;
}
</style>
#abc
<template>
<div>
<!-- 使用 Element UI `el-card` 组件创建一个卡片式的布局容器类名为 `login-form-layout`用于包裹登录相关的表单元素使其在页面上呈现出特定的视觉效果和布局样式 -->
<el-card class="login-form-layout">
<!-- 使用 Element UI `el-form` 表单组件设置自动补全功能为 `on`绑定数据模型为 `loginForm`关联表单验证规则为 `loginRules`设置表单引用名为 `loginForm`标签位置为 `left`通常指表单标签在输入框左侧显示用于构建登录表单 -->
<el-form autoComplete="on"
:model="loginForm"
:rules="loginRules"
ref="loginForm"
label-position="left">
<!-- 一个 `div` 元素设置文本居中对齐内部使用 `svg-icon` 组件展示一个名为 `login-mall` 的图标用于在登录表单上方显示一个具有特定样式宽度高度颜色的图标可能起到品牌标识等作用 -->
<div style="text-align: center">
<svg-icon icon-class="login-mall" style="width: 56px;height: 56px;color: #409EFF"></svg-icon>
</div>
<!-- 一个 `h2` 标题元素类名为 `login-title` `color-main`用于显示页面标题mall-admin-web通过 `color-main` 类可能会应用特定的主色调样式 -->
<h2 class="login-title color-main">mall-admin-web</h2>
<!-- `el-form-item` 表单元素指定了验证属性 `prop` `username`用于包裹用户名输入框相关的内容对应表单中用户名的输入和验证部分 -->
<el-form-item prop="username">
<!-- 使用 Element UI `el-input` 输入框组件设置 `name` 属性为 `username`类型为 `text`双向绑定 `loginForm.username` 数据自动补全功能为 `on`设置占位提示文字为请输入用户名用于接收用户输入的用户名 -->
<el-input name="username"
type="text"
v-model="loginForm.username"
autoComplete="on"
placeholder="请输入用户名">
<!-- 使用 `slot` 插槽在输入框前缀位置插入一个 `svg-icon` 组件图标类名为 `user` 且应用 `color-main` 用于在用户名输入框前面展示一个表示用户的图标增强视觉提示效果 -->
<span slot="prefix">
<svg-icon icon-class="user" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<!-- `el-form-item` 表单元素指定验证属性 `prop` `password`用于包裹密码输入框相关的内容对应表单中密码的输入和验证部分 -->
<el-form-item prop="password">
<!-- 使用 Element UI `el-input` 输入框组件设置 `name` 属性为 `password`类型通过 `pwdType` 变量动态控制用于实现密码显示隐藏切换功能监听回车键按下事件`@keyup.enter.native`并触发 `handleLogin` 方法双向绑定 `loginForm.password` 数据自动补全功能为 `on`设置占位提示文字为请输入密码用于接收用户输入的密码 -->
<el-input name="password"
:type="pwdType"
@keyup.enter.native="handleLogin"
v-model="loginForm.password"
autoComplete="on"
placeholder="请输入密码">
<!-- 使用 `slot` 插槽在输入框前缀位置插入一个 `svg-icon` 组件图标类名为 `password` 且应用 `color-main` 用于在密码输入框前面展示一个表示密码的图标增强视觉提示效果 -->
<span slot="prefix">
<svg-icon icon-class="password" class="color-main"></svg-icon>
</span>
<!-- 使用 `slot` 插槽在输入框后缀位置插入一个 `svg-icon` 组件图标类名为 `eye` 且应用 `color-main` 点击该图标可触发 `showPwd` 方法用于实现密码显示隐藏的切换功能通过点击眼睛图标来切换密码的可见性 -->
<span slot="suffix" @click="showPwd">
<svg-icon icon-class="eye" class="color-main"></svg-icon>
</span>
</el-input>
</el-form-item>
<!-- `el-form-item` 表单元素设置了底部外边距为 `60px` 且文本居中对齐用于放置登录和获取体验账号的按钮作为表单底部的操作按钮区域 -->
<el-form-item style="margin-bottom: 60px;text-align: center">
<!-- 使用 Element UI `el-button` 按钮组件设置样式宽度为 `45%`按钮类型为 `primary`通常表示主要的突出显示的按钮样式通过 `loading` 变量控制加载状态显示如按钮显示加载动画等点击时触发 `handleLogin` 方法阻止默认行为防止表单提交等默认操作用于执行登录操作 -->
<el-button style="width: 45%" type="primary" :loading="loading" @click.native.prevent="handleLogin">
登录
</el-button>
<!-- 使用 Element UI `el-button` 按钮组件设置样式宽度为 `45%`按钮类型为 `primary`点击时触发 `handleTry` 方法阻止默认行为用于执行获取体验账号的操作 -->
<el-button style="width: 45%" type="primary" @click.native.prevent="handleTry">
获取体验账号
</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 使用 `img` 图片元素通过 `:src` 绑定 `login_center_bg` 变量 `data` 中定义应该是图片资源路径类名为 `login-center-layout`用于展示登录页面中心位置的背景图片根据样式设置其布局和显示效果 -->
<img :src="login_center_bg" class="login-center-layout">
<!-- 使用 Element UI `el-dialog` 对话框组件设置标题为公众号二维码通过双向绑定控制对话框的显示隐藏状态`:visible.sync`设置不显示关闭按钮`:show-close="false"`使其居中显示`:center="true"`宽度为 `30%`用于弹出展示公众号二维码相关信息的对话框 -->
<el-dialog
title="公众号二维码"
:visible.sync="dialogVisible"
:show-close="false"
:center="true"
width="30%">
<!-- 一个 `div` 元素设置文本居中对齐内部包含文本和图片元素用于在对话框中展示引导用户关注公众号获取体验账号的相关提示信息以及公众号二维码图片 -->
<div style="text-align: center">
<span class="font-title-large"><span class="color-main font-extra-large">关注公众号</span>回复<span class="color-main font-extra-large">体验</span>获取体验账号</span>
<br>
<!-- 使用 `img` 图片元素设置图片源地址宽度高度以及顶部外边距用于展示公众号二维码图片 -->
<img src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg" width="160" height="160" style="margin-top: 10px">
</div>
<span slot="footer" class="dialog-footer">
<!-- 使用 Element UI `el-button` 按钮组件按钮类型为 `primary`点击时触发 `dialogConfirm` 方法用于在对话框中执行确定操作 -->
<el-button type="primary" @click="dialogConfirm"></el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// `@/utils/validate` `isvalidUsername`
import {isvalidUsername} from '@/utils/validate';
// `@/utils/support` `setSupport` `getSupport` `setCookie` `getCookie` `Cookie`
import {setSupport,getSupport,setCookie,getCookie} from '@/utils/support';
// `login_center_bg` `@/assets/images/login_center_bg.png`
import login_center_bg from '@/assets/images/login_center_bg.png'
export default {
name: 'login',
data() {
const validateUsername = (rule, value, callback) => {
// `isvalidUsername` `Error`
if (!isvalidUsername(value)) {
callback(new Error('请输入正确的用户名'))
} else {
callback()
}
};
const validatePass = (rule, value, callback) => {
// `3` `Error` 3
if (value.length < 3) {
callback(new Error('密码不能小于3位'))
} else {
callback()
}
};
return {
// `username` `password` `Cookie`
loginForm: {
username: '',
password: '',
},
// `username` `required: true``trigger: 'blur'`使 `validateUsername` `password` 使 `validatePass`
loginRules: {
username: [{required: true, trigger: 'blur', validator: validateUsername}],
password: [{required: true, trigger: 'blur', validator: validatePass}]
},
// `false` `true` `false`
loading: false,
// `password` `showPwd` `password`
pwdType: 'password',
//
login_center_bg,
// `false` `true`
dialogVisible:false,
// 使 `false`
supportDialogVisible:false
}
},
created() {
// `Cookie` `loginForm.username` `loginForm.password` `null` `admin` `null` `Cookie`
this.loginForm.username = getCookie("username");
this.loginForm.password = getCookie("password");
if(this.loginForm.username === undefined||this.loginForm.username==null||this.loginForm.username===''){
this.loginForm.username = 'admin';
}
if(this.loginForm.password === undefined||this.loginForm.password==null){
this.loginForm.password = '';
}
},
methods: {
showPwd() {
// `pwdType` `password` 使 `pwdType` `password`
if (this.pwdType === 'password') {
this.pwdType = ''
} else {
this.pwdType = 'password'
}
},
handleLogin() {
// `$refs.loginForm` `validate` `valid` `true`
//
// `loading` `true` `$store.dispatch` `Login` Vuex `loading` `false`使 `setCookie` `Cookie` `15` `setCookie` `$router.push` `/``valid` `false` `false`
this.$refs.loginForm.validate(valid => {
if (valid) {
// let isSupport = getSupport();
// if(isSupport===undefined||isSupport==null){
// this.dialogVisible =true;
// return;
// }
this.loading = true;
this.$store.dispatch('Login', this.loginForm).then(() => {
this.loading = false;
setCookie("username",this.loginForm.username,15);
setCookie("password",this.loginForm.password,15);
this.$router.push({path: '/'})
}).catch(() => {
this.loading = false
})
} else {
console.log('参数验证不合法!');
return false
}
})
},
handleTry() {
// `dialogVisible` `true`
this.dialogVisible =true
},
dialogConfirm() {
// `dialogVisible` `false` `setSupport` `true` `setSupport`
this.dialogVisible =false;
setSupport(true);
},
dialogCancel() {
// `dialogVisible` `false` `setSupport` `false`
this.dialogVisible = false;
setSupport(false);
}
}
}
</script>
<style scoped>
// `login-form-layout` `absolute`使 `body` `0` `360px` `140px` `auto`

@ -1,34 +0,0 @@
<template> 
<brand-detail :is-edit='false'></brand-detail>
</template>
<script>
import BrandDetail from './components/BrandDetail'
export default {
name: 'addBrand',
components: { BrandDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 使用BrandDetail组件并传递一个名为is-edit的属性值设置为false用于表示当前处于非编辑状态 -->
<brand-detail :is-edit='false'></brand-detail>
</template>
<script>
// BrandDetail./components/BrandDetailVue
import BrandDetail from './components/BrandDetail'
export default {
name: 'addBrand',
// BrandDetail使使
components: { BrandDetail }
}
</script>
<style>
/* 这里可以添加针对当前组件的样式规则,目前为空 */
</style>

@ -1,145 +0,0 @@
<template> 
<el-card class="form-container" shadow="never">
<el-form :model="brand" :rules="rules" ref="brandFrom" label-width="150px">
<el-form-item label="品牌名称:" prop="name">
<el-input v-model="brand.name"></el-input>
</el-form-item>
<el-form-item label="品牌首字母:">
<el-input v-model="brand.firstLetter"></el-input>
</el-form-item>
<el-form-item label="品牌LOGO" prop="logo">
<single-upload v-model="brand.logo"></single-upload>
</el-form-item>
<el-form-item label="品牌专区大图:">
<single-upload v-model="brand.bigPic"></single-upload>
</el-form-item>
<el-form-item label="品牌故事:">
<el-input
placeholder="请输入内容"
type="textarea"
v-model="brand.brandStory"
:autosize="true"></el-input>
</el-form-item>
<el-form-item label="排序:" prop="sort">
<el-input v-model.number="brand.sort"></el-input>
</el-form-item>
<el-form-item label="是否显示:">
<el-radio-group v-model="brand.showStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="品牌制造商:">
<el-radio-group v-model="brand.factoryStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('brandFrom')"></el-button>
<el-button v-if="!isEdit" @click="resetForm('brandFrom')"></el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
import {createBrand, getBrand, updateBrand} from '@/api/brand'
import SingleUpload from '@/components/Upload/singleUpload'
const defaultBrand={
bigPic: '',
brandStory: '',
factoryStatus: 0,
firstLetter: '',
logo: '',
name: '',
showStatus: 0,
sort: 0
};
export default {
name: 'BrandDetail',
components:{SingleUpload},
props: {
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
brand:Object.assign({}, defaultBrand),
rules: {
name: [
{required: true, message: '请输入品牌名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
],
logo: [
{required: true, message: '请输入品牌logo', trigger: 'blur'}
],
sort: [
{type: 'number', message: '排序必须为数字'}
],
}
}
},
created() {
if (this.isEdit) {
getBrand(this.$route.query.id).then(response => {
this.brand = response.data;
});
}else{
this.brand = Object.assign({},defaultBrand);
}
},
methods: {
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('是否提交数据', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
updateBrand(this.$route.query.id, this.brand).then(response => {
this.$refs[formName].resetFields();
this.$message({
message: '修改成功',
type: 'success',
duration:1000
});
this.$router.back();
});
} else {
createBrand(this.brand).then(response => {
this.$refs[formName].resetFields();
this.brand = Object.assign({},defaultBrand);
this.$message({
message: '提交成功',
type: 'success',
duration:1000
});
});
}
});
} else {
this.$message({
message: '验证失败',
type: 'error',
duration:1000
});
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.brand = Object.assign({},defaultBrand);
}
}
}
</script>
<style>
</style>

@ -1,674 +0,0 @@
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float: right"
@click="searchBrandList()"
type="primary"
size="small">
查询结果
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="输入搜索:">
<el-input style="width: 203px" v-model="listQuery.keyword" placeholder="品牌名称/关键字"></el-input>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button
class="btn-add"
@click="addBrand()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="brandTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<el-table-column type="selection" width="60" align="center"></el-table-column>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="品牌名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="品牌首字母" width="100" align="center">
<template slot-scope="scope">{{scope.row.firstLetter}}</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<el-table-column label="品牌制造商" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleFactoryStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.factoryStatus">
</el-switch>
</template>
</el-table-column>
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleShowStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.showStatus">
</el-switch>
</template>
</el-table-column>
<el-table-column label="相关" width="220" align="center">
<template slot-scope="scope">
<span>商品</span>
<el-button
size="mini"
type="text"
@click="getProductList(scope.$index, scope.row)">100
</el-button>
<span>评价</span>
<el-button
size="mini"
type="text"
@click="getProductCommentList(scope.$index, scope.row)">1000
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="batch-operate-container">
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import {fetchList, updateShowStatus, updateFactoryStatus, deleteBrand} from '@/api/brand'
export default {
name: 'brandList',
data() {
return {
operates: [
{
label: "显示品牌",
value: "showBrand"
},
{
label: "隐藏品牌",
value: "hideBrand"
}
],
operateType: null,
listQuery: {
keyword: null,
pageNum: 1,
pageSize: 10
},
list: null,
total: null,
listLoading: true,
multipleSelection: []
}
},
created() {
this.getList();
},
methods: {
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
this.totalPage = response.data.totalPage;
this.pageSize = response.data.pageSize;
});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleUpdate(index, row) {
this.$router.push({path: '/pms/updateBrand', query: {id: row.id}})
},
handleDelete(index, row) {
this.$confirm('是否要删除该品牌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteBrand(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
},
getProductList(index, row) {
console.log(index, row);
},
getProductCommentList(index, row) {
console.log(index, row);
},
handleFactoryStatusChange(index, row) {
var data = new URLSearchParams();
data.append("ids", row.id);
data.append("factoryStatus", row.factoryStatus);
updateFactoryStatus(data).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
}).catch(error => {
if (row.factoryStatus === 0) {
row.factoryStatus = 1;
} else {
row.factoryStatus = 0;
}
});
},
handleShowStatusChange(index, row) {
let data = new URLSearchParams();
;
data.append("ids", row.id);
data.append("showStatus", row.showStatus);
updateShowStatus(data).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
}).catch(error => {
if (row.showStatus === 0) {
row.showStatus = 1;
} else {
row.showStatus = 0;
}
});
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
searchBrandList() {
this.listQuery.pageNum = 1;
this.getList();
},
handleBatchOperate() {
console.log(this.multipleSelection);
if (this.multipleSelection < 1) {
this.$message({
message: '请选择一条记录',
type: 'warning',
duration: 1000
});
return;
}
let showStatus = 0;
if (this.operateType === 'showBrand') {
showStatus = 1;
} else if (this.operateType === 'hideBrand') {
showStatus = 0;
} else {
this.$message({
message: '请选择批量操作类型',
type: 'warning',
duration: 1000
});
return;
}
let ids = [];
for (let i = 0; i < this.multipleSelection.length; i++) {
ids.push(this.multipleSelection[i].id);
}
let data = new URLSearchParams();
data.append("ids", ids);
data.append("showStatus", showStatus);
updateShowStatus(data).then(response => {
this.getList();
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
addBrand() {
this.$router.push({path: '/pms/addBrand'})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
</style>
#abc
<template>
<!-- 整个页面的最外层容器用于布局和包裹内部的各个组件与元素 -->
<div class="app-container">
<!-- 筛选搜索区域的卡片组件设置阴影效果为无 -->
<el-card class="filter-container" shadow="never">
<div>
<!-- 使用Element UI的图标组件展示搜索图标 -->
<i class="el-icon-search"></i>
<!-- 显示筛选搜索的文字说明 -->
<span>筛选搜索</span>
<!-- Element UI的按钮组件点击时触发searchBrandList方法样式设置为靠右类型为主要按钮尺寸为小 -->
<el-button
style="float: right"
@click="searchBrandList()"
type="primary"
size="small">
查询结果
</el-button>
</div>
<div style="margin-top: 15px">
<!-- 内联表单组件绑定数据模型为listQuery尺寸为小标签宽度为140px -->
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<!-- 表单项标签显示为输入搜索 -->
<el-form-item label="输入搜索:">
<!-- 输入框组件绑定数据模型为listQuery的keyword属性宽度为203px有占位提示文字 -->
<el-input style="width: 203px" v-model="listQuery.keyword" placeholder="品牌名称/关键字"></el-input>
</el-form-item>
</el-form>
</div>
</el-card>
<!-- 操作区域的卡片组件设置阴影效果为无 -->
<el-card class="operate-container" shadow="never">
<!-- 使用Element UI的图标组件展示票务图标此处可能表意不太准确需根据实际情况确认合适图标含义 -->
<i class="el-icon-tickets"></i>
<!-- 显示数据列表的文字说明 -->
<span>数据列表</span>
<!-- Element UI的按钮组件点击时触发addBrand方法尺寸为迷你 -->
<el-button
class="btn-add"
@click="addBrand()"
size="mini">
添加
</el-button>
</el-card>
<!-- 表格容器用于放置展示数据的表格 -->
<div class="table-container">
<!-- Element UI的表格组件绑定数据为list宽度为100%监听选择行变化事件加载状态变化设置边框 -->
<el-table ref="brandTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<!-- 表格列类型为选择框宽度为60px内容居中对齐 -->
<el-table-column type="selection" width="60" align="center"></el-table-column>
<!-- 表格列标签显示为编号宽度为100px内容居中对齐通过插槽作用域展示对应行的数据中的id属性 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列标签显示为品牌名称内容居中对齐通过插槽作用域展示对应行的数据中的name属性 -->
<el-table-column label="品牌名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列标签显示为品牌首字母宽度为100px内容居中对齐通过插槽作用域展示对应行的数据中的firstLetter属性 -->
<el-table-column label="品牌首字母" width="100" align="center">
<template slot-scope="scope">{{scope.row.firstLetter}}</template>
</el-table-column>
<!-- 表格列标签显示为排序宽度为100px内容居中对齐通过插槽作用域展示对应行的数据中的sort属性 -->
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<!-- 表格列标签显示为品牌制造商宽度为100px内容居中对齐内部包含一个开关组件用于切换工厂状态绑定对应行的数据中的factoryStatus属性并监听状态改变事件 -->
<el-table-column label="品牌制造商" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleFactoryStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.factoryStatus">
</el-switch>
</template>
</el-table-column>
<!-- 表格列标签显示为是否显示宽度为100px内容居中对齐内部包含一个开关组件用于切换显示状态绑定对应行的数据中的showStatus属性并监听状态改变事件 -->
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleShowStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.showStatus">
</el-switch>
</template>
</el-table-column>
<!-- 表格列标签显示为相关宽度为220px内容居中对齐内部包含查看商品评价相关的按钮点击可触发对应的方法并传递对应行数据 -->
<el-table-column label="相关" width="220" align="center">
<template slot-scope="scope">
<span>商品</span>
<el-button
size="mini"
type="text"
@click="getProductList(scope.$index, scope.row)">100
</el-button>
<span>评价</span>
<el-button
size="mini"
type="text"
@click="getProductCommentList(scope.$index, scope.row)">1000
</el-button>
</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为200px内容居中对齐内部包含编辑删除按钮点击可触发对应的操作方法并传递对应行数据 -->
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 批量操作区域的容器 -->
<div class="batch-operate-container">
<!-- 下拉选择框组件绑定数据模型为operateType有占位提示文字 -->
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<!-- 通过循环生成下拉选项每个选项的标签和值根据operates数组中的元素来确定 -->
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- Element UI的按钮组件点击时触发handleBatchOperate方法样式设置有一定间隔类型为主要按钮尺寸为小 -->
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<!-- 分页容器用于放置分页组件 -->
<div class="pagination-container">
<!-- Element UI的分页组件设置背景色监听页面尺寸和当前页变化事件布局包含多种分页相关元素绑定相关数据属性 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// @/api/brand
import {fetchList, updateShowStatus, updateFactoryStatus, deleteBrand} from '@/api/brand'
export default {
name: 'brandList',
data() {
return {
//
operates: [
{
label: "显示品牌",
value: "showBrand"
},
{
label: "隐藏品牌",
value: "hideBrand"
}
],
// null
operateType: null,
//
listQuery: {
keyword: null,
pageNum: 1,
pageSize: 10
},
// null
list: null,
// null
total: null,
// true
listLoading: true,
//
multipleSelection: []
}
},
created() {
// getList
this.getList();
},
methods: {
getList() {
// true
this.listLoading = true;
// fetchList
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
this.totalPage = response.data.totalPage;
this.pageSize = response.data.pageSize;
});
},
handleSelectionChange(val) {
// multipleSelection
this.multipleSelection = val;
},
handleUpdate(index, row) {
// id
this.$router.push({path: '/pms/updateBrand', query: {id: row.id}})
},
handleDelete(index, row) {
// deleteBrand
this.$confirm('是否要删除该品牌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteBrand(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
},
getProductList(index, row) {
//
console.log(index, row);
},
getProductCommentList(index, row) {
//
console.log(index, row);
},
handleFactoryStatusChange(index, row) {
// URLSearchParamsidupdateFactoryStatus
var data = new URLSearchParams();
data.append("ids", row.id);
data.append("factoryStatus", row.factoryStatus);
updateFactoryStatus(data).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
}).catch(error => {
if (row.factoryStatus === 0) {
row.factoryStatus = 1;
} else {
row.factoryStatus = 0;
}
});
},
handleShowStatusChange(index, row) {
// URLSearchParamsidupdateShowStatus
let data = new URLSearchParams();
data.append("ids", row.id);
data.append("showStatus", row.showStatus);
updateShowStatus(data).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
}).catch(error => {
if (row.showStatus === 0) {
row.showStatus = 1;
} else {
row.showStatus = 0;
}
});
},
handleSizeChange(val) {
// 1
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
//
this.listQuery.pageNum = val;
this.getList();
},
searchBrandList() {
// 1
this.listQuery.pageNum = 1;
this.getList();
},
handleBatchOperate() {
console.log(this.multipleSelection);
//
if (this.multipleSelection.length < 1) {
this.$message({
message: '请选择一条记录',
type: 'warning',
duration: 1000
});
return;
}
let showStatus = 0;
//
if (this.operateType === 'showBrand') {
showStatus = 1;
} else if (this.operateType === 'hideBrand') {
showStatus = 0;
} else {
//
this.$message({
message: '请选择批量操作类型',
type: 'warning',
duration: 1000
});
return;
}
let ids = [];
// idids
for (let i = 0; i < this.multipleSelection.length; i++) {
ids.push(this.multipleSelection[i].id);
}
let data = new URLSearchParams();
data.append("ids", ids);
data.append("showStatus", showStatus);
// updateShowStatus
updateShowStatus(data).then(response => {
this.getList();
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
addBrand() {
//
this.$router.push({path: '/pms/addBrand'})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
/*
scoped属性表示样式只作用于当前组件内部的元素避免样式污染其他组件 */
</

@ -1,37 +0,0 @@
<template> 
<brand-detail :is-edit='true'></brand-detail>
</template>
<script>
import BrandDetail from './components/BrandDetail'
export default {
name: 'updateBrand',
components: { BrandDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 使用BrandDetail组件并传递一个名为is-edit的属性值设置为true意味着当前处于编辑状态
可能用于控制BrandDetail组件内部呈现出可编辑的界面等相关功能 -->
<brand-detail :is-edit='true'></brand-detail>
</template>
<script>
// './components/BrandDetail'BrandDetailVue
// 使
import BrandDetail from './components/BrandDetail'
export default {
name: 'updateBrand',
// BrandDetail使template使
//
components: { BrandDetail }
}
</script>
<style>
/* CSS
比如对组件内元素的布局颜色字体等样式相关的设置 */
</style>

@ -1,30 +0,0 @@
<template> 
<product-detail :is-edit='false'></product-detail>
</template>
<script>
import ProductDetail from './components/ProductDetail'
export default {
name: 'addProduct',
components: { ProductDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 这里使用了名为 `product-detail` 的自定义组件通过 `:is-edit='false'` 属性绑定 `product-detail` 组件传递了一个名为 `is-edit` 的属性值为 `false`意味着当前是新增商品的操作模式而非编辑商品模式`product-detail` 组件应该会根据这个属性来展示相应的界面和执行对应的逻辑 -->
<product-detail :is-edit='false'></product-detail>
</template>
<script>
// `./components/` `ProductDetail`
import ProductDetail from './components/ProductDetail';
export default {
name: 'addProduct',
// `components` `ProductDetail` 使`addProduct`使 `<product-detail>` Vue.js
components: { ProductDetail }
}
</script>
<style>
/* 这里的样式部分目前为空,可根据 `addProduct` 组件整体的视觉设计需求,添加相应的 CSS 样式规则,比如设置组件的布局、大小、颜色等样式属性,使其在页面中呈现出符合预期的外观效果 */
</style>

@ -1,952 +0,0 @@
<template>
<div style="margin-top: 50px">
<el-form :model="value" ref="productAttrForm" label-width="120px" class="form-inner-container" size="small">
<el-form-item label="属性类型:">
<el-select v-model="value.productAttributeCategoryId"
placeholder="请选择属性类型"
@change="handleProductAttrChange">
<el-option
v-for="item in productAttributeCategoryOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="商品规格:">
<el-card shadow="never" class="cardBg">
<div v-for="(productAttr,idx) in selectProductAttr">
{{productAttr.name}}
<el-checkbox-group v-if="productAttr.handAddStatus===0" v-model="selectProductAttr[idx].values">
<el-checkbox v-for="item in getInputListArr(productAttr.inputList)" :label="item" :key="item"
class="littleMarginLeft"></el-checkbox>
</el-checkbox-group>
<div v-else>
<el-checkbox-group v-model="selectProductAttr[idx].values">
<div v-for="(item,index) in selectProductAttr[idx].options" style="display: inline-block"
class="littleMarginLeft">
<el-checkbox :label="item" :key="item"></el-checkbox>
<el-button type="text" class="littleMarginLeft" @click="handleRemoveProductAttrValue(idx,index)">
</el-button>
</div>
</el-checkbox-group>
<el-input v-model="addProductAttrValue" style="width: 160px;margin-left: 10px" clearable></el-input>
<el-button class="littleMarginLeft" @click="handleAddProductAttrValue(idx)"></el-button>
</div>
</div>
</el-card>
<el-table style="width: 100%;margin-top: 20px"
:data="value.skuStockList"
border>
<el-table-column
v-for="(item,index) in selectProductAttr"
:label="item.name"
:key="item.id"
align="center">
<template slot-scope="scope">
{{getProductSkuSp(scope.row,index)}}
</template>
</el-table-column>
<el-table-column
label="销售价格"
width="100"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.price"></el-input>
</template>
</el-table-column>
<el-table-column
label="促销价格"
width="100"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.promotionPrice"></el-input>
</template>
</el-table-column>
<el-table-column
label="商品库存"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.stock"></el-input>
</template>
</el-table-column>
<el-table-column
label="库存预警值"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.lowStock"></el-input>
</template>
</el-table-column>
<el-table-column
label="SKU编号"
width="160"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.skuCode"></el-input>
</template>
</el-table-column>
<el-table-column
label="操作"
width="80"
align="center">
<template slot-scope="scope">
<el-button
type="text"
@click="handleRemoveProductSku(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-button
type="primary"
style="margin-top: 20px"
@click="handleRefreshProductSkuList">刷新列表
</el-button>
<el-button
type="primary"
style="margin-top: 20px"
@click="handleSyncProductSkuPrice">同步价格
</el-button>
<el-button
type="primary"
style="margin-top: 20px"
@click="handleSyncProductSkuStock">同步库存
</el-button>
</el-form-item>
<el-form-item label="属性图片:" v-if="hasAttrPic">
<el-card shadow="never" class="cardBg">
<div v-for="(item,index) in selectProductAttrPics">
<span>{{item.name}}:</span>
<single-upload v-model="item.pic"
style="width: 300px;display: inline-block;margin-left: 10px"></single-upload>
</div>
</el-card>
</el-form-item>
<el-form-item label="商品参数:">
<el-card shadow="never" class="cardBg">
<div v-for="(item,index) in selectProductParam" :class="{littleMarginTop:index!==0}">
<div class="paramInputLabel">{{item.name}}:</div>
<el-select v-if="item.inputType===1" class="paramInput" v-model="selectProductParam[index].value">
<el-option
v-for="item in getParamInputList(item.inputList)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-input v-else class="paramInput" v-model="selectProductParam[index].value"></el-input>
</div>
</el-card>
</el-form-item>
<el-form-item label="商品相册:">
<multi-upload v-model="selectProductPics"></multi-upload>
</el-form-item>
<el-form-item label="商品详情:">
<el-tabs v-model="activeHtmlName" type="card">
<el-tab-pane label="电脑端详情" name="pc">
<tinymce :width="595" :height="300" v-model="value.detailHtml"></tinymce>
</el-tab-pane>
<el-tab-pane label="移动端详情" name="mobile">
<tinymce :width="595" :height="300" v-model="value.detailMobileHtml"></tinymce>
</el-tab-pane>
</el-tabs>
</el-form-item>
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleNext"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {fetchList as fetchProductAttrCateList} from '@/api/productAttrCate'
import {fetchList as fetchProductAttrList} from '@/api/productAttr'
import SingleUpload from '@/components/Upload/singleUpload'
import MultiUpload from '@/components/Upload/multiUpload'
import Tinymce from '@/components/Tinymce'
export default {
name: "ProductAttrDetail",
components: {SingleUpload, MultiUpload, Tinymce},
props: {
value: Object,
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
//
hasEditCreated:false,
//
productAttributeCategoryOptions: [],
//
selectProductAttr: [],
//
selectProductParam: [],
//
selectProductAttrPics: [],
//
addProductAttrValue: '',
//
activeHtmlName: 'pc'
}
},
computed: {
//
hasAttrPic() {
if (this.selectProductAttrPics.length < 1) {
return false;
}
return true;
},
//
productId(){
return this.value.id;
},
//
selectProductPics:{
get:function () {
let pics=[];
if(this.value.pic===undefined||this.value.pic==null||this.value.pic===''){
return pics;
}
pics.push(this.value.pic);
if(this.value.albumPics===undefined||this.value.albumPics==null||this.value.albumPics===''){
return pics;
}
let albumPics = this.value.albumPics.split(',');
for(let i=0;i<albumPics.length;i++){
pics.push(albumPics[i]);
}
return pics;
},
set:function (newValue) {
if (newValue == null || newValue.length === 0) {
this.value.pic = null;
this.value.albumPics = null;
} else {
this.value.pic = newValue[0];
this.value.albumPics = '';
if (newValue.length > 1) {
for (let i = 1; i < newValue.length; i++) {
this.value.albumPics += newValue[i];
if (i !== newValue.length - 1) {
this.value.albumPics += ',';
}
}
}
}
}
}
},
created() {
this.getProductAttrCateList();
},
watch: {
productId:function (newValue) {
if(!this.isEdit)return;
if(this.hasEditCreated)return;
if(newValue===undefined||newValue==null||newValue===0)return;
this.handleEditCreated();
}
},
methods: {
handleEditCreated() {
//id
if(this.value.productAttributeCategoryId!=null){
this.handleProductAttrChange(this.value.productAttributeCategoryId);
}
this.hasEditCreated=true;
},
getProductAttrCateList() {
let param = {pageNum: 1, pageSize: 100};
fetchProductAttrCateList(param).then(response => {
this.productAttributeCategoryOptions = [];
let list = response.data.list;
for (let i = 0; i < list.length; i++) {
this.productAttributeCategoryOptions.push({label: list[i].name, value: list[i].id});
}
});
},
getProductAttrList(type, cid) {
let param = {pageNum: 1, pageSize: 100, type: type};
fetchProductAttrList(cid, param).then(response => {
let list = response.data.list;
if (type === 0) {
this.selectProductAttr = [];
for (let i = 0; i < list.length; i++) {
let options = [];
let values = [];
if (this.isEdit) {
if (list[i].handAddStatus === 1) {
//
options = this.getEditAttrOptions(list[i].id);
}
//
values = this.getEditAttrValues(i);
}
this.selectProductAttr.push({
id: list[i].id,
name: list[i].name,
handAddStatus: list[i].handAddStatus,
inputList: list[i].inputList,
values: values,
options: options
});
}
if(this.isEdit){
//
this.refreshProductAttrPics();
}
} else {
this.selectProductParam = [];
for (let i = 0; i < list.length; i++) {
let value=null;
if(this.isEdit){
//
value= this.getEditParamValue(list[i].id);
}
this.selectProductParam.push({
id: list[i].id,
name: list[i].name,
value: value,
inputType: list[i].inputType,
inputList: list[i].inputList
});
}
}
});
},
//
getEditAttrOptions(id) {
let options = [];
for (let i = 0; i < this.value.productAttributeValueList.length; i++) {
let attrValue = this.value.productAttributeValueList[i];
if (attrValue.productAttributeId === id) {
let strArr = attrValue.value.split(',');
for (let j = 0; j < strArr.length; j++) {
options.push(strArr[j]);
}
break;
}
}
return options;
},
//
getEditAttrValues(index) {
let values = new Set();
if (index === 0) {
for (let i = 0; i < this.value.skuStockList.length; i++) {
let sku = this.value.skuStockList[i];
let spData = JSON.parse(sku.spData);
if (spData!= null && spData.length>=1) {
values.add(spData[0].value);
}
}
} else if (index === 1) {
for (let i = 0; i < this.value.skuStockList.length; i++) {
let sku = this.value.skuStockList[i];
let spData = JSON.parse(sku.spData);
if (spData!= null && spData.length>=2) {
values.add(spData[1].value);
}
}
} else {
for (let i = 0; i < this.value.skuStockList.length; i++) {
let sku = this.value.skuStockList[i];
let spData = JSON.parse(sku.spData);
if (spData!= null && spData.length>=3) {
values.add(spData[2].value);
}
}
}
return Array.from(values);
},
//
getEditParamValue(id){
for(let i=0;i<this.value.productAttributeValueList.length;i++){
if(id===this.value.productAttributeValueList[i].productAttributeId){
return this.value.productAttributeValueList[i].value;
}
}
},
handleProductAttrChange(value) {
this.getProductAttrList(0, value);
this.getProductAttrList(1, value);
},
getInputListArr(inputList) {
return inputList.split(',');
},
handleAddProductAttrValue(idx) {
let options = this.selectProductAttr[idx].options;
if (this.addProductAttrValue == null || this.addProductAttrValue == '') {
this.$message({
message: '属性值不能为空',
type: 'warning',
duration: 1000
});
return
}
if (options.indexOf(this.addProductAttrValue) !== -1) {
this.$message({
message: '属性值不能重复',
type: 'warning',
duration: 1000
});
return;
}
this.selectProductAttr[idx].options.push(this.addProductAttrValue);
this.addProductAttrValue = null;
},
handleRemoveProductAttrValue(idx, index) {
this.selectProductAttr[idx].options.splice(index, 1);
},
getProductSkuSp(row, index) {
let spData = JSON.parse(row.spData);
if(spData!=null&&index<spData.length){
return spData[index].value;
}else{
return null;
}
},
handleRefreshProductSkuList() {
this.$confirm('刷新列表将导致sku信息重新生成是否要刷新', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.refreshProductAttrPics();
this.refreshProductSkuList();
});
},
handleSyncProductSkuPrice(){
this.$confirm('将同步第一个sku的价格到所有sku,是否继续', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if(this.value.skuStockList!==null&&this.value.skuStockList.length>0){
let tempSkuList = [];
tempSkuList = tempSkuList.concat(tempSkuList,this.value.skuStockList);
let price=this.value.skuStockList[0].price;
for(let i=0;i<tempSkuList.length;i++){
tempSkuList[i].price=price;
}
this.value.skuStockList=[];
this.value.skuStockList=this.value.skuStockList.concat(this.value.skuStockList,tempSkuList);
}
});
},
handleSyncProductSkuStock(){
this.$confirm('将同步第一个sku的库存到所有sku,是否继续', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if(this.value.skuStockList!==null&&this.value.skuStockList.length>0){
let tempSkuList = [];
tempSkuList = tempSkuList.concat(tempSkuList,this.value.skuStockList);
let stock=this.value.skuStockList[0].stock;
let lowStock=this.value.skuStockList[0].lowStock;
for(let i=0;i<tempSkuList.length;i++){
tempSkuList[i].stock=stock;
tempSkuList[i].lowStock=lowStock;
}
this.value.skuStockList=[];
this.value.skuStockList=this.value.skuStockList.concat(this.value.skuStockList,tempSkuList);
}
});
},
refreshProductSkuList() {
this.value.skuStockList = [];
let skuList = this.value.skuStockList;
//
if (this.selectProductAttr.length === 1) {
let attr = this.selectProductAttr[0];
for (let i = 0; i < attr.values.length; i++) {
skuList.push({
spData: JSON.stringify([{key:attr.name,value:attr.values[i]}])
});
}
} else if (this.selectProductAttr.length === 2) {
let attr0 = this.selectProductAttr[0];
let attr1 = this.selectProductAttr[1];
for (let i = 0; i < attr0.values.length; i++) {
if (attr1.values.length === 0) {
skuList.push({
spData: JSON.stringify([{key:attr0.name,value:attr0.values[i]}])
});
continue;
}
for (let j = 0; j < attr1.values.length; j++) {
let spData = [];
spData.push({key:attr0.name,value:attr0.values[i]});
spData.push({key:attr1.name,value:attr1.values[j]});
skuList.push({
spData: JSON.stringify(spData)
});
}
}
} else {
let attr0 = this.selectProductAttr[0];
let attr1 = this.selectProductAttr[1];
let attr2 = this.selectProductAttr[2];
for (let i = 0; i < attr0.values.length; i++) {
if (attr1.values.length === 0) {
skuList.push({
spData: JSON.stringify([{key:attr0.name,value:attr0.values[i]}])
});
continue;
}
for (let j = 0; j < attr1.values.length; j++) {
if (attr2.values.length === 0) {
let spData = [];
spData.push({key:attr0.name,value:attr0.values[i]});
spData.push({key:attr1.name,value:attr1.values[j]});
skuList.push({
spData: JSON.stringify(spData)
});
continue;
}
for (let k = 0; k < attr2.values.length; k++) {
let spData = [];
spData.push({key:attr0.name,value:attr0.values[i]});
spData.push({key:attr1.name,value:attr1.values[j]});
spData.push({key:attr2.name,value:attr2.values[k]});
skuList.push({
spData: JSON.stringify(spData)
});
}
}
}
}
},
refreshProductAttrPics() {
this.selectProductAttrPics = [];
if (this.selectProductAttr.length >= 1) {
let values = this.selectProductAttr[0].values;
for (let i = 0; i < values.length; i++) {
let pic=null;
if(this.isEdit){
//
pic=this.getProductSkuPic(values[i]);
}
this.selectProductAttrPics.push({name: values[i], pic: pic})
}
}
},
//
getProductSkuPic(name){
for(let i=0;i<this.value.skuStockList.length;i++){
let spData = JSON.parse(this.value.skuStockList[i].spData);
if(name===spData[0].value){
return this.value.skuStockList[i].pic;
}
}
return null;
},
//
mergeProductAttrValue() {
this.value.productAttributeValueList = [];
for (let i = 0; i < this.selectProductAttr.length; i++) {
let attr = this.selectProductAttr[i];
if (attr.handAddStatus === 1 && attr.options != null && attr.options.length > 0) {
this.value.productAttributeValueList.push({
productAttributeId: attr.id,
value: this.getOptionStr(attr.options)
});
}
}
for (let i = 0; i < this.selectProductParam.length; i++) {
let param = this.selectProductParam[i];
this.value.productAttributeValueList.push({
productAttributeId: param.id,
value: param.value
});
}
},
//
mergeProductAttrPics() {
for (let i = 0; i < this.selectProductAttrPics.length; i++) {
for (let j = 0; j < this.value.skuStockList.length; j++) {
let spData = JSON.parse(this.value.skuStockList[j].spData);
if (spData[0].value === this.selectProductAttrPics[i].name) {
this.value.skuStockList[j].pic = this.selectProductAttrPics[i].pic;
}
}
}
},
getOptionStr(arr) {
let str = '';
for (let i = 0; i < arr.length; i++) {
str += arr[i];
if (i != arr.length - 1) {
str += ',';
}
}
return str;
},
handleRemoveProductSku(index, row) {
let list = this.value.skuStockList;
if (list.length === 1) {
list.pop();
} else {
list.splice(index, 1);
}
},
getParamInputList(inputList) {
return inputList.split(',');
},
handlePrev() {
this.$emit('prevStep')
},
handleNext() {
this.mergeProductAttrValue();
this.mergeProductAttrPics();
this.$emit('nextStep')
}
}
}
</script>
<style scoped>
.littleMarginLeft {
margin-left: 10px;
}
.littleMarginTop {
margin-top: 10px;
}
.paramInput {
width: 250px;
}
.paramInputLabel {
display: inline-block;
width: 100px;
text-align: right;
padding-right: 10px
}
.cardBg {
background: #F8F9FC;
}
</style>
#abc
<template>
<!-- 整体的外层 div设置了距离顶部 50px margin用于页面布局上的间隔 -->
<div style="margin-top: 50px">
<!-- el-form 表单组件绑定数据模型为 value设置了表单引用名标签宽度类名以及尺寸为小用于收集和展示商品相关信息 -->
<el-form :model="value" ref="productAttrForm" label-width="120px" class="form-inner-container" size="small">
<!-- 表单项标签显示为属性类型 -->
<el-form-item label="属性类型:">
<!-- el-select 下拉选择框组件绑定 v-model value.productAttributeCategoryId有占位提示文字并且监听 change 事件 -->
<el-select v-model="value.productAttributeCategoryId"
placeholder="请选择属性类型"
@change="handleProductAttrChange">
<!-- 通过循环生成下拉选项每个选项的标签和值根据 productAttributeCategoryOptions 数组中的元素来确定 -->
<el-option
v-for="item in productAttributeCategoryOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 表单项标签显示为商品规格用于展示和操作商品规格相关内容 -->
<el-form-item label="商品规格:">
<!-- el-card 卡片组件设置阴影效果为无添加了自定义类名 cardBg用于对商品规格部分进行布局划分 -->
<el-card shadow="never" class="cardBg">
<!-- 循环遍历 selectProductAttr 数组展示每个商品属性相关内容 -->
<div v-for="(productAttr,idx) in selectProductAttr">
<!-- 显示商品属性的名称 -->
{{productAttr.name}}
<!-- 根据商品属性的 handAddStatus 判断使用不同的复选框组展示方式当为 0 时使用固定的输入列表生成复选框 -->
<el-checkbox-group v-if="productAttr.handAddStatus===0" v-model="selectProductAttr[idx].values">
<el-checkbox v-for="item in getInputListArr(productAttr.inputList)" :label="item" :key="item"
class="littleMarginLeft"></el-checkbox>
</el-checkbox-group>
<!-- handAddStatus 不为 0 展示可动态操作的复选框组包含添加删除选项等功能 -->
<div v-else>
<el-checkbox-group v-model="selectProductAttr[idx].values">
<div v-for="(item,index) in selectProductAttr[idx].options" style="display: inline-block"
class="littleMarginLeft">
<el-checkbox :label="item" :key="item"></el-checkbox>
<el-button type="text" class="littleMarginLeft" @click="handleRemoveProductAttrValue(idx,index)">
</el-button>
</div>
</el-checkbox-group>
<el-input v-model="addProductAttrValue" style="width: 160px;margin-left: 10px" clearable></el-input>
<el-button class="littleMarginLeft" @click="handleAddProductAttrValue(idx)"></el-button>
</div>
</div>
</el-card>
<!-- el-table 表格组件设置宽度为 100%绑定数据为 value.skuStockList设置边框用于展示商品 SKU 相关信息 -->
<el-table style="width: 100%;margin-top: 20px"
:data="value.skuStockList"
border>
<!-- 循环生成表格列根据 selectProductAttr 数组中的每个商品属性生成对应列用于展示每个 SKU 对应的属性值 -->
<el-table-column
v-for="(item,index) in selectProductAttr"
:label="item.name"
:key="item.id"
align="center">
<template slot-scope="scope">
{{getProductSkuSp(scope.row,index)}}
</template>
</el-table-column>
<!-- 表格列标签显示为销售价格宽度为 100px内容居中对齐内部使用输入框展示和编辑价格 -->
<el-table-column
label="销售价格"
width="100"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.price"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为促销价格宽度为 100px内容居中对齐内部使用输入框展示和编辑促销价格 -->
<el-table-column
label="促销价格"
width="100"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.promotionPrice"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为商品库存宽度为 80px内容居中对齐内部使用输入框展示和编辑库存数量 -->
<el-table-column
label="商品库存"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.stock"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为库存预警值宽度为 80px内容居中对齐内部使用输入框展示和编辑库存预警值 -->
<el-table-column
label="库存预警值"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.lowStock"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为SKU 编号宽度为 160px内容居中对齐内部使用输入框展示和编辑 SKU 编号 -->
<el-table-column
label="SKU 编号"
width="160"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.skuCode"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为 80px内容居中对齐内部包含删除按钮点击可删除对应行的 SKU 数据 -->
<el-table-column
label="操作"
width="80"
align="center">
<template slot-scope="scope">
<el-button
type="text"
@click="handleRemoveProductSku(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- el-button 按钮组件类型为主要按钮点击时触发 handleRefreshProductSkuList 方法用于刷新商品 SKU 列表 -->
<el-button
type="primary"
style="margin-top: 20px"
@click="handleRefreshProductSkuList">刷新列表
</el-button>
<!-- el-button 按钮组件类型为主要按钮点击时触发 handleSyncProductSkuPrice 方法用于同步商品 SKU 的价格 -->
<el-button
type="primary"
style="margin-top: 20px"
@click="handleSyncProductSkuPrice">同步价格
</el-button>
<!-- el-button 按钮组件类型为主要按钮点击时触发 handleSyncProductSkuStock 方法用于同步商品 SKU 的库存 -->
<el-button
type="primary"
style="margin-top: 20px"
@click="handleSyncProductSkuStock">同步库存
</el-button>
</el-form-item>
<!-- 根据 hasAttrPic 计算属性判断是否显示商品属性图片相关内容只有当有属性图片时才展示 -->
<el-form-item label="属性图片:" v-if="hasAttrPic">
<!-- el-card 卡片组件设置阴影效果为无添加了自定义类名 cardBg用于对商品属性图片部分进行布局划分 -->
<el-card shadow="never" class="cardBg">
<!-- 循环遍历 selectProductAttrPics 数组展示每个商品属性图片相关内容使用 single-upload 组件上传图片 -->
<div v-for="(item,index) in selectProductAttrPics">
<span>{{item.name}}:</span>
<single-upload v-model="item.pic"
style="width: 300px;display: inline-block;margin-left: 10px"></single-upload>
</div>
</el-card>
</el-form-item>
<!-- 表单项标签显示为商品参数用于展示和编辑商品参数相关内容 -->
<el-form-item label="商品参数:">
<!-- el-card 卡片组件设置阴影效果为无添加了自定义类名 cardBg用于对商品参数部分进行布局划分 -->
<el-card shadow="never" class="cardBg">
<!-- 循环遍历 selectProductParam 数组展示每个商品参数相关内容根据输入类型选择不同的输入组件展示和编辑参数值 -->
<div v-for="(item,index) in selectProductParam" :class="{littleMarginTop:index!==0}">
<div class="paramInputLabel">{{item.name}}:</div>
<el-select v-if="item.inputType===1" class="paramInput" v-model="selectProductParam[index].value">
<el-option
v-for="item in getParamInputList(item.inputList)"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
<el-input v-else class="paramInput" v-model="selectProductParam[index].value"></el-input>
</div>
</el-card>
</el-form-item>
<!-- 表单项标签显示为商品相册使用 multi-upload 组件用于上传商品的相册图片 -->
<el-form-item label="商品相册:">
<multi-upload v-model="selectProductPics"></multi-upload>
</el-form-item>
<!-- 表单项标签显示为商品详情使用 el-tabs 选项卡组件展示电脑端和移动端的商品详情分别使用 tinymce 富文本编辑器进行编辑 -->
<el-form-item label="商品详情:">
<el-tabs v-model="activeHtmlName" type="card">
<el-tab-pane label="电脑端详情" name="pc">
<tinymce :width="595" :height="300" v-model="value.detailHtml"></tinymce>
</el-tab-pane>
<el-tab-pane label="移动端详情" name="mobile">
<tinymce :width="595" :height="300" v-model="value.detailMobileHtml"></tinymce>
</el-tab-pane>
</el-tabs>
</el-form-item>
<!-- 表单项用于放置操作按钮设置文本居中对齐包含上一步下一步按钮点击分别触发对应的方法 -->
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleNext"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// @/api/productAttrCate fetchList fetchProductAttrCateList
import {fetchList as fetchProductAttrCateList} from '@/api/productAttrCate'
// @/api/productAttr fetchList fetchProductAttrList
import {fetchList as fetchProductAttrList} from '@/api/productAttr'
// SingleUpload
import SingleUpload from '@/api/SingleUpload'
// MultiUpload
import MultiUpload from '@/api/MultiUpload'
// Tinymce
import Tinymce from '@/api/Tinymce'
export default
name: "ProductAttrDetail",
components: {SingleUpload, MultiUpload, Tinymce},
props: {
// value
value: Object,
// isEdit false
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
// false
hasEditCreated: false,
//
productAttributeCategoryOptions: [],
//
selectProductAttr: [],
//
selectProductParam: [],
//
selectProductAttrPics: [],
//
addProductAttrValue: '',
// 'pc'
activeHtmlName: 'pc'
}
},
computed: {
// selectProductAttrPics
hasAttrPic() {
if (this.selectProductAttrPics.length < 1) {
return false;
}
return true;
},
// value
productId() {
return this.value.id;
},
// value
selectProductPics: {
get: function () {
let pics = [];
if (this.value.pic === undefined || this.value.pic == null || this.value.pic === '') {
return pics;
}
pics.push(this.value.pic);
if (this.value.albumPics === undefined || this.value.albumPics == null || this.value.albumPics === '') {
return pics;
}
let albumPics = this.value.albumPics.split(',');
for (let i = 0; i < albumPics.length; i++) {
pics.push(albumPics[i]);
}
return pics;
},
set: function (newValue) {
if (newValue == null || newValue.length === 0) {
this.value.pic = null;
this.value.albumPics = null;
} else {
this.value.pic = newValue[0];
this.value.albumPics = '';
if (newValue.length > 1) {
for (let i = 1; i < newValue.length; i++) {
this.value.albumPics += newValue[i];
if (i!== newValue.length - 1) {
this.value.albumPics += ',';
}
}
}
}
}
}
},
created() {
// getProductAttrCateList
this.getProductAttrCateList();
},
watch: {
productId: function (newValue) {
//
if (!this.isEdit) return;
//
if (this.hasEditCreated) return;
// undefinednull 0
if (newValue === undefined || newValue == null || newValue === 0) return;
// handleEditCreated
this.handleEditCreated();
}
},
methods:
handleEditCreated() {
// id id
if (this.value.productAttributeCategoryId!= null) {
this.handleProductAttrChange(this.value.productAttributeCategoryId);
}
// true
this.hasEditCreated = true;
},
getProductAttrCateList()

@ -1,396 +0,0 @@
<template> 
<el-card class="form-container" shadow="never">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="填写商品信息"></el-step>
<el-step title="填写商品促销"></el-step>
<el-step title="填写商品属性"></el-step>
<el-step title="选择商品关联"></el-step>
</el-steps>
<product-info-detail
v-show="showStatus[0]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep">
</product-info-detail>
<product-sale-detail
v-show="showStatus[1]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep"
@prevStep="prevStep">
</product-sale-detail>
<product-attr-detail
v-show="showStatus[2]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep"
@prevStep="prevStep">
</product-attr-detail>
<product-relation-detail
v-show="showStatus[3]"
v-model="productParam"
:is-edit="isEdit"
@prevStep="prevStep"
@finishCommit="finishCommit">
</product-relation-detail>
</el-card>
</template>
<script>
import ProductInfoDetail from './ProductInfoDetail';
import ProductSaleDetail from './ProductSaleDetail';
import ProductAttrDetail from './ProductAttrDetail';
import ProductRelationDetail from './ProductRelationDetail';
import {createProduct,getProduct,updateProduct} from '@/api/product';
const defaultProductParam = {
albumPics: '',
brandId: null,
brandName: '',
deleteStatus: 0,
description: '',
detailDesc: '',
detailHtml: '',
detailMobileHtml: '',
detailTitle: '',
feightTemplateId: 0,
flashPromotionCount: 0,
flashPromotionId: 0,
flashPromotionPrice: 0,
flashPromotionSort: 0,
giftPoint: 0,
giftGrowth: 0,
keywords: '',
lowStock: 0,
name: '',
newStatus: 0,
note: '',
originalPrice: 0,
pic: '',
//{memberLevelId: 0,memberPrice: 0,memberLevelName: null}
memberPriceList: [],
//
productFullReductionList: [{fullPrice: 0, reducePrice: 0}],
//
productLadderList: [{count: 0,discount: 0,price: 0}],
previewStatus: 0,
price: 0,
productAttributeCategoryId: null,
//{productAttributeId: 0, value: ''}
productAttributeValueList: [],
//sku{lowStock: 0, pic: '', price: 0, sale: 0, skuCode: '', spData: '', stock: 0}
skuStockList: [],
//{subjectId: 0}
subjectProductRelationList: [],
//{prefrenceAreaId: 0}
prefrenceAreaProductRelationList: [],
productCategoryId: null,
productCategoryName: '',
productSn: '',
promotionEndTime: '',
promotionPerLimit: 0,
promotionPrice: null,
promotionStartTime: '',
promotionType: 0,
publishStatus: 0,
recommandStatus: 0,
sale: 0,
serviceIds: '',
sort: 0,
stock: 0,
subTitle: '',
unit: '',
usePointLimit: 0,
verifyStatus: 0,
weight: 0
};
export default {
name: 'ProductDetail',
components: {ProductInfoDetail, ProductSaleDetail, ProductAttrDetail, ProductRelationDetail},
props: {
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
active: 0,
productParam: Object.assign({}, defaultProductParam),
showStatus: [true, false, false, false]
}
},
created(){
if(this.isEdit){
getProduct(this.$route.query.id).then(response=>{
this.productParam=response.data;
});
}
},
methods: {
hideAll() {
for (let i = 0; i < this.showStatus.length; i++) {
this.showStatus[i] = false;
}
},
prevStep() {
if (this.active > 0 && this.active < this.showStatus.length) {
this.active--;
this.hideAll();
this.showStatus[this.active] = true;
}
},
nextStep() {
if (this.active < this.showStatus.length - 1) {
this.active++;
this.hideAll();
this.showStatus[this.active] = true;
}
},
finishCommit(isEdit) {
this.$confirm('是否要提交该产品', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if(isEdit){
updateProduct(this.$route.query.id,this.productParam).then(response=>{
this.$message({
type: 'success',
message: '提交成功',
duration:1000
});
this.$router.back();
});
}else{
createProduct(this.productParam).then(response=>{
this.$message({
type: 'success',
message: '提交成功',
duration:1000
});
location.reload();
});
}
})
}
}
}
</script>
<style>
.form-container {
width: 960px;
}
.form-inner-container {
width: 800px;
}
</style>
#abc
<template>
<!-- 使用Element UI的el-card组件创建一个卡片式容器设置类名为form-container阴影效果为无用于对内部内容进行布局包裹 -->
<el-card class="form-container" shadow="never">
<!-- 使用Element UI的el-steps步骤条组件绑定:active属性用于控制当前激活的步骤设置完成状态的样式为success并且让步骤标题居中对齐 -->
<el-steps :active="active" finish-status="success" align-center>
<!-- 定义一个步骤标题为填写商品信息具体内容由对应的组件product-info-detail来填充 -->
<el-step title="填写商品信息"></el-step>
<!-- 定义一个步骤标题为填写商品促销具体内容由对应的组件product-sale-detail来填充 -->
<el-step title="填写商品促销"></el-step>
<!-- 定义一个步骤标题为填写商品属性具体内容由对应的组件product-attr-detail来填充 -->
<el-step title="填写商品属性"></el-step>
<!-- 定义一个步骤标题为选择商品关联具体内容由对应的组件product-relation-detail来填充 -->
<el-step title="选择商品关联"></el-step>
</el-steps>
<!-- 使用product-info-detail组件通过v-show指令根据showStatus数组中对应索引的值来控制显示隐藏绑定v-model用于双向数据绑定传递is-edit属性并且监听nextStep事件 -->
<product-info-detail
v-show="showStatus[0]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep">
</product-info-detail>
<!-- 使用product-sale-detail组件通过v-show指令根据showStatus数组中对应索引的值来控制显示隐藏绑定v-model用于双向数据绑定传递is-edit属性并且监听nextStep和prevStep事件 -->
<product-sale-detail
v-show="showStatus[1]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep"
@prevStep="prevStep">
</product-sale-detail>
<!-- 使用product-attr-detail组件通过v-show指令根据showStatus数组中对应索引的值来控制显示隐藏绑定v-model用于双向数据绑定传递is-edit属性并且监听nextStep和prevStep事件 -->
<product-attr-detail
v-show="showStatus[2]"
v-model="productParam"
:is-edit="isEdit"
@nextStep="nextStep"
@prevStep="prevStep">
</product-attr-detail>
<!-- 使用product-relation-detail组件通过v-show指令根据showStatus数组中对应索引的值来控制显示隐藏绑定v-model用于双向数据绑定传递is-edit属性并且监听prevStep和finishCommit事件 -->
<product-relation-detail
v-show="showStatus[3]"
v-model="productParam"
:is-edit="isEdit"
@prevStep="prevStep"
@finishCommit="finishCommit">
</product-relation-detail>
</el-card>
</template>
<script>
// ProductInfoDetailVue
import ProductInfoDetail from './ProductInfoDetail';
// ProductSaleDetailVue
import ProductSaleDetail from './ProductSaleDetail';
// ProductAttrDetailVue
import ProductAttrDetail from './ProductAttrDetail';
// ProductRelationDetailVue
import ProductRelationDetail from './ProductRelationDetail';
// @/api/productcreateProductgetProductupdateProduct
import {createProduct, getProduct, updateProduct} from '@/api/product';
//
const defaultProductParam = {
albumPics: '',
brandId: null,
brandName: '',
deleteStatus: 0,
description: '',
detailDesc: '',
detailHtml: '',
detailMobileHtml: '',
detailTitle: '',
feightTemplateId: 0,
flashPromotionCount: 0,
flashPromotionId: 0,
flashPromotionPrice: 0,
flashPromotionSort: 0,
giftPoint: 0,
giftGrowth: 0,
keywords: '',
lowStock: 0,
name: '',
newStatus: 0,
note: '',
originalPrice: 0,
pic: '',
// ID
memberPriceList: [],
//
productFullReductionList: [{fullPrice: 0, reducePrice: 0}],
//
productLadderList: [{count: 0, discount: 0, price: 0}],
previewStatus: 0,
price: 0,
productAttributeCategoryId: null,
// ID
productAttributeValueList: [],
// SKUSKU
skuStockList: [],
// ID
subjectProductRelationList: [],
// ID
prefrenceAreaProductRelationList: [],
productCategoryId: null,
productCategoryName: '',
productSn: '',
promotionEndTime: '',
promotionPerLimit: 0,
promotionPrice: null,
promotionStartTime: '',
promotionType: 0,
publishStatus: 0,
recommandStatus: 0,
sale: 0,
serviceIds: '',
sort: 0,
stock: 0,
subTitle: '',
unit: '',
usePointLimit: 0,
verifyStatus: 0,
weight: 0
};
export default {
name: 'ProductDetail',
components: {ProductInfoDetail, ProductSaleDetail, ProductAttrDetail, ProductRelationDetail},
props: {
// isEditfalse
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
// 0
active: 0,
// Object.assign
productParam: Object.assign({}, defaultProductParam),
// true
showStatus: [true, false, false, false]
}
},
created() {
// isEdittruegetProductIDproductParam
if (this.isEdit) {
getProduct(this.$route.query.id).then(response => {
this.productParam = response.data;
});
}
},
methods: {
hideAll() {
// showStatusfalse
for (let i = 0; i < this.showStatus.length; i++) {
this.showStatus[i] = false;
}
},
prevStep() {
// 0退1hideAll
if (this.active > 0 && this.active < this.showStatus.length) {
this.active--;
this.hideAll();
this.showStatus[this.active] = true;
}
},
nextStep() {
// 11hideAll
if (this.active < this.showStatus.length - 1) {
this.active++;
this.hideAll();
this.showStatus[this.active] = true;
}
},
finishCommit(isEdit) {
// isEdit
this.$confirm('是否要提交该产品', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (isEdit) {
// isEdittrueupdateProductID
updateProduct(this.$route.query.id, this.productParam).then(response => {
this.$message({
type: 'success',
message: '提交成功',
duration: 1000
});
this.$router.back();
});
} else {
// createProduct
createProduct(this.productParam).then(response => {
this.$message({
type: 'success',
message: '提交成功',
duration: 1000
});
location.reload();
});
}
})
}
}
}
</script>

@ -1,384 +0,0 @@
<template>
<div style="margin-top: 50px">
<el-form :model="value" :rules="rules" ref="productInfoForm" label-width="120px" class="form-inner-container" size="small">
<el-form-item label="商品分类:" prop="productCategoryId">
<el-cascader
v-model="selectProductCateValue"
:options="productCateOptions">
</el-cascader>
</el-form-item>
<el-form-item label="商品名称:" prop="name">
<el-input v-model="value.name"></el-input>
</el-form-item>
<el-form-item label="副标题:" prop="subTitle">
<el-input v-model="value.subTitle"></el-input>
</el-form-item>
<el-form-item label="商品品牌:" prop="brandId">
<el-select
v-model="value.brandId"
@change="handleBrandChange"
placeholder="请选择品牌">
<el-option
v-for="item in brandOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="商品介绍:">
<el-input
:autoSize="true"
v-model="value.description"
type="textarea"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item label="商品货号:">
<el-input v-model="value.productSn"></el-input>
</el-form-item>
<el-form-item label="商品售价:">
<el-input v-model="value.price"></el-input>
</el-form-item>
<el-form-item label="市场价:">
<el-input v-model="value.originalPrice"></el-input>
</el-form-item>
<el-form-item label="商品库存:">
<el-input v-model="value.stock"></el-input>
</el-form-item>
<el-form-item label="计量单位:">
<el-input v-model="value.unit"></el-input>
</el-form-item>
<el-form-item label="商品重量:">
<el-input v-model="value.weight" style="width: 300px"></el-input>
<span style="margin-left: 20px"></span>
</el-form-item>
<el-form-item label="排序">
<el-input v-model="value.sort"></el-input>
</el-form-item>
<el-form-item style="text-align: center">
<el-button type="primary" size="medium" @click="handleNext('productInfoForm')"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {fetchListWithChildren} from '@/api/productCate'
import {fetchList as fetchBrandList} from '@/api/brand'
import {getProduct} from '@/api/product';
export default {
name: "ProductInfoDetail",
props: {
value: Object,
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
hasEditCreated:false,
//
selectProductCateValue: [],
productCateOptions: [],
brandOptions: [],
rules: {
name: [
{required: true, message: '请输入商品名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
],
subTitle: [{required: true, message: '请输入商品副标题', trigger: 'blur'}],
productCategoryId: [{required: true, message: '请选择商品分类', trigger: 'blur'}],
brandId: [{required: true, message: '请选择商品品牌', trigger: 'blur'}],
description: [{required: true, message: '请输入商品介绍', trigger: 'blur'}],
requiredProp: [{required: true, message: '该项为必填项', trigger: 'blur'}]
}
};
},
created() {
this.getProductCateList();
this.getBrandList();
},
computed:{
//
productId(){
return this.value.id;
}
},
watch: {
productId:function(newValue){
if(!this.isEdit)return;
if(this.hasEditCreated)return;
if(newValue===undefined||newValue==null||newValue===0)return;
this.handleEditCreated();
},
selectProductCateValue: function (newValue) {
if (newValue != null && newValue.length === 2) {
this.value.productCategoryId = newValue[1];
this.value.productCategoryName= this.getCateNameById(this.value.productCategoryId);
} else {
this.value.productCategoryId = null;
this.value.productCategoryName=null;
}
}
},
methods: {
//
handleEditCreated(){
if(this.value.productCategoryId!=null){
this.selectProductCateValue.push(this.value.cateParentId);
this.selectProductCateValue.push(this.value.productCategoryId);
}
this.hasEditCreated=true;
},
getProductCateList() {
fetchListWithChildren().then(response => {
let list = response.data;
this.productCateOptions = [];
for (let i = 0; i < list.length; i++) {
let children = [];
if (list[i].children != null && list[i].children.length > 0) {
for (let j = 0; j < list[i].children.length; j++) {
children.push({label: list[i].children[j].name, value: list[i].children[j].id});
}
}
this.productCateOptions.push({label: list[i].name, value: list[i].id, children: children});
}
});
},
getBrandList() {
fetchBrandList({pageNum: 1, pageSize: 100}).then(response => {
this.brandOptions = [];
let brandList = response.data.list;
for (let i = 0; i < brandList.length; i++) {
this.brandOptions.push({label: brandList[i].name, value: brandList[i].id});
}
});
},
getCateNameById(id){
let name=null;
for(let i=0;i<this.productCateOptions.length;i++){
for(let j=0;j<this.productCateOptions[i].children.length;j++){
if(this.productCateOptions[i].children[j].value===id){
name=this.productCateOptions[i].children[j].label;
return name;
}
}
}
return name;
},
handleNext(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
this.$emit('nextStep');
} else {
this.$message({
message: '验证失败',
type: 'error',
duration:1000
});
return false;
}
});
},
handleBrandChange(val) {
let brandName = '';
for (let i = 0; i < this.brandOptions.length; i++) {
if (this.brandOptions[i].value === val) {
brandName = this.brandOptions[i].label;
break;
}
}
this.value.brandName = brandName;
}
}
}
</script>
<style scoped>
</style>
#abc
<template>
<!-- 外层的 div 元素设置了距离顶部 50px margin用于在页面布局上与其他元素产生间隔 -->
<div style="margin-top: 50px">
<!-- el-form 表单组件用于收集和验证商品相关信息绑定数据模型为 value关联验证规则 rules设置了表单引用名标签宽度类名以及尺寸为小 -->
<el-form :model="value" :rules="rules" ref="productInfoForm" label-width="120px" class="form-inner-container" size="small">
<!-- 表单项标签显示为商品分类通过 prop 属性关联对应的验证规则用于选择商品分类 -->
<el-form-item label="商品分类:" prop="productCategoryId">
<!-- el-cascader 级联选择器组件绑定 v-model selectProductCateValue其选项数据由 productCateOptions 提供用于选择多级的商品分类 -->
<el-cascader
v-model="selectProductCateValue"
:options="productCateOptions">
</el-cascader>
</el-form-item>
<!-- 表单项标签显示为商品名称通过 prop 属性关联对应的验证规则内部使用输入框收集商品名称信息 -->
<el-form-item label="商品名称:" prop="name">
<el-input v-model="value.name"></el-input>
</el-form-item>
<!-- 表单项标签显示为副标题通过 prop 属性关联对应的验证规则内部使用输入框收集商品副标题信息 -->
<el-form-item label="副标题:" prop="subTitle">
<el-input v-model="value.subTitle"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品品牌通过 prop 属性关联对应的验证规则内部使用下拉选择框选择商品品牌并且监听 change 事件 -->
<el-form-item label="商品品牌:" prop="brandId">
<el-select
v-model="value.brandId"
@change="handleBrandChange"
placeholder="请选择品牌">
<!-- 通过循环生成下拉选项每个选项的标签和值根据 brandOptions 数组中的元素来确定 -->
<el-option
v-for="item in brandOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 表单项标签显示为商品介绍内部使用可自动调整大小的文本域输入框收集商品介绍信息 -->
<el-form-item label="商品介绍:">
<el-input
:autoSize="true"
v-model="value.description"
type="textarea"
placeholder="请输入内容"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品货号内部使用输入框收集商品货号信息 -->
<el-form-item label="商品货号:">
<el-input v-model="value.productSn"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品售价内部使用输入框收集商品售价信息 -->
<el-form-item label="商品售价:">
<el-input v-model="value.price"></el-input>
</el-form-item>
<!-- 表单项标签显示为市场价内部使用输入框收集商品市场价信息 -->
<el-form-item label="市场价:">
<el-input v-model="value.originalPrice"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品库存内部使用输入框收集商品库存信息 -->
<el-form-item label="商品库存:">
<el-input v-model="value.stock"></el-input>
</el-form-item>
<!-- 表单项标签显示为计量单位内部使用输入框收集商品计量单位信息 -->
<el-form-item label="计量单位:">
<el-input v-model="value.unit"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品重量内部使用输入框收集商品重量信息并在输入框右侧显示作为单位提示 -->
<el-form-item label="商品重量:">
<el-input v-model="value.weight" style="width: 300px"></el-input>
<span style="margin-left: 20px"></span>
</el-form-item>
<!-- 表单项标签显示为排序内部使用输入框收集商品排序相关信息 -->
<el-form-item label="排序">
<el-input v-model="value.sort"></el-input>
</el-form-item>
<!-- 表单项用于放置操作按钮设置文本居中对齐包含一个下一步按钮点击时触发 handleNext 方法并传入当前表单名称用于进入下一个填写商品促销的步骤 -->
<el-form-item style="text-align: center">
<el-button type="primary" size="medium" @click="handleNext('productInfoForm')"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// @/api/productCate fetchListWithChildren
import {fetchListWithChildren} from '@/api/productCate'
// @/api/brand fetchList fetchBrandList
import {fetchList as fetchBrandList} from '@/api/brand'
// @/api/product getProduct 使
import {getProduct} from '@/api/product';
export default
name: "ProductInfoDetail",
props: {
// value 便
value: Object,
// isEdit false
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
// false
hasEditCreated: false,
//
selectProductCateValue: [],
// ID
productCateOptions: [],
// ID
brandOptions: [],
//
rules: {
name: [
//
{required: true, message: '请输入商品名称', trigger: 'blur'},
// 2 140 2 140
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
],
subTitle: [
//
{required: true, message: '请输入商品副标题', trigger: 'blur'}
],
productCategoryId: [
//
{required: true, message: '请选择商品分类', trigger: 'blur'}
],
brandId: [
//
{required: true, message: '请选择商品品牌', trigger: 'blur'}
],
description: [
//
{required: true, message: '请输入商品介绍', trigger: 'blur'}
],
requiredProp: [
//
{required: true, message: '该项为必填项', trigger: 'blur'}
]
}
};
},
created() {
// getProductCateList getBrandList
this.getProductCateList();
this.getBrandList();
},
computed: {
// value id undefined
productId() {
return this.value.id;
}
},
watch: {
productId: function (newValue) {
//
if (!this.isEdit) return;
//
if (this.hasEditCreated) return;
// undefinednull 0
if (newValue === undefined || newValue == null || newValue === 0) return;
// handleEditCreated
this.handleEditCreated();
},
selectProductCateValue: function (newValue) {
// null 2
if (newValue!= null && newValue.length === 2) {
// ID ID
this.value.productCategoryId = newValue[1];
// getCateNameById
this.value.productCategoryName = this.getCateNameById(this.value.productCategoryId);
} else {
// ID null
this.value.productCategoryId = null;
this.value.productCategoryName = null;
}
}
},
methods:
//
handleEditCreated()
if (this.value.productCategoryId!= null)
//

@ -1,310 +0,0 @@
<template>
<div style="margin-top: 50px">
<el-form :model="value"
ref="productRelationForm"
label-width="120px"
class="form-inner-container"
size="small">
<el-form-item label="关联专题:">
<el-transfer
style="display: inline-block"
filterable
:filter-method="filterMethod"
filter-placeholder="请输入专题名称"
v-model="selectSubject"
:titles="subjectTitles"
:data="subjectList">
</el-transfer>
</el-form-item>
<el-form-item label="关联优选:">
<el-transfer
style="display: inline-block"
filterable
:filter-method="filterMethod"
filter-placeholder="请输入优选名称"
v-model="selectPrefrenceArea"
:titles="prefrenceAreaTitles"
:data="prefrenceAreaList">
</el-transfer>
</el-form-item>
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleFinishCommit"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {fetchListAll as fetchSubjectList} from '@/api/subject'
import {fetchList as fetchPrefrenceAreaList} from '@/api/prefrenceArea'
export default {
name: "ProductRelationDetail",
props: {
value: Object,
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
//
subjectList: [],
//
subjectTitles: ['待选择', '已选择'],
//
prefrenceAreaList: [],
//
prefrenceAreaTitles: ['待选择', '已选择']
};
},
created() {
this.getSubjectList();
this.getPrefrenceAreaList();
},
computed:{
//
selectSubject:{
get:function () {
let subjects =[];
if(this.value.subjectProductRelationList==null||this.value.subjectProductRelationList.length<=0){
return subjects;
}
for(let i=0;i<this.value.subjectProductRelationList.length;i++){
subjects.push(this.value.subjectProductRelationList[i].subjectId);
}
return subjects;
},
set:function (newValue) {
this.value.subjectProductRelationList=[];
for(let i=0;i<newValue.length;i++){
this.value.subjectProductRelationList.push({subjectId:newValue[i]});
}
}
},
//
selectPrefrenceArea:{
get:function () {
let prefrenceAreas =[];
if(this.value.prefrenceAreaProductRelationList==null||this.value.prefrenceAreaProductRelationList.length<=0){
return prefrenceAreas;
}
for(let i=0;i<this.value.prefrenceAreaProductRelationList.length;i++){
prefrenceAreas.push(this.value.prefrenceAreaProductRelationList[i].prefrenceAreaId);
}
return prefrenceAreas;
},
set:function (newValue) {
this.value.prefrenceAreaProductRelationList=[];
for(let i=0;i<newValue.length;i++){
this.value.prefrenceAreaProductRelationList.push({prefrenceAreaId:newValue[i]});
}
}
}
},
methods: {
filterMethod(query, item) {
return item.label.indexOf(query) > -1;
},
getSubjectList() {
fetchSubjectList().then(response => {
let list = response.data;
for (let i = 0; i < list.length; i++) {
this.subjectList.push({
label: list[i].title,
key: list[i].id
});
}
});
},
getPrefrenceAreaList() {
fetchPrefrenceAreaList().then(response=>{
let list = response.data;
for (let i = 0; i < list.length; i++) {
this.prefrenceAreaList.push({
label: list[i].name,
key: list[i].id
});
}
});
},
handlePrev(){
this.$emit('prevStep')
},
handleFinishCommit(){
this.$emit('finishCommit',this.isEdit);
}
}
}
</script>
<style scoped>
</style>
#abc
<template>
<!-- 外层的 div 元素设置了距离顶部 50px margin用于在页面布局上与其他元素产生间隔 -->
<div style="margin-top: 50px">
<!-- el-form 表单组件用于收集和展示商品关联相关信息绑定数据模型为 value设置了表单引用名标签宽度类名以及尺寸为小 -->
<el-form :model="value"
ref="productRelationForm"
label-width="120px"
class="form-inner-container"
size="small">
<!-- 表单项标签显示为关联专题用于选择商品关联的专题信息 -->
<el-form-item label="关联专题:">
<!-- el-transfer 穿梭框组件设置为内联块级元素显示可进行过滤操作绑定过滤方法设置过滤占位提示文字双向绑定选中的数据指定左右标题以及数据源 -->
<el-transfer
style="display: inline-block"
filterable
:filter-method="filterMethod"
filter-placeholder="请输入专题名称"
v-model="selectSubject"
:titles="subjectTitles"
:data="subjectList">
</el-transfer>
</el-form-item>
<!-- 表单项标签显示为关联优选用于选择商品关联的优选信息 -->
<el-form-item label="关联优选:">
<!-- el-transfer 穿梭框组件设置为内联块级元素显示可进行过滤操作绑定过滤方法设置过滤占位提示文字双向绑定选中的数据指定左右标题以及数据源 -->
<el-transfer
style="display: inline-block"
filterable
:filter-method="filterMethod"
filter-placeholder="请输入优选名称"
v-model="selectPrefrenceArea"
:titles="prefrenceAreaTitles"
:data="prefrenceAreaList">
</el-transfer>
</el-form-item>
<!-- 表单项用于放置操作按钮设置文本居中对齐包含上一步完成提交商品按钮点击分别触发对应的方法 -->
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleFinishCommit"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// @/api/subject fetchListAll fetchSubjectList
import {fetchListAll as fetchSubjectList} from '@/api/subject'
// @/api/prefrenceArea fetchList fetchPrefrenceAreaList
import {fetchList as fetchPrefrenceAreaList} from '@/api/prefrenceArea'
export default {
name: "ProductRelationDetail",
props: {
// value 便
value: Object,
// isEdit false
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
// ID
subjectList: [],
// 穿穿
subjectTitles: ['待选择', '已选择'],
// ID
prefrenceAreaList: [],
// 穿穿
prefrenceAreaTitles: ['待选择', '已选择']
};
},
created() {
// getSubjectList getPrefrenceAreaList
this.getSubjectList();
this.getPrefrenceAreaList();
},
computed: {
// value subjectProductRelationList ID
selectSubject: {
get: function () {
let subjects = [];
if (this.value.subjectProductRelationList == null || this.value.subjectProductRelationList.length <= 0) {
return subjects;
}
for (let i = 0; i < this.value.subjectProductRelationList.length; i++) {
subjects.push(this.value.subjectProductRelationList[i].subjectId);
}
return subjects;
},
set: function (newValue) {
// value subjectProductRelationList ID
this.value.subjectProductRelationList = [];
for (let i = 0; i < newValue.length; i++) {
this.value.subjectProductRelationList.push({subjectId: newValue[i]});
}
}
},
// value prefrenceAreaProductRelationList ID
selectPrefrenceArea: {
get: function () {
let prefrenceAreas = [];
if (this.value.prefrenceAreaProductRelationList == null || this.value.prefrenceAreaProductRelationList.length <= 0) {
return prefrenceAreas;
}
for (let i = 0; i < this.value.prefrenceAreaProductRelationList.length; i++) {
prefrenceAreas.push(this.value.prefrenceAreaProductRelationList[i].prefrenceAreaId);
}
return prefrenceAreas;
},
set: function (newValue) {
// value prefrenceAreaProductRelationList ID
this.value.prefrenceAreaProductRelationList = [];
for (let i = 0; i < newValue.length; i++) {
this.value.prefrenceAreaProductRelationList.push({prefrenceAreaId: newValue[i]});
}
}
}
},
methods: {
// el-transfer 穿queryitem
filterMethod(query, item) {
return item.label.indexOf(query) > -1;
},
getSubjectList() {
// fetchSubjectList 穿使
fetchSubjectList().then(response => {
let list = response.data;
for (let i = 0; i < list.length; i++) {
this.subjectList.push({
label: list[i].title,
key: list[i].id
});
}
});
},
getPrefrenceAreaList() {
// fetchPrefrenceAreaList 穿使
fetchPrefrenceAreaList().then(response => {
let list = response.data;
for (let i = 0; i < list.length; i++) {
this.prefrenceAreaList.push({
label: list[i].name,
key: list[i].id
});
}
});
},
handlePrev() {
// prevStep 退
this.$emit('prevStep')
},
handleFinishCommit() {
// finishCommit isEdit
this.$emit('finishCommit', this.isEdit);
}
}
}
</script>
<style scoped>
/* 这里的样式部分设置了 scoped 属性,表示样式仅作用于当前组件内部的元素,目前为空,可根据组件的设计需求添加具体的样式规则,比如对表单内各元素、穿梭框等的样式调整,使其在页面中呈现出符合设计预期的外观效果 */
</style>

@ -1,601 +0,0 @@
<template>
<div style="margin-top: 50px">
<el-form :model="value" ref="productSaleForm" label-width="120px" class="form-inner-container" size="small">
<el-form-item label="赠送积分:">
<el-input v-model="value.giftPoint"></el-input>
</el-form-item>
<el-form-item label="赠送成长值:">
<el-input v-model="value.giftGrowth"></el-input>
</el-form-item>
<el-form-item label="积分购买限制:">
<el-input v-model="value.usePointLimit"></el-input>
</el-form-item>
<el-form-item label="预告商品:">
<el-switch
v-model="value.previewStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<el-form-item label="商品上架:">
<el-switch
v-model="value.publishStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<el-form-item label="商品推荐:">
<span style="margin-right: 10px">新品</span>
<el-switch
v-model="value.newStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
<span style="margin-left: 10px;margin-right: 10px">推荐</span>
<el-switch
v-model="value.recommandStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<el-form-item label="服务保证:">
<el-checkbox-group v-model="selectServiceList">
<el-checkbox :label="1">无忧退货</el-checkbox>
<el-checkbox :label="2">快速退款</el-checkbox>
<el-checkbox :label="3">免费包邮</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="详细页标题:">
<el-input v-model="value.detailTitle"></el-input>
</el-form-item>
<el-form-item label="详细页描述:">
<el-input v-model="value.detailDesc"></el-input>
</el-form-item>
<el-form-item label="商品关键字:">
<el-input v-model="value.keywords"></el-input>
</el-form-item>
<el-form-item label="商品备注:">
<el-input v-model="value.note" type="textarea" :autoSize="true"></el-input>
</el-form-item>
<el-form-item label="选择优惠方式:">
<el-radio-group v-model="value.promotionType" size="small">
<el-radio-button :label="0">无优惠</el-radio-button>
<el-radio-button :label="1">特惠促销</el-radio-button>
<el-radio-button :label="2">会员价格</el-radio-button>
<el-radio-button :label="3">阶梯价格</el-radio-button>
<el-radio-button :label="4">满减价格</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-show="value.promotionType===1">
<div>
开始时间
<el-date-picker
v-model="value.promotionStartTime"
type="datetime"
:picker-options="pickerOptions1"
placeholder="选择开始时间">
</el-date-picker>
</div>
<div class="littleMargin">
结束时间
<el-date-picker
v-model="value.promotionEndTime"
type="datetime"
:picker-options="pickerOptions1"
placeholder="选择结束时间">
</el-date-picker>
</div>
<div class="littleMargin">
促销价格
<el-input style="width: 220px" v-model="value.promotionPrice" placeholder="输入促销价格"></el-input>
</div>
</el-form-item>
<el-form-item v-show="value.promotionType===2">
<div v-for="(item, index) in value.memberPriceList" :class="{littleMargin:index!==0}">
{{item.memberLevelName}}
<el-input v-model="item.memberPrice" style="width: 200px"></el-input>
</div>
</el-form-item>
<el-form-item v-show="value.promotionType===3">
<el-table :data="value.productLadderList"
style="width: 80%" border>
<el-table-column
label="数量"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.count"></el-input>
</template>
</el-table-column>
<el-table-column
label="折扣"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.discount"></el-input>
</template>
</el-table-column>
<el-table-column
align="center"
label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleRemoveProductLadder(scope.$index, scope.row)">删除</el-button>
<el-button type="text" @click="handleAddProductLadder(scope.$index, scope.row)">添加</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item v-show="value.promotionType===4">
<el-table :data="value.productFullReductionList"
style="width: 80%" border>
<el-table-column
label="满"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.fullPrice"></el-input>
</template>
</el-table-column>
<el-table-column
label="立减"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.reducePrice"></el-input>
</template>
</el-table-column>
<el-table-column
align="center"
label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleRemoveFullReduction(scope.$index, scope.row)">删除</el-button>
<el-button type="text" @click="handleAddFullReduction(scope.$index, scope.row)">添加</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleNext"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {fetchList as fetchMemberLevelList} from '@/api/memberLevel'
export default {
name: "ProductSaleDetail",
props: {
value: Object,
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
//
pickerOptions1: {
disabledDate(time) {
return time.getTime() < Date.now();
}
}
}
},
created() {
if (this.isEdit) {
// this.handleEditCreated();
} else {
fetchMemberLevelList({defaultStatus: 0}).then(response => {
let memberPriceList = [];
for (let i = 0; i < response.data.length; i++) {
let item = response.data[i];
memberPriceList.push({memberLevelId: item.id, memberLevelName: item.name})
}
this.value.memberPriceList = memberPriceList;
});
}
},
computed: {
//
selectServiceList: {
get() {
let list = [];
if (this.value.serviceIds === undefined || this.value.serviceIds == null || this.value.serviceIds === '') return list;
let ids = this.value.serviceIds.split(',');
for (let i = 0; i < ids.length; i++) {
list.push(Number(ids[i]));
}
return list;
},
set(newValue) {
let serviceIds = '';
if (newValue != null && newValue.length > 0) {
for (let i = 0; i < newValue.length; i++) {
serviceIds += newValue[i] + ',';
}
if (serviceIds.endsWith(',')) {
serviceIds = serviceIds.substr(0, serviceIds.length - 1)
}
this.value.serviceIds = serviceIds;
} else {
this.value.serviceIds = null;
}
}
}
},
methods: {
handleEditCreated() {
let ids = this.value.serviceIds.split(',');
console.log('handleEditCreated', ids);
for (let i = 0; i < ids.length; i++) {
this.selectServiceList.push(Number(ids[i]));
}
},
handleRemoveProductLadder(index, row) {
let productLadderList = this.value.productLadderList;
if (productLadderList.length === 1) {
productLadderList.pop();
productLadderList.push({
count: 0,
discount: 0,
price: 0
})
} else {
productLadderList.splice(index, 1);
}
},
handleAddProductLadder(index, row) {
let productLadderList = this.value.productLadderList;
if (productLadderList.length < 3) {
productLadderList.push({
count: 0,
discount: 0,
price: 0
})
} else {
this.$message({
message: '最多只能添加三条',
type: 'warning'
});
}
},
handleRemoveFullReduction(index, row) {
let fullReductionList = this.value.productFullReductionList;
if (fullReductionList.length === 1) {
fullReductionList.pop();
fullReductionList.push({
fullPrice: 0,
reducePrice: 0
});
} else {
fullReductionList.splice(index, 1);
}
},
handleAddFullReduction(index, row) {
let fullReductionList = this.value.productFullReductionList;
if (fullReductionList.length < 3) {
fullReductionList.push({
fullPrice: 0,
reducePrice: 0
});
} else {
this.$message({
message: '最多只能添加三条',
type: 'warning'
});
}
},
handlePrev() {
this.$emit('prevStep')
},
handleNext() {
this.$emit('nextStep')
}
}
}
</script>
<style scoped>
.littleMargin {
margin-top: 10px;
}
</style>
#abc
<template>
<!-- 外层的 div 元素设置了距离顶部 50px margin用于在页面布局上与其他元素产生间隔 -->
<div style="margin-top: 50px">
<!-- el-form 表单组件用于收集和展示商品促销相关信息绑定数据模型为 value设置了表单引用名标签宽度类名以及尺寸为小 -->
<el-form :model="value" ref="productSaleForm" label-width="120px" class="form-inner-container" size="small">
<!-- 表单项标签显示为赠送积分内部使用输入框收集赠送积分的数量信息 -->
<el-form-item label="赠送积分:">
<el-input v-model="value.giftPoint"></el-input>
</el-form-item>
<!-- 表单项标签显示为赠送成长值内部使用输入框收集赠送成长值的数量信息 -->
<el-form-item label="赠送成长值:">
<el-input v-model="value.giftGrowth"></el-input>
</el-form-item>
<!-- 表单项标签显示为积分购买限制内部使用输入框收集积分购买限制的相关信息 -->
<el-form-item label="积分购买限制:">
<el-input v-model="value.usePointLimit"></el-input>
</el-form-item>
<!-- 表单项标签显示为预告商品内部使用 el-switch 开关组件来控制商品是否为预告状态通过设置不同的激活值和非激活值来表示开关的两种状态 -->
<el-form-item label="预告商品:">
<el-switch
v-model="value.previewStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<!-- 表单项标签显示为商品上架内部使用 el-switch 开关组件来控制商品是否上架通过设置不同的激活值和非激活值来表示开关的两种状态 -->
<el-form-item label="商品上架:">
<el-switch
v-model="value.publishStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<!-- 表单项标签显示为商品推荐包含多个开关组件分别用于控制商品是否为新品以及是否推荐通过设置不同的激活值和非激活值来表示开关的两种状态并在开关之间添加了文字提示间隔 -->
<el-form-item label="商品推荐:">
<span style="margin-right: 10px">新品</span>
<el-switch
v-model="value.newStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
<span style="margin-left: 10px;margin-right: 10px">推荐</span>
<el-switch
v-model="value.recommandStatus"
:active-value="1"
:inactive-value="0">
</el-switch>
</el-form-item>
<!-- 表单项标签显示为服务保证内部使用 el-checkbox-group 复选框组组件提供了几个固定的服务选项供用户选择用于选择商品的服务保证内容 -->
<el-form-item label="服务保证:">
<el-checkbox-group v-model="selectServiceList">
<el-checkbox :label="1">无忧退货</el-checkbox>
<el-checkbox :label="2">快速退款</el-checkbox>
<el-checkbox :label="3">免费包邮</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!-- 表单项标签显示为详细页标题内部使用输入框收集商品详细页标题信息 -->
<el-form-item label="详细页标题:">
<el-input v-model="value.detailTitle"></el-input>
</el-form-item>
<!-- 表单项标签显示为详细页描述内部使用输入框收集商品详细页描述信息 -->
<el-form-item label="详细页描述:">
<el-input v-model="value.detailDesc"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品关键字内部使用输入框收集商品关键字信息 -->
<el-form-item label="商品关键字:">
<el-input v-model="value.keywords"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品备注内部使用可自动调整大小的文本域输入框收集商品备注信息 -->
<el-form-item label="商品备注:">
<el-input v-model="value.note" type="textarea" :autoSize="true"></el-input>
</el-form-item>
<!-- 表单项标签显示为选择优惠方式内部使用 el-radio-group 单选框组组件提供了几种不同的优惠方式选项供用户选择用于确定商品采用的优惠方式 -->
<el-form-item label="选择优惠方式:">
<el-radio-group v-model="value.promotionType" size="small">
<el-radio-button :label="0">无优惠</el-radio-button>
<el-radio-button :label="1">特惠促销</el-radio-button>
<el-radio-button :label="2">会员价格</el-radio-button>
<el-radio-button :label="3">阶梯价格</el-radio-button>
<el-radio-button :label="4">满减价格</el-radio-button>
</el-radio-group>
</el-form-item>
<!-- 根据商品优惠方式promotionType的值判断是否显示当值为 1特惠促销时显示该部分内容用于设置特惠促销的相关时间和价格信息 -->
<el-form-item v-show="value.promotionType===1">
<div>
开始时间
<!-- el-date-picker 日期时间选择器组件绑定 v-model value.promotionStartTime设置选择器类型为 datetime关联日期禁用配置有占位提示文字用于选择特惠促销开始时间 -->
<el-date-picker
v-model="value.promotionStartTime"
type="datetime"
:picker-options="pickerOptions1"
placeholder="选择开始时间">
</el-date-picker>
</div>
<div class="littleMargin">
结束时间
<!-- el-date-picker 日期时间选择器组件绑定 v-model value.promotionEndTime设置选择器类型为 datetime关联日期禁用配置有占位提示文字用于选择特惠促销结束时间 -->
<el-date-picker
v-model="value.promotionEndTime"
type="datetime"
:picker-options="pickerOptions1"
placeholder="选择结束时间">
</el-date-picker>
</div>
<div class="littleMargin">
促销价格
<!-- 输入框组件设置宽度为 220px绑定 v-model value.promotionPrice有占位提示文字用于输入特惠促销价格 -->
<el-input style="width: 220px" v-model="value.promotionPrice" placeholder="输入促销价格"></el-input>
</div>
</el-form-item>
<!-- 根据商品优惠方式promotionType的值判断是否显示当值为 2会员价格时显示该部分内容通过循环展示每个会员等级对应的价格输入框用于设置不同会员等级的商品价格 -->
<el-form-item v-show="value.promotionType===2">
<div v-for="(item, index) in value.memberPriceList" :class="{littleMargin:index!==0}">
{{item.memberLevelName}}
<el-input v-model="item.memberPrice" style="width: 200px"></el-input>
</div>
</el-form-item>
<!-- 根据商品优惠方式promotionType的值判断是否显示当值为 3阶梯价格时显示该部分内容使用 el-table 表格组件展示和操作商品阶梯价格相关信息包含数量折扣等列以及添加删除操作按钮 -->
<el-form-item v-show="value.promotionType===3">
<el-table :data="value.productLadderList"
style="width: 80%" border>
<!-- 表格列标签显示为数量内容居中对齐宽度为 120px内部使用输入框展示和编辑阶梯价格对应的数量信息 -->
<el-table-column
label="数量"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.count"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为折扣内容居中对齐宽度为 120px内部使用输入框展示和编辑阶梯价格对应的折扣信息 -->
<el-table-column
label="折扣"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.discount"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为操作内容居中对齐内部包含删除和添加按钮点击可对当前行的阶梯价格数据进行相应操作 -->
<el-table-column
align="center"
label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleRemoveProductLadder(scope.$index, scope.row)">删除</el-button>
<el-button type="text" @click="handleAddProductLadder(scope.$index, scope.row)">添加</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 根据商品优惠方式promotionType的值判断是否显示当值为 4满减价格时显示该部分内容使用 el-table 表格组件展示和操作商品满减价格相关信息包含满减条件立减金额等列以及添加删除操作按钮 -->
<el-form-item v-show="value.promotionType===4">
<el-table :data="value.productFullReductionList"
style="width: 80%" border>
<!-- 表格列标签显示为内容居中对齐宽度为 120px内部使用输入框展示和编辑满减价格对应的满金额信息 -->
<el-table-column
label="满"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.fullPrice"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为立减内容居中对齐宽度为 120px内部使用输入框展示和编辑满减价格对应的立减金额信息 -->
<el-table-column
label="立减"
align="center"
width="120">
<template slot-scope="scope">
<el-input v-model="scope.row.reducePrice"></el-input>
</template>
</el-table-column>
<!-- 表格列标签显示为操作内容居中对齐内部包含删除和添加按钮点击可对当前行的满减价格数据进行相应操作 -->
<el-table-column
align="center"
label="操作">
<template slot-scope="scope">
<el-button type="text" @click="handleRemoveFullReduction(scope.$index, scope.row)">删除</el-button>
<el-button type="text" @click="handleAddFullReduction(scope.$index, scope.row)">添加</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<!-- 表单项用于放置操作按钮设置文本居中对齐包含上一步下一步按钮点击分别触发对应的方法用于在商品信息填写流程中进行步骤切换 -->
<el-form-item style="text-align: center">
<el-button size="medium" @click="handlePrev"></el-button>
<el-button type="primary" size="medium" @click="handleNext"></el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
// @/api/memberLevel fetchList fetchMemberLevelList
import {fetchList as fetchMemberLevelList} from '@/api/memberLevel'
export default
name: "ProductSaleDetail",
props: {
// value 便
value: Object,
// isEdit false
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
// disabledDate
pickerOptions1: {
disabledDate(time) {
return time.getTime() < Date.now();
}
}
};
},
created() {
if (this.isEdit) {
// handleEditCreated
// this.handleEditCreated();
} else {
// fetchMemberLevelList ID value.memberPriceList
fetchMemberLevelList({defaultStatus: 0}).then(response => {
let memberPriceList = [];
for (let i = 0; i < response.data.length; i++) {
let item = response.data[i];
memberPriceList.push({memberLevelId: item.id, memberLevelName: item.name})
}
this.value.memberPriceList = memberPriceList;
});
}
},
computed: {
// value.serviceIds 便
selectServiceList: {
get() {
let list = [];
if (this.value.serviceIds === undefined || this.value.serviceIds == null || this.value.serviceIds === '') return list;
let ids = this.value.serviceIds.split(',');
for (let i = 0; i < ids.length; i++) {
list.push(Number(ids[i]));
}
return list;
},
set(newValue) {
let serviceIds = '';
if (newValue!= null && newValue.length > 0) {
for (let i = 0; i < newValue.length; i++) {
serviceIds += newValue[i] + ',';
}
if (serviceIds.endsWith(',')) {
serviceIds = serviceIds.substr(0, serviceIds.length - 1)
}
this.value.serviceIds = serviceIds;
} else {
this.value.serviceIds = null;
}
}
}
},
methods:
handleEditCreated() {
let ids = this.value.serviceIds.split(',');
console.log('handleEditCreated', ids);
for (let i = 0; i < ids.length; i++) {
this.selectServiceList.push(Number(ids[i]));
}
},
handleRemoveProductLadder(index, row) {
let productLadderList = this.value.productLadderList;
// 0
if (productLadderList.length === 1) {
productLadderList.pop();
productLadderList.push({
count: 0,
discount: 0,
price: 0
})
} else {
//
productLadderList.splice(index, 1);
}
},
handleAddProductLadder(index, row)
let productLadderList = this.value.productLadderList;
// 3 0
if (productLadderList.length < 3)
productLadderList.push
count: 0,
discount:

@ -1,908 +0,0 @@
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float: right"
@click="handleSearchList()"
type="primary"
size="small">
查询结果
</el-button>
<el-button
style="float: right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="输入搜索:">
<el-input style="width: 203px" v-model="listQuery.keyword" placeholder="商品名称"></el-input>
</el-form-item>
<el-form-item label="商品货号:">
<el-input style="width: 203px" v-model="listQuery.productSn" placeholder="商品货号"></el-input>
</el-form-item>
<el-form-item label="商品分类:">
<el-cascader
clearable
v-model="selectProductCateValue"
:options="productCateOptions">
</el-cascader>
</el-form-item>
<el-form-item label="商品品牌:">
<el-select v-model="listQuery.brandId" placeholder="请选择品牌" clearable>
<el-option
v-for="item in brandOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="上架状态:">
<el-select v-model="listQuery.publishStatus" placeholder="全部" clearable>
<el-option
v-for="item in publishStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="审核状态:">
<el-select v-model="listQuery.verifyStatus" placeholder="全部" clearable>
<el-option
v-for="item in verifyStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button
class="btn-add"
@click="handleAddProduct()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="productTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<el-table-column type="selection" width="60" align="center"></el-table-column>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="商品图片" width="120" align="center">
<template slot-scope="scope"><img style="height: 80px" :src="scope.row.pic"></template>
</el-table-column>
<el-table-column label="商品名称" align="center">
<template slot-scope="scope">
<p>{{scope.row.name}}</p>
<p>品牌{{scope.row.brandName}}</p>
</template>
</el-table-column>
<el-table-column label="价格/货号" width="120" align="center">
<template slot-scope="scope">
<p>价格{{scope.row.price}}</p>
<p>货号{{scope.row.productSn}}</p>
</template>
</el-table-column>
<el-table-column label="标签" width="140" align="center">
<template slot-scope="scope">
<p>上架
<el-switch
@change="handlePublishStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.publishStatus">
</el-switch>
</p>
<p>新品
<el-switch
@change="handleNewStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.newStatus">
</el-switch>
</p>
<p>推荐
<el-switch
@change="handleRecommendStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.recommandStatus">
</el-switch>
</p>
</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<el-table-column label="SKU库存" width="100" align="center">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" @click="handleShowSkuEditDialog(scope.$index, scope.row)" circle></el-button>
</template>
</el-table-column>
<el-table-column label="销量" width="100" align="center">
<template slot-scope="scope">{{scope.row.sale}}</template>
</el-table-column>
<el-table-column label="审核状态" width="100" align="center">
<template slot-scope="scope">
<p>{{scope.row.verifyStatus | verifyStatusFilter}}</p>
<p>
<el-button
type="text"
@click="handleShowVerifyDetail(scope.$index, scope.row)">审核详情
</el-button>
</p>
</template>
</el-table-column>
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<p>
<el-button
size="mini"
@click="handleShowProduct(scope.$index, scope.row)">查看
</el-button>
<el-button
size="mini"
@click="handleUpdateProduct(scope.$index, scope.row)">编辑
</el-button>
</p>
<p>
<el-button
size="mini"
@click="handleShowLog(scope.$index, scope.row)">日志
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</p>
</template>
</el-table-column>
</el-table>
</div>
<div class="batch-operate-container">
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
<el-dialog
title="编辑货品信息"
:visible.sync="editSkuInfo.dialogVisible"
width="40%">
<span>商品货号</span>
<span>{{editSkuInfo.productSn}}</span>
<el-input placeholder="按sku编号搜索" v-model="editSkuInfo.keyword" size="small" style="width: 50%;margin-left: 20px">
<el-button slot="append" icon="el-icon-search" @click="handleSearchEditSku"></el-button>
</el-input>
<el-table style="width: 100%;margin-top: 20px"
:data="editSkuInfo.stockList"
border>
<el-table-column
label="SKU编号"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.skuCode"></el-input>
</template>
</el-table-column>
<el-table-column
v-for="(item,index) in editSkuInfo.productAttr"
:label="item.name"
:key="item.id"
align="center">
<template slot-scope="scope">
{{getProductSkuSp(scope.row,index)}}
</template>
</el-table-column>
<el-table-column
label="销售价格"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.price"></el-input>
</template>
</el-table-column>
<el-table-column
label="商品库存"
width="80"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.stock"></el-input>
</template>
</el-table-column>
<el-table-column
label="库存预警值"
width="100"
align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.lowStock"></el-input>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="editSkuInfo.dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleEditSkuConfirm"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {
fetchList,
updateDeleteStatus,
updateNewStatus,
updateRecommendStatus,
updatePublishStatus
} from '@/api/product'
import {fetchList as fetchSkuStockList,update as updateSkuStockList} from '@/api/skuStock'
import {fetchList as fetchProductAttrList} from '@/api/productAttr'
import {fetchList as fetchBrandList} from '@/api/brand'
import {fetchListWithChildren} from '@/api/productCate'
const defaultListQuery = {
keyword: null,
pageNum: 1,
pageSize: 5,
publishStatus: null,
verifyStatus: null,
productSn: null,
productCategoryId: null,
brandId: null
};
export default {
name: "productList",
data() {
return {
editSkuInfo:{
dialogVisible:false,
productId:null,
productSn:'',
productAttributeCategoryId:null,
stockList:[],
productAttr:[],
keyword:null
},
operates: [
{
label: "商品上架",
value: "publishOn"
},
{
label: "商品下架",
value: "publishOff"
},
{
label: "设为推荐",
value: "recommendOn"
},
{
label: "取消推荐",
value: "recommendOff"
},
{
label: "设为新品",
value: "newOn"
},
{
label: "取消新品",
value: "newOff"
},
{
label: "转移到分类",
value: "transferCategory"
},
{
label: "移入回收站",
value: "recycle"
}
],
operateType: null,
listQuery: Object.assign({}, defaultListQuery),
list: null,
total: null,
listLoading: true,
selectProductCateValue: null,
multipleSelection: [],
productCateOptions: [],
brandOptions: [],
publishStatusOptions: [{
value: 1,
label: '上架'
}, {
value: 0,
label: '下架'
}],
verifyStatusOptions: [{
value: 1,
label: '审核通过'
}, {
value: 0,
label: '未审核'
}]
}
},
created() {
this.getList();
this.getBrandList();
this.getProductCateList();
},
watch: {
selectProductCateValue: function (newValue) {
if (newValue != null && newValue.length == 2) {
this.listQuery.productCategoryId = newValue[1];
} else {
this.listQuery.productCategoryId = null;
}
}
},
filters: {
verifyStatusFilter(value) {
if (value === 1) {
return '审核通过';
} else {
return '未审核';
}
}
},
methods: {
getProductSkuSp(row, index) {
let spData = JSON.parse(row.spData);
if(spData!=null&&index<spData.length){
return spData[index].value;
}else{
return null;
}
},
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
getBrandList() {
fetchBrandList({pageNum: 1, pageSize: 100}).then(response => {
this.brandOptions = [];
let brandList = response.data.list;
for (let i = 0; i < brandList.length; i++) {
this.brandOptions.push({label: brandList[i].name, value: brandList[i].id});
}
});
},
getProductCateList() {
fetchListWithChildren().then(response => {
let list = response.data;
this.productCateOptions = [];
for (let i = 0; i < list.length; i++) {
let children = [];
if (list[i].children != null && list[i].children.length > 0) {
for (let j = 0; j < list[i].children.length; j++) {
children.push({label: list[i].children[j].name, value: list[i].children[j].id});
}
}
this.productCateOptions.push({label: list[i].name, value: list[i].id, children: children});
}
});
},
handleShowSkuEditDialog(index,row){
this.editSkuInfo.dialogVisible=true;
this.editSkuInfo.productId=row.id;
this.editSkuInfo.productSn=row.productSn;
this.editSkuInfo.productAttributeCategoryId = row.productAttributeCategoryId;
this.editSkuInfo.keyword=null;
fetchSkuStockList(row.id,{keyword:this.editSkuInfo.keyword}).then(response=>{
this.editSkuInfo.stockList=response.data;
});
if(row.productAttributeCategoryId!=null){
fetchProductAttrList(row.productAttributeCategoryId,{type:0}).then(response=>{
this.editSkuInfo.productAttr=response.data.list;
});
}
},
handleSearchEditSku(){
fetchSkuStockList(this.editSkuInfo.productId,{keyword:this.editSkuInfo.keyword}).then(response=>{
this.editSkuInfo.stockList=response.data;
});
},
handleEditSkuConfirm(){
if(this.editSkuInfo.stockList==null||this.editSkuInfo.stockList.length<=0){
this.$message({
message: '暂无sku信息',
type: 'warning',
duration: 1000
});
return
}
this.$confirm('是否要进行修改', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(()=>{
updateSkuStockList(this.editSkuInfo.productId,this.editSkuInfo.stockList).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
this.editSkuInfo.dialogVisible=false;
});
});
},
handleSearchList() {
this.listQuery.pageNum = 1;
this.getList();
},
handleAddProduct() {
this.$router.push({path:'/pms/addProduct'});
},
handleBatchOperate() {
if(this.operateType==null){
this.$message({
message: '请选择操作类型',
type: 'warning',
duration: 1000
});
return;
}
if(this.multipleSelection==null||this.multipleSelection.length<1){
this.$message({
message: '请选择要操作的商品',
type: 'warning',
duration: 1000
});
return;
}
this.$confirm('是否要进行该批量操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let ids=[];
for(let i=0;i<this.multipleSelection.length;i++){
ids.push(this.multipleSelection[i].id);
}
switch (this.operateType) {
case this.operates[0].value:
this.updatePublishStatus(1,ids);
break;
case this.operates[1].value:
this.updatePublishStatus(0,ids);
break;
case this.operates[2].value:
this.updateRecommendStatus(1,ids);
break;
case this.operates[3].value:
this.updateRecommendStatus(0,ids);
break;
case this.operates[4].value:
this.updateNewStatus(1,ids);
break;
case this.operates[5].value:
this.updateNewStatus(0,ids);
break;
case this.operates[6].value:
break;
case this.operates[7].value:
this.updateDeleteStatus(1,ids);
break;
default:
break;
}
this.getList();
});
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handlePublishStatusChange(index, row) {
let ids = [];
ids.push(row.id);
this.updatePublishStatus(row.publishStatus, ids);
},
handleNewStatusChange(index, row) {
let ids = [];
ids.push(row.id);
this.updateNewStatus(row.newStatus, ids);
},
handleRecommendStatusChange(index, row) {
let ids = [];
ids.push(row.id);
this.updateRecommendStatus(row.recommandStatus, ids);
},
handleResetSearch() {
this.selectProductCateValue = [];
this.listQuery = Object.assign({}, defaultListQuery);
},
handleDelete(index, row){
this.$confirm('是否要进行删除操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let ids = [];
ids.push(row.id);
this.updateDeleteStatus(1,ids);
});
},
handleUpdateProduct(index,row){
this.$router.push({path:'/pms/updateProduct',query:{id:row.id}});
},
handleShowProduct(index,row){
console.log("handleShowProduct",row);
},
handleShowVerifyDetail(index,row){
console.log("handleShowVerifyDetail",row);
},
handleShowLog(index,row){
console.log("handleShowLog",row);
},
updatePublishStatus(publishStatus, ids) {
let params = new URLSearchParams();
params.append('ids', ids);
params.append('publishStatus', publishStatus);
updatePublishStatus(params).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
updateNewStatus(newStatus, ids) {
let params = new URLSearchParams();
params.append('ids', ids);
params.append('newStatus', newStatus);
updateNewStatus(params).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
updateRecommendStatus(recommendStatus, ids) {
let params = new URLSearchParams();
params.append('ids', ids);
params.append('recommendStatus', recommendStatus);
updateRecommendStatus(params).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
updateDeleteStatus(deleteStatus, ids) {
let params = new URLSearchParams();
params.append('ids', ids);
params.append('deleteStatus', deleteStatus);
updateDeleteStatus(params).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
});
this.getList();
}
}
}
</script>
<style></style>
#abc
<template>
<!-- 最外层的 div 元素设置了类名为 `app-container`用于包裹整个页面内容作为整体布局的容器 -->
<div class="app-container">
<!-- 使用 Element UI `el-card` 组件创建一个卡片式容器类名为 `filter-container`设置阴影效果为无用于放置筛选搜索相关的内容 -->
<el-card class="filter-container" shadow="never">
<div>
<!-- 使用一个图标元素这里是 Element UI 的搜索图标用于在视觉上提示筛选搜索功能 -->
<i class="el-icon-search"></i>
<!-- 显示筛选搜索文字用于明确功能区域的用途 -->
<span>筛选搜索</span>
<!-- 使用 Element UI `el-button` 按钮组件设置样式为右浮动点击时触发 `handleSearchList` 方法按钮类型为主要按钮通常有突出显示效果尺寸为小用于执行查询结果的操作 -->
<el-button
style="float: right"
@click="handleSearchList()"
type="primary"
size="small">
查询结果
</el-button>
<!-- 使用 Element UI `el-button` 按钮组件设置样式为右浮动且与右侧有 15px 的间隔点击时触发 `handleResetSearch` 方法尺寸为小用于执行重置筛选条件的操作 -->
<el-button
style="float: right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<!-- 使用 Element UI `el-form` 表单组件设置表单为内联模式表单元素在一行显示绑定数据模型为 `listQuery`尺寸为小标签宽度为 140px用于放置各种筛选条件输入框 -->
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<!-- 表单项标签显示为输入搜索内部使用 `el-input` 输入框组件设置宽度为 203px双向绑定 `listQuery.keyword` 数据有占位提示文字商品名称用于输入搜索关键词按商品名称进行筛选 -->
<el-form-item label="输入搜索:">
<el-input style="width: 203px" v-model="listQuery.keyword" placeholder="商品名称"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品货号内部使用 `el-input` 输入框组件设置宽度为 203px双向绑定 `listQuery.productSn` 数据有占位提示文字商品货号用于输入商品货号进行筛选 -->
<el-form-item label="商品货号:">
<el-input style="width: 203px" v-model="listQuery.productSn" placeholder="商品货号"></el-input>
</el-form-item>
<!-- 表单项标签显示为商品分类内部使用 `el-cascader` 级联选择器组件设置可清除选择内容双向绑定 `selectProductCateValue` 数据其选项数据由 `productCateOptions` 提供用于选择商品分类进行筛选 -->
<el-form-item label="商品分类:">
<el-cascader
clearable
v-model="selectProductCateValue"
:options="productCateOptions">
</el-cascader>
</el-form-item>
<!-- 表单项标签显示为商品品牌内部使用 `el-select` 下拉选择框组件双向绑定 `listQuery.brandId` 数据有占位提示文字请选择品牌设置可清除选择内容其下拉选项通过循环 `brandOptions` 数组生成用于选择商品品牌进行筛选 -->
<el-form-item label="商品品牌:">
<el-select v-model="listQuery.brandId" placeholder="请选择品牌" clearable>
<el-option
v-for="item in brandOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 表单项标签显示为上架状态内部使用 `el-select` 下拉选择框组件双向绑定 `listQuery.publishStatus` 数据有占位提示文字全部设置可清除选择内容其下拉选项由 `publishStatusOptions` 数组提供用于选择商品上架状态进行筛选 -->
<el-form-item label="上架状态:">
<el-select v-model="listQuery.publishStatus" placeholder="全部" clearable>
<el-option
v-for="item in publishStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 表单项标签显示为审核状态内部使用 `el-select` 下拉选择框组件双向绑定 `listQuery.verifyStatus` 数据有占位提示文字全部设置可清除选择内容其下拉选项由 `verifyStatusOptions` 数组提供用于选择商品审核状态进行筛选 -->
<el-form-item label="审核状态:">
<el-select v-model="listQuery.verifyStatus" placeholder="全部" clearable>
<el-option
v-for="item in verifyStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</el-card>
<!-- 使用 Element UI `el-card` 组件创建一个卡片式容器类名为 `operate-container`设置阴影效果为无用于放置数据列表操作相关的内容 -->
<el-card class="operate-container" shadow="never">
<!-- 使用一个图标元素这里是 Element UI 的票务图标可能用于视觉上提示与数据操作相关的功能 -->
<i class="el-icon-tickets"></i>
<!-- 显示数据列表文字用于明确功能区域的用途 -->
<span>数据列表</span>
<!-- 使用 Element UI `el-button` 按钮组件设置类名为 `btn-add`点击时触发 `handleAddProduct` 方法尺寸为迷你型用于执行添加商品的操作 -->
<el-button
class="btn-add"
@click="handleAddProduct()"
size="mini">
添加
</el-button>
</el-card>
<!-- 一个 div 元素设置类名为 `table-container`用于包裹数据列表表格作为表格展示的容器 -->
<div class="table-container">
<!-- 使用 Element UI `el-table` 表格组件设置了表格引用名为 `productTable`绑定数据为 `list`宽度为 100%监听行选择变化事件 `selection-change` 并触发 `handleSelectionChange` 方法根据 `listLoading` 变量控制加载状态显示设置表格边框用于展示商品数据列表 -->
<el-table ref="productTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<!-- 表格列类型为选择列可勾选行宽度为 60px内容居中对齐用于选择表格中的行数据 -->
<el-table-column type="selection" width="60" align="center"></el-table-column>
<!-- 表格列标签显示为编号宽度为 100px内容居中对齐通过插槽作用域获取当前行数据展示商品编号信息 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列标签显示为商品图片宽度为 120px内容居中对齐通过插槽作用域获取当前行数据展示商品图片信息图片设置了高度为 80px -->
<el-table-column label="商品图片" width="120" align="center">
<template slot-scope="scope"><img style="height: 80px" :src="scope.row.pic"></template>
</el-table-column>
<!-- 表格列标签显示为商品名称内容居中对齐通过插槽作用域获取当前行数据展示商品名称以及品牌信息 -->
<el-table-column label="商品名称" align="center">
<template slot-scope="scope">
<p>{{scope.row.name}}</p>
<p>品牌{{scope.row.brandName}}</p>
</template>
</el-table-column>
<!-- 表格列标签显示为价格/货号宽度为 120px内容居中对齐通过插槽作用域获取当前行数据展示商品价格和货号信息 -->
<el-table-column label="价格/货号" width="120" align="center">
<template slot-scope="scope">
<p>价格{{scope.row.price}}</p>
<p>货号{{scope.row.productSn}}</p>
</template>
</el-table-column>
<!-- 表格列标签显示为标签宽度为 140px内容居中对齐通过插槽作用域获取当前行数据包含多个开关组件用于展示和操作商品的上架新品推荐等状态信息 -->
<el-table-column label="标签" width="140" align="center">
<template slot-scope="scope">
<p>上架
<!-- 使用 `el-switch` 开关组件监听开关状态变化事件 `change` 并触发对应的方法设置激活值和非激活值双向绑定当前行的 `publishStatus` 数据用于控制商品上架状态 -->
<el-switch
@change="handlePublishStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.publishStatus">
</el-switch>
</p>
<p>新品
<!-- 使用 `el-switch` 开关组件监听开关状态变化事件 `change` 并触发对应的方法设置激活值和非激活值双向绑定当前行的 `newStatus` 数据用于控制商品是否为新品状态 -->
<el-switch
@change="handleNewStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.newStatus">
</el-switch>
</p>
<p>推荐
<!-- 使用 `el-switch` 开关组件监听开关状态变化事件 `change` 并触发对应的方法设置激活值和非激活值双向绑定当前行的 `recommandStatus` 数据用于控制商品是否为推荐状态 -->
<el-switch
@change="handleRecommendStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.recommandStatus">
</el-switch>
</p>
</template>
</el-table-column>
<!-- 表格列标签显示为排序宽度为 100px内容居中对齐通过插槽作用域获取当前行数据展示商品排序信息 -->
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<!-- 表格列标签显示为SKU 库存宽度为 100px内容居中对齐通过插槽作用域获取当前行数据包含一个编辑按钮点击触发 `handleShowSkuEditDialog` 方法用于查看和编辑商品 SKU 库存信息 -->
<el-table-column label="SKU 库存" width="100" align="center">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" @click="handleShowSkuEditDialog(scope.$index, scope.row)" circle></el-button>
</template>
</el-table-column>
<!-- 表格列标签显示为销量宽度为 100px内容居中对齐通过插槽作用域获取当前行数据展示商品销量信息 -->
<el-table-column label="销量" width="100" align="center">
<template slot-scope="scope">{{scope.row.sale}}</template>
</el-table-column>
<!-- 表格列标签显示为审核状态宽度为 100px内容居中对齐通过插槽作用域获取当前行数据展示商品审核状态信息同时包含一个查看审核详情的按钮点击触发 `handleShowVerifyDetail` 方法 -->
<el-table-column label="审核状态" width="100" align="center">
<template slot-scope="scope">
<p>{{scope.row.verifyStatus | verifyStatusFilter}}</p>
<p>
<el-button
type="text"
@click="handleShowVerifyDetail(scope.$index, scope.row)">审核详情
</el-button>
</p>
</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为 160px内容居中对齐通过插槽作用域获取当前行数据包含多个操作按钮如查看编辑查看日志删除等分别触发对应的方法用于对商品进行各种操作 -->
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<p>
<el-button
size="mini"
@click="handleShowProduct(scope.$index, scope.row)">查看
</el-button>
<el-button
size="mini"
@click="handleUpdateProduct(scope.$index, scope.row)">编辑
</el-button>
</p>
<p>
<el-button
size="mini"
@click="handleShowLog(scope.$index, scope.row)">日志
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</p>
</template>
</el-table-column>
</el-table>
</div>
<!-- 一个 div 元素设置类名为 `batch-operate-container`用于放置批量操作相关的内容如选择批量操作类型和执行操作的按钮 -->
<div class="batch-operate-container">
<!-- 使用 Element UI `el-select` 下拉选择框组件尺寸为小双向绑定 `operateType` 数据有占位提示文字批量操作其下拉选项通过循环 `operates` 数组生成用于选择批量操作的类型 -->
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- 使用 Element UI `el-button` 按钮组件设置样式为左距 20px类名为 `search-button`点击时触发 `handleBatchOperate` 方法按钮类型为主要按钮通常有突出显示效果尺寸为小用于执行确定批量操作的动作 -->
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<!-- 一个 div 元素设置类名为 `pagination-container`用于包裹分页组件作为分页功能的容器 -->
<div class="pagination-container">
<!-- 使用 Element UI `el-pagination` 分页组件设置背景色样式监听页面尺寸变化和当前页变化事件并分别触发对应的方法设置分页布局样式绑定页面尺寸可选页面尺寸数组当前页码以及总数据量等数据用于实现数据列表的分页功能 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
<!-- 使用 Element UI `el-dialog` 对话框组件设置标题为编辑货品信息通过双向绑定控制对话框的显示隐藏状态宽度设置为 40%用于展示和编辑商品 SKU 库存相关的详细信息 -->
<el-dialog
title="编辑货品信息"
:visible.sync="editSkuInfo.dialogVisible"
width="40%">
<span>商品货号

@ -1,30 +0,0 @@
<template> 
<product-detail :is-edit='true'></product-detail>
</template>
<script>
import ProductDetail from './components/ProductDetail'
export default {
name: 'updateProduct',
components: { ProductDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 此处使用了名为 `product-detail` 的自定义组件通过 `:is-edit='true'` 属性绑定 `product-detail` 组件传递了一个名为 `is-edit` 的属性值为 `true`意味着当前是编辑商品的操作模式与新增商品模式相区别`product-detail` 组件应该会根据这个属性来展示相应的编辑界面以及执行对应的逻辑 -->
<product-detail :is-edit='true'></product-detail>
</template>
<script>
// `./components/` `ProductDetail`
import ProductDetail from './components/ProductDetail';
export default {
name: 'updateProduct',
// `components` `ProductDetail` 使`updateProduct`使 `<product-detail>` Vue.js 便使
components: { ProductDetail }
}
</script>
<style>
/* 这里的样式部分目前为空,可根据 `updateProduct` 组件整体的视觉呈现需求,添加相应的 CSS 样式规则,例如对整个组件布局进行调整,设置组件内各元素的字体、颜色、间距等样式属性,使其在页面中展现出符合预期的外观效果 */
</style>

@ -1,32 +0,0 @@
<template>
<product-attr-detail :is-edit='false'></product-attr-detail>
</template>
<script>
import ProductAttrDetail from './components/ProductAttrDetail'
export default {
name: 'addProductAttr',
components: { ProductAttrDetail }
}
</script>
<style scoped>
</style>
#abc
<template>
<!-- 使用名为 `product-attr-detail` 的自定义组件通过 `:is-edit='false'` 属性绑定向该组件传递了名为 `is-edit` 的属性值设为 `false`表示当前处于添加商品属性的操作模式区别于编辑商品属性模式`product-attr-detail` 组件会依据这个属性值来展示对应的界面以及执行相应的添加相关逻辑 -->
<product-attr-detail :is-edit='false'></product-attr-detail>
</template>
<script>
// `./components/` `ProductAttrDetail`
import ProductAttrDetail from './components/ProductAttrDetail';
export default {
name: 'addProductAttr',
// `components` `ProductAttrDetail` 使 `addProductAttr` `<product-attr-detail>` Vue.js 便
components: { ProductAttrDetail }
}
</script>
<style scoped>
/* 这里样式部分设置了 `scoped` 属性,意味着样式只会应用到当前组件内部的元素上。目前该部分样式为空,后续可以根据 `addProductAttr` 组件的视觉设计要求,添加对应的 CSS 样式规则,像设置组件内文本的字体、颜色,表单元素的布局、边框样式等,让组件在页面中呈现出期望的外观效果 */
</style>

@ -1,185 +0,0 @@
<template>
<el-card class="form-container" shadow="never">
<el-form :model="productAttr" :rules="rules" ref="productAttrFrom" label-width="150px">
<el-form-item label="属性名称:" prop="name">
<el-input v-model="productAttr.name"></el-input>
</el-form-item>
<el-form-item label="商品类型:">
<el-select v-model="productAttr.productAttributeCategoryId" placeholder="请选择">
<el-option
v-for="item in productAttrCateList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="分类筛选样式:">
<el-radio-group v-model="productAttr.filterType">
<el-radio :label="0">普通</el-radio>
<el-radio :label="1">颜色</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="能否进行检索:">
<el-radio-group v-model="productAttr.searchType">
<el-radio :label="0">不需要检索</el-radio>
<el-radio :label="1">关键字检索</el-radio>
<el-radio :label="2">范围检索</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品属性关联:">
<el-radio-group v-model="productAttr.relatedStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="属性是否可选:">
<el-radio-group v-model="productAttr.selectType">
<el-radio :label="0">唯一</el-radio>
<el-radio :label="1">单选</el-radio>
<el-radio :label="2">复选</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="属性值的录入方式:">
<el-radio-group v-model="productAttr.inputType">
<el-radio :label="0">手工录入</el-radio>
<el-radio :label="1">从下面列表中选择</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="属性值可选值列表:">
<el-input :autosize="true" type="textarea" v-model="inputListFormat"></el-input>
</el-form-item>
<el-form-item label="是否支持手动新增:">
<el-radio-group v-model="productAttr.handAddStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="排序属性:">
<el-input v-model="productAttr.sort"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('productAttrFrom')"></el-button>
<el-button v-if="!isEdit" @click="resetForm('productAttrFrom')"></el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
import {fetchList} from '@/api/productAttrCate'
import {createProductAttr,getProductAttr,updateProductAttr} from '@/api/productAttr'
const defaultProductAttr = {
filterType: 0,
handAddStatus: 0,
inputList: '',
inputType: 0,
name: '',
productAttributeCategoryId: 0,
relatedStatus: 0,
searchType: 0,
selectType: 0,
sort: 0,
type: 0
};
export default {
name: "ProductAttrDetail",
props: {
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
productAttr: Object.assign({}, defaultProductAttr),
rules: {
name: [
{required: true, message: '请输入属性名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
]
},
productAttrCateList: null,
inputListFormat:null
}
},
created() {
if(this.isEdit){
getProductAttr(this.$route.query.id).then(response => {
this.productAttr = response.data;
this.inputListFormat = this.productAttr.inputList.replace(/,/g,'\n');
});
}else{
this.resetProductAttr();
}
this.getCateList();
},
watch:{
inputListFormat: function (newValue, oldValue) {
newValue = newValue.replace(/\n/g,',');
this.productAttr.inputList = newValue;
}
},
methods: {
getCateList() {
let listQuery = {pageNum: 1, pageSize: 100};
fetchList(listQuery).then(response => {
this.productAttrCateList = response.data.list;
});
},
resetProductAttr() {
this.productAttr = Object.assign({}, defaultProductAttr);
this.productAttr.productAttributeCategoryId = Number(this.$route.query.cid);
this.productAttr.type = Number(this.$route.query.type);
},
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('是否提交数据', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if(this.isEdit){
updateProductAttr(this.$route.query.id,this.productAttr).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
this.$router.back();
});
}else{
createProductAttr(this.productAttr).then(response=>{
this.$message({
message: '提交成功',
type: 'success',
duration: 1000
});
this.resetForm('productAttrFrom');
});
}
});
} else {
this.$message({
message: '验证失败',
type: 'error',
duration: 1000
});
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.resetProductAttr();
}
},
}
</script>
<style scoped>
</style>

@ -1,463 +0,0 @@
<template> 
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button
class="btn-add"
@click="addProductAttrCate()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="productAttrCateTable"
style="width: 100%"
:data="list"
v-loading="listLoading"
border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="类型名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="属性数量" width="200" align="center">
<template slot-scope="scope">{{scope.row.attributeCount==null?0:scope.row.attributeCount}}</template>
</el-table-column>
<el-table-column label="参数数量" width="200" align="center">
<template slot-scope="scope">{{scope.row.paramCount==null?0:scope.row.paramCount}}</template>
</el-table-column>
<el-table-column label="设置" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="getAttrList(scope.$index, scope.row)">属性列表
</el-button>
<el-button
size="mini"
@click="getParamList(scope.$index, scope.row)">参数列表
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
:before-close="handleClose()"
width="30%">
<el-form ref="productAttrCatForm":model="productAttrCate" :rules="rules" label-width="120px">
<el-form-item label="类型名称" prop="name">
<el-input v-model="productAttrCate.name" auto-complete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleConfirm('productAttrCatForm')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {fetchList,createProductAttrCate,deleteProductAttrCate,updateProductAttrCate} from '@/api/productAttrCate'
export default {
name: 'productAttrCateList',
data() {
return {
list: null,
total: null,
listLoading: true,
listQuery: {
pageNum: 1,
pageSize: 5
},
dialogVisible: false,
dialogTitle:'',
productAttrCate:{
name:'',
id:null
},
rules: {
name: [
{ required: true, message: '请输入类型名称', trigger: 'blur' }
]
}
}
},
created() {
this.getList();
},
methods: {
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
addProductAttrCate() {
this.dialogVisible = true;
this.dialogTitle = "添加类型";
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleDelete(index, row) {
this.$confirm('是否要删除该品牌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProductAttrCate(row.id).then(response=>{
this.$message({
message: '删除成功',
type: 'success',
duration:1000
});
this.getList();
});
});
},
handleUpdate(index, row) {
this.dialogVisible = true;
this.dialogTitle = "编辑类型";
this.productAttrCate.name = row.name;
this.productAttrCate.id = row.id;
},
getAttrList(index, row) {
this.$router.push({path: '/pms/productAttrList',query:{cid:row.id,cname:row.name,type:0}})
},
getParamList(index, row) {
this.$router.push({path: '/pms/productAttrList',query:{cid:row.id,cname:row.name,type:1}})
},
handleConfirm(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
let data = new URLSearchParams();
data.append("name",this.productAttrCate.name);
if(this.dialogTitle==="添加类型"){
createProductAttrCate(data).then(response=>{
this.$message({
message: '添加成功',
type: 'success',
duration:1000
});
this.dialogVisible = false;
this.getList();
});
}else{
updateProductAttrCate(this.productAttrCate.id,data).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration:1000
});
this.dialogVisible = false;
this.getList();
});
}
} else {
console.log('error submit!!');
return false;
}
});
},
handleClose(){
if (!this.dialogVisible && this.$refs.productAttrCatForm) {
this.$refs.productAttrCatForm.clearValidate()
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
</style>
#abc
<template>
<!-- 最外层的 div 元素设置了类名为 `app-container`作为整个页面内容的容器用于整体布局和包裹内部的各个功能模块 -->
<div class="app-container">
<!-- 使用 Element UI `el-card` 组件创建一个卡片式容器类名为 `operate-container`设置阴影效果为无用于放置与数据列表操作相关的内容比如添加按钮等 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 Element UI 的图标组件展示票务图标并设置了距顶部 5px margin用于在视觉上提示与数据操作相关的功能起到一定的表意作用 -->
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<!-- 显示数据列表文字同样设置了距顶部 5px margin用于明确此卡片容器内操作主要针对的数据列表功能区域 -->
<span style="margin-top: 5px">数据列表</span>
<!-- 使用 Element UI `el-button` 按钮组件设置类名为 `btn-add`点击时触发 `addProductAttrCate` 方法尺寸为迷你型用于执行添加商品属性分类的操作 -->
<el-button
class="btn-add"
@click="addProductAttrCate()"
size="mini">
添加
</el-button>
</el-card>
<!-- 一个 div 元素设置类名为 `table-container`作为表格展示的容器用于包裹下面的 `el-table` 组件呈现数据列表内容 -->
<div class="table-container">
<!-- 使用 Element UI `el-table` 表格组件设置了表格引用名为 `productAttrCateTable`宽度为 100%绑定数据为 `list`根据 `listLoading` 变量控制加载状态显示设置表格边框用于展示商品属性分类相关的数据列表 -->
<el-table ref="productAttrCateTable"
style="width: 100%"
:data="list"
v-loading="listLoading"
border>
<!-- 表格列标签显示为编号宽度为 100px内容居中对齐通过插槽作用域获取当前行数据展示商品属性分类的编号信息 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列标签显示为类型名称内容居中对齐通过插槽作用域获取当前行数据展示商品属性分类的类型名称信息 -->
<el-table-column label="类型名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列标签显示为属性数量宽度为 200px内容居中对齐通过插槽作用域获取当前行数据展示商品属性分类对应的属性数量信息如果数量为 `null`则显示为 0 -->
<el-table-column label="属性数量" width="200" align="center">
<template slot-scope="scope">{{scope.row.attributeCount==null?0:scope.row.attributeCount}}</template>
</el-table-column>
<!-- 表格列标签显示为参数数量宽度为 200px内容居中对齐通过插槽作用域获取当前行数据展示商品属性分类对应的参数数量信息如果数量为 `null`则显示为 0 -->
<el-table-column label="参数数量" width="200" align="center">
<template slot-scope="scope">{{scope.row.paramCount==null?0:scope.row.paramCount}}</template>
</el-table-column>
<!-- 表格列标签显示为设置宽度为 200px内容居中对齐通过插槽作用域获取当前行数据包含两个按钮分别点击可跳转到对应的属性列表和参数列表页面用于查看相应详细信息 -->
<el-table-column label="设置" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="getAttrList(scope.$index, scope.row)">属性列表
</el-button>
<el-button
size="mini"
@click="getParamList(scope.$index, scope.row)">参数列表
</el-button>
</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为 200px内容居中对齐通过插槽作用域获取当前行数据包含编辑和删除两个按钮分别点击可触发对应的编辑和删除操作方法 -->
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 一个 div 元素设置类名为 `pagination-container`用于包裹分页组件作为分页功能的容器 -->
<div class="pagination-container">
<!-- 使用 Element UI `el-pagination` 分页组件设置背景色样式监听页面尺寸变化和当前页变化事件并分别触发对应的方法设置分页布局样式绑定页面尺寸可选页面尺寸数组当前页码以及总数据量等数据用于实现数据列表的分页功能 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
<!-- 使用 Element UI `el-dialog` 对话框组件通过双向绑定控制对话框的标题显示隐藏状态以及关闭前的操作宽度设置为 30%用于弹出添加或编辑商品属性分类的表单界面 -->
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
:before-close="handleClose()"
width="30%">
<!-- 使用 Element UI `el-form` 表单组件设置了表单引用名绑定数据模型为 `productAttrCate`关联表单验证规则 `rules`标签宽度为 120px用于放置添加或编辑商品属性分类的输入框等表单元素 -->
<el-form ref="productAttrCatForm":model="productAttrCate" :rules="rules" label-width="120px">
<!-- 表单项标签显示为类型名称指定了验证属性 `prop` `name`内部使用 `el-input` 输入框组件双向绑定 `productAttrCate.name` 数据设置自动补全功能为关闭用于输入商品属性分类的名称 -->
<el-form-item label="类型名称" prop="name">
<el-input v-model="productAttrCate.name" auto-complete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<!-- 使用 Element UI `el-button` 按钮组件点击时隐藏对话框用于取消添加或编辑操作 -->
<el-button @click="dialogVisible = false"> </el-button>
<!-- 使用 Element UI `el-button` 按钮组件点击时触发 `handleConfirm` 方法并传入表单引用名按钮类型为主要按钮通常有突出显示效果用于确认添加或编辑操作 -->
<el-button type="primary" @click="handleConfirm('productAttrCatForm')"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// `@/api/productAttrCate` API
import {fetchList,createProductAttrCate,deleteProductAttrCate,updateProductAttrCate} from '@/api/productAttrCate';
export default {
name: 'productAttrCateList',
data() {
return {
// `null`
list: null,
// `null`
total: null,
// `true` `false`
listLoading: true,
//
listQuery: {
pageNum: 1,
pageSize: 5
},
// `false`
dialogVisible: false,
//
dialogTitle: '',
// IDID `null`
productAttrCate: {
name: '',
id: null
},
// `name` `blur`
rules: {
name: [
{ required: true, message: '请输入类型名称', trigger: 'blur' }
]
}
};
},
created() {
// `getList`
this.getList();
},
methods: {
getList() {
// `listLoading` `true`
this.listLoading = true;
// `fetchList` `listQuery` `listLoading` `false` `list` `total`
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
addProductAttrCate() {
// `dialogVisible` `true`使 `dialogTitle`
this.dialogVisible = true;
this.dialogTitle = "添加类型";
},
handleSizeChange(val) {
// `listQuery` `pageNum` 1 `pageSize` `val` `getList`
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
// `listQuery` `pageNum` `val` `getList`
this.listQuery.pageNum = val;
this.getList();
},
handleDelete(index, row) {
// `deleteProductAttrCate` `id` `getList`
this.$confirm('是否要删除该品牌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProductAttrCate(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
},
handleUpdate(index, row) {
// `dialogVisible` `true`使 `dialogTitle` ID `productAttrCate`
this.dialogVisible = true;
this.dialogTitle = "编辑类型";
this.productAttrCate.name = row.name;
this.productAttrCate.id = row.id;
},
getAttrList(index, row) {
// `$router.push` `/pms/productAttrList` `cid` ID`cname` `type` 0
this.$router.push({path: '/pms/productAttrList',query:{cid:row.id,cname:row.name,type:0}})
},
getParamList(index, row) {
// `$router.push` `/pms/productAttrList` `cid` ID`cname` `type` 1
this.$router.push({path: '/pms/productAttrList',query:{cid:row.id,cname:row.name,type:1}})
},
handleConfirm(formName) {
// `$refs[formName].validate` `valid` `true``dialogTitle` `createProductAttrCate` `updateProductAttrCate` ID `valid` `false` `false`
this.$refs[formName].validate((valid) => {
if (valid) {
let data = new URLSearchParams();
data.append("name",this.productAttrCate.name);
if(this.dialogTitle==="添加类型"){
createProductAttrCate(data).then(response => {
this.$message({
message: '添加成功',
type: 'success',
duration: 1000
});
this.dialogVisible = false;
this.getList();
});
}else{
updateProductAttrCate(this.productAttrCate.id,data).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
this.dialogVisible = false;
this.getList();
});
}
} else {
console.log('error submit!!');
return false;
}
});
},
handleClose() {
// `$refs.productAttrCatForm` `clearValidate`
if (!this.dialogVisible && this.$refs.productAttrCatForm) {
this.$refs.productAttrCatForm.clearValidate()
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>

@ -1,455 +0,0 @@
<template> 
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button
class="btn-add"
@click="addProductAttr()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="productAttrTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<el-table-column type="selection" width="60" align="center"></el-table-column>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="属性名称" width="140" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="商品类型" width="140" align="center">
<template slot-scope="scope">{{$route.query.cname}}</template>
</el-table-column>
<el-table-column label="属性是否可选" width="120" align="center">
<template slot-scope="scope">{{scope.row.selectType|selectTypeFilter}}</template>
</el-table-column>
<el-table-column label="属性值的录入方式" width="150" align="center">
<template slot-scope="scope">{{scope.row.inputType|inputTypeFilter}}</template>
</el-table-column>
<el-table-column label="可选值列表" align="center">
<template slot-scope="scope">{{scope.row.inputList}}</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="batch-operate-container">
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import {fetchList, deleteProductAttr} from '@/api/productAttr'
export default {
name: 'productAttrList',
data() {
return {
list: null,
total: null,
listLoading: true,
listQuery: {
pageNum: 1,
pageSize: 5,
type: this.$route.query.type
},
operateType: null,
multipleSelection: [],
operates: [
{
label: "删除",
value: "deleteProductAttr"
}
]
}
},
created() {
this.getList();
},
methods: {
getList() {
this.listLoading = true;
fetchList(this.$route.query.cid, this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
addProductAttr() {
this.$router.push({path:'/pms/addProductAttr',query:{cid:this.$route.query.cid,type:this.$route.query.type}});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleBatchOperate() {
if (this.multipleSelection < 1) {
this.$message({
message: '请选择一条记录',
type: 'warning',
duration: 1000
});
return;
}
if (this.operateType !== 'deleteProductAttr') {
this.$message({
message: '请选择批量操作类型',
type: 'warning',
duration: 1000
});
return;
}
let ids = [];
for (let i = 0; i < this.multipleSelection.length; i++) {
ids.push(this.multipleSelection[i].id);
}
this.handleDeleteProductAttr(ids);
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleUpdate(index, row) {
this.$router.push({path:'/pms/updateProductAttr',query:{id:row.id}});
},
handleDeleteProductAttr(ids) {
this.$confirm('是否要删除该属性', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let data = new URLSearchParams();
data.append("ids", ids);
deleteProductAttr(data).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
},
handleDelete(index, row) {
let ids = [];
ids.push(row.id);
this.handleDeleteProductAttr(ids);
},
},
filters: {
inputTypeFilter(value) {
if (value === 1) {
return '从列表中选取';
} else {
return '手工录入'
}
},
selectTypeFilter(value) {
if (value === 1) {
return '单选';
} else if (value === 2) {
return '多选';
} else {
return '唯一'
}
},
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
</style>
#abc
<template>
<!-- 最外层的 div 元素类名为 `app-container`作为整个页面内容的容器用于包裹内部各个功能模块实现整体页面布局 -->
<div class="app-container">
<!-- 使用 Element UI `el-card` 组件创建一个卡片式容器类名为 `operate-container`设置阴影效果为 `never`无阴影用于放置与数据列表操作相关的元素比如操作按钮等 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 Element UI 的图标组件展示票务图标并设置 `margin-top: 5px`使其在垂直方向上距顶部有一定间距在视觉上辅助提示该区域与数据操作相关 -->
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<!-- 显示数据列表文字同样设置 `margin-top: 5px`明确该卡片容器内的操作是针对下方展示的数据列表起到功能说明作用 -->
<span style="margin-top: 5px">数据列表</span>
<!-- 使用 Element UI `el-button` 按钮组件设置类名为 `btn-add`点击时触发 `addProductAttr` 方法尺寸为 `mini`迷你型用于执行添加商品属性的操作 -->
<el-button
class="btn-add"
@click="addProductAttr()"
size="mini">
添加
</el-button>
</el-card>
<!-- div 元素类名为 `table-container`作为表格展示的容器用于包裹 `el-table` 组件使其在页面中以特定样式展示数据列表 -->
<div class="table-container">
<!-- 使用 Element UI `el-table` 表格组件设置引用名为 `productAttrTable`绑定数据为 `list`宽度为 `100%`监听 `selection-change` 事件当表格行选择状态改变时并触发 `handleSelectionChange` 方法根据 `listLoading` 变量控制加载状态显示如显示加载动画等设置表格边框样式用于展示商品属性相关的数据列表 -->
<el-table ref="productAttrTable"
:data="list"
style="width: 100%"
@selection-change="handleSelectionChange"
v-loading="listLoading"
border>
<!-- 表格列类型为 `selection`选择列宽度为 `60px`内容在单元格中居中对齐用于在表格中提供勾选行的功能方便进行批量操作等选择行的场景 -->
<el-table-column type="selection" width="60" align="center"></el-table-column>
<!-- 表格列标签显示为编号宽度为 `100px`内容在单元格中居中对齐通过插槽作用域`slot-scope`获取当前行数据展示商品属性的编号信息 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列标签显示为属性名称宽度为 `140px`内容在单元格中居中对齐通过插槽作用域获取当前行数据展示商品属性的名称信息 -->
<el-table-column label="属性名称" width="140" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列标签显示为商品类型宽度为 `140px`内容在单元格中居中对齐通过路由对象`$route`的查询参数`query`获取 `cname` 的值来展示商品类型信息表明该属性所属的商品类型 -->
<el-table-column label="商品类型" width="140" align="center">
<template slot-scope="scope">{{$route.query.cname}}</template>
</el-table-column>
<!-- 表格列标签显示为属性是否可选宽度为 `120px`内容在单元格中居中对齐通过管道符`|`使用 `selectTypeFilter` 过滤器对 `scope.row.selectType` 的值进行处理后展示用于以更友好的文字形式展示属性可选类型如单选多选等 -->
<el-table-column label="属性是否可选" width="120" align="center">
<template slot-scope="scope">{{scope.row.selectType|selectTypeFilter}}</template>
</el-table-column>
<!-- 表格列标签显示为属性值的录入方式宽度为 `150px`内容在单元格中居中对齐通过管道符使用 `inputTypeFilter` 过滤器对 `scope.row.inputType` 的值进行处理后展示用于以更友好的文字形式展示属性值录入方式如从列表中选取手工录入等 -->
<el-table-column label="属性值的录入方式" width="150" align="center">
<template slot-scope="scope">{{scope.row.inputType|inputTypeFilter}}</template>
</el-table-column>
<!-- 表格列标签显示为可选值列表内容在单元格中居中对齐通过插槽作用域获取当前行数据直接展示商品属性的可选值列表信息 -->
<el-table-column label="可选值列表" align="center">
<template slot-scope="scope">{{scope.row.inputList}}</template>
</el-table-column>
<!-- 表格列标签显示为排序宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据展示商品属性在排序方面的相关信息比如用于确定属性展示顺序等 -->
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为 `200px`内容在单元格中居中对齐通过插槽作用域获取当前行数据包含编辑和删除两个按钮分别点击可触发对应的 `handleUpdate` `handleDelete` 方法用于对单个商品属性进行编辑或删除操作 -->
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- div 元素类名为 `batch-operate-container`用于放置批量操作相关的元素如选择批量操作类型的下拉框和执行操作的按钮 -->
<div class="batch-operate-container">
<!-- 使用 Element UI `el-select` 下拉选择框组件尺寸为 `small`小型双向绑定 `operateType` 数据设置占位提示文字为批量操作其下拉选项通过循环 `operates` 数组生成用于选择批量操作的具体类型 -->
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operates"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- 使用 Element UI `el-button` 按钮组件设置样式 `margin-left: 20px`距左侧 20px 间距类名为 `search-button`点击时触发 `handleBatchOperate` 方法按钮类型为 `primary`主要按钮通常有突出显示效果尺寸为 `small`用于执行确定批量操作的动作 -->
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<!-- div 元素类名为 `pagination-container`作为分页功能的容器用于包裹 `el-pagination` 分页组件实现数据列表的分页展示 -->
<div class="pagination-container">
<!-- 使用 Element UI `el-pagination` 分页组件设置 `background`背景色样式监听 `size-change`页面尺寸变化 `current-change`当前页码变化事件并分别触发对应的 `handleSizeChange` `handleCurrentChange` 方法设置分页布局样式绑定页面尺寸可选页面尺寸数组当前页码以及总数据量等数据实现数据列表的分页功能 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// `@/api/productAttr` `fetchList` `deleteProductAttr` API
import {fetchList, deleteProductAttr} from '@/api/productAttr';
export default {
name: 'productAttrList',
data() {
return {
// `null`
list: null,
// `null`
total: null,
// `true` `false`
listLoading: true,
// `type`
listQuery: {
pageNum: 1,
pageSize: 5,
type: this.$route.query.type
},
// `null`
operateType: null,
// `selection-change` 便
multipleSelection: [],
// `label` `value`
operates: [
{
label: "删除",
value: "deleteProductAttr"
}
]
};
},
created() {
// `getList`
this.getList();
},
methods: {
getList() {
// `listLoading` `true`
this.listLoading = true;
// `fetchList` `cid` ID `listQuery` `listLoading` `false` `list` `total`
fetchList(this.$route.query.cid, this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
addProductAttr() {
// `$router.push` `/pms/addProductAttr` `cid` `type`
this.$router.push({path:'/pms/addProductAttr',query:{cid:this.$route.query.cid,type:this.$route.query.type}});
},
handleSelectionChange(val) {
// `multipleSelection` 便
this.multipleSelection = val;
},
handleBatchOperate() {
// `multipleSelection` 1 `deleteProductAttr` `id` `handleDeleteProductAttr`
if (this.multipleSelection < 1) {
this.$message({
message: '请选择一条记录',
type: 'warning',
duration: 1000
});
return;
}
if (this.operateType!== 'deleteProductAttr') {
this.$message({
message: '请选择批量操作类型',
type: 'warning',
duration: 1000
});
return;
}
let ids = [];
for (let i = 0; i < this.multipleSelection.length; i++) {
ids.push(this.multipleSelection[i].id);
}
this.handleDeleteProductAttr(ids);
},
handleSizeChange(val) {
// `listQuery` `pageNum` 1 `pageSize` `val` `getList`
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
// `listQuery` `pageNum` `val` `getList`
this.listQuery.pageNum = val;
this.getList();
},
handleUpdate(index, row) {
// `$router.push` `/pms/updateProductAttr` `id` ID
this.$router.push({path:'/pms/updateProductAttr',query:{id:row.id}});
},
handleDeleteProductAttr(ids) {
// `URLSearchParams` `ids` `deleteProductAttr` `getList`
this.$confirm('是否要删除该属性', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let data = new URLSearchParams();
data.append("ids", ids);
deleteProductAttr(data).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
},
handleDelete(index, row) {
// `ids` `id` `handleDeleteProductAttr`
let ids = [];
ids.push(row.id);
this.handleDeleteProductAttr(ids);
}
},
filters:
// `inputType`

@ -1,32 +0,0 @@
<template>
<product-attr-detail :is-edit='true'></product-attr-detail>
</template>
<script>
import ProductAttrDetail from './components/ProductAttrDetail'
export default {
name: 'updateProductAttr',
components: { ProductAttrDetail }
}
</script>
<style scoped>
</style>
#abc
<template>
<!-- 使用名为 `product-attr-detail` 的自定义组件通过 `:is-edit='true'` 属性绑定向该组件传递了名为 `is-edit` 的属性值设为 `true`表示当前处于编辑商品属性的操作模式区别于新增商品属性模式`product-attr-detail` 组件会依据这个属性值来展示对应的编辑界面以及执行相应的编辑相关逻辑 -->
<product-attr-detail :is-edit='true'></product-attr-detail>
</template>
<script>
// `./components/` `ProductAttrDetail`
import ProductAttrDetail from './components/ProductAttrDetail';
export default {
name: 'updateProductAttr',
// `components` `ProductAttrDetail` 使 `updateProductAttr` `<product-attr-detail>` Vue.js 便
components: { ProductAttrDetail }
}
</script>
<style scoped>
/* 这里样式部分设置了 `scoped` 属性,意味着样式只会应用到当前组件内部的元素上。目前该部分样式为空,后续可以根据 `updateProductAttr` 组件的视觉设计要求,添加对应的 CSS 样式规则,像设置组件内文本的字体、颜色,表单元素的布局、边框样式等,让组件在页面中呈现出期望的外观效果 */
</style>

@ -1,31 +0,0 @@
<template> 
<product-cate-detail :is-edit='false'></product-cate-detail>
</template>
<script>
import ProductCateDetail from './components/ProductCateDetail'
export default {
name: 'addProductCate',
components: { ProductCateDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 使用名为 `product-cate-detail` 的自定义组件通过 `:is-edit='false'` 属性绑定 `product-cate-detail` 组件传递了 `is-edit` 属性其值为 `false`这表明当前处于添加商品分类的操作模式与编辑商品分类模式相区分`product-cate-detail` 组件会基于这个属性值展示出对应的添加商品分类界面并执行相应的添加相关逻辑 -->
<product-cate-detail :is-edit='false'></product-cate-detail>
</template>
<script>
// `./components/` `ProductCateDetail` `./components/`
import ProductCateDetail from './components/ProductCateDetail';
export default {
name: 'addProductCate',
// `components` `ProductCateDetail` `addProductCate` `<product-cate-detail>` Vue.js 便便
components: { ProductCateDetail }
}
</script>
<style>
/* 这里的样式部分目前为空,后续可以依据 `addProductCate` 组件整体的视觉呈现要求,添加相应的 CSS 样式规则,例如设置组件在页面中的整体布局样式(如宽度、高度、外边距、内边距等),对组件内文本的字体、字号、颜色等样式属性进行定义,还可以针对各种表单元素(如果有的话)设置其边框、背景色、圆角等外观样式,从而让组件在页面中展现出符合预期的视觉效果 */
</style>

@ -1,264 +0,0 @@
<template>
<el-card class="form-container" shadow="never">
<el-form :model="productCate"
:rules="rules"
ref="productCateFrom"
label-width="150px">
<el-form-item label="分类名称:" prop="name">
<el-input v-model="productCate.name"></el-input>
</el-form-item>
<el-form-item label="上级分类:">
<el-select v-model="productCate.parentId"
placeholder="请选择分类">
<el-option
v-for="item in selectProductCateList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="数量单位:">
<el-input v-model="productCate.productUnit"></el-input>
</el-form-item>
<el-form-item label="排序:">
<el-input v-model="productCate.sort"></el-input>
</el-form-item>
<el-form-item label="是否显示:">
<el-radio-group v-model="productCate.showStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否显示在导航栏:">
<el-radio-group v-model="productCate.navStatus">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分类图标:">
<single-upload v-model="productCate.icon"></single-upload>
</el-form-item>
<el-form-item v-for="(filterProductAttr, index) in filterProductAttrList"
:label="index | filterLabelFilter"
:key="filterProductAttr.key"
>
<el-cascader
clearable
v-model="filterProductAttr.value"
:options="filterAttrs">
</el-cascader>
<el-button style="margin-left: 20px" @click.prevent="removeFilterAttr(filterProductAttr)">删除</el-button>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="handleAddFilterAttr()"></el-button>
</el-form-item>
<el-form-item label="关键词:">
<el-input v-model="productCate.keywords"></el-input>
</el-form-item>
<el-form-item label="分类描述:">
<el-input type="textarea" :autosize="true" v-model="productCate.description"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('productCateFrom')"></el-button>
<el-button v-if="!isEdit" @click="resetForm('productCateFrom')"></el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
import {fetchList, createProductCate, updateProductCate, getProductCate} from '@/api/productCate';
import {fetchListWithAttr} from '@/api/productAttrCate';
import {getProductAttrInfo} from '@/api/productAttr';
import SingleUpload from '@/components/Upload/singleUpload';
const defaultProductCate = {
description: '',
icon: '',
keywords: '',
name: '',
navStatus: 0,
parentId: 0,
productUnit: '',
showStatus: 0,
sort: 0,
productAttributeIdList: []
};
export default {
name: "ProductCateDetail",
components: {SingleUpload},
props: {
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
productCate: Object.assign({}, defaultProductCate),
selectProductCateList: [],
rules: {
name: [
{required: true, message: '请输入品牌名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
]
},
filterAttrs: [],
filterProductAttrList: [{
value: []
}]
}
},
created() {
if (this.isEdit) {
getProductCate(this.$route.query.id).then(response => {
this.productCate = response.data;
});
getProductAttrInfo(this.$route.query.id).then(response => {
if (response.data != null && response.data.length > 0) {
this.filterProductAttrList = [];
for (let i = 0; i < response.data.length; i++) {
this.filterProductAttrList.push({
key: Date.now() + i,
value: [response.data[i].attributeCategoryId, response.data[i].attributeId]
})
}
}
});
} else {
this.productCate = Object.assign({}, defaultProductCate);
}
this.getSelectProductCateList();
this.getProductAttrCateList();
},
methods: {
getSelectProductCateList() {
fetchList(0, {pageSize: 100, pageNum: 1}).then(response => {
this.selectProductCateList = response.data.list;
this.selectProductCateList.unshift({id: 0, name: '无上级分类'});
});
},
getProductAttrCateList() {
fetchListWithAttr().then(response => {
let list = response.data;
for (let i = 0; i < list.length; i++) {
let productAttrCate = list[i];
let children = [];
if (productAttrCate.productAttributeList != null && productAttrCate.productAttributeList.length > 0) {
for (let j = 0; j < productAttrCate.productAttributeList.length; j++) {
children.push({
label: productAttrCate.productAttributeList[j].name,
value: productAttrCate.productAttributeList[j].id
})
}
}
this.filterAttrs.push({label: productAttrCate.name, value: productAttrCate.id, children: children});
}
});
},
getProductAttributeIdList() {
//
let productAttributeIdList = [];
for (let i = 0; i < this.filterProductAttrList.length; i++) {
let item = this.filterProductAttrList[i];
if (item.value !== null && item.value.length === 2) {
productAttributeIdList.push(item.value[1]);
}
}
return productAttributeIdList;
},
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('是否提交数据', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
this.productCate.productAttributeIdList = this.getProductAttributeIdList();
updateProductCate(this.$route.query.id, this.productCate).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
this.$router.back();
});
} else {
this.productCate.productAttributeIdList = this.getProductAttributeIdList();
createProductCate(this.productCate).then(response => {
this.$refs[formName].resetFields();
this.resetForm(formName);
this.$message({
message: '提交成功',
type: 'success',
duration: 1000
});
});
}
});
} else {
this.$message({
message: '验证失败',
type: 'error',
duration: 1000
});
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.productCate = Object.assign({}, defaultProductCate);
this.getSelectProductCateList();
this.filterProductAttrList = [{
value: []
}];
},
removeFilterAttr(productAttributeId) {
if (this.filterProductAttrList.length === 1) {
this.$message({
message: '至少要留一个',
type: 'warning',
duration: 1000
});
return;
}
var index = this.filterProductAttrList.indexOf(productAttributeId);
if (index !== -1) {
this.filterProductAttrList.splice(index, 1)
}
},
handleAddFilterAttr() {
if (this.filterProductAttrList.length === 3) {
this.$message({
message: '最多添加三个',
type: 'warning',
duration: 1000
});
return;
}
this.filterProductAttrList.push({
value: null,
key: Date.now()
});
}
},
filters: {
filterLabelFilter(index) {
if (index === 0) {
return '筛选属性:';
} else {
return '';
}
}
}
}
</script>
<style scoped>
</style>

@ -1,456 +0,0 @@
<template>
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button
class="btn-add"
@click="handleAddProductCate()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="productCateTable"
style="width: 100%"
:data="list"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="分类名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="级别" width="100" align="center">
<template slot-scope="scope">{{scope.row.level | levelFilter}}</template>
</el-table-column>
<el-table-column label="商品数量" width="100" align="center">
<template slot-scope="scope">{{scope.row.productCount }}</template>
</el-table-column>
<el-table-column label="数量单位" width="100" align="center">
<template slot-scope="scope">{{scope.row.productUnit }}</template>
</el-table-column>
<el-table-column label="导航栏" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleNavStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.navStatus">
</el-switch>
</template>
</el-table-column>
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleShowStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.showStatus">
</el-switch>
</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort }}</template>
</el-table-column>
<el-table-column label="设置" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
:disabled="scope.row.level | disableNextLevel"
@click="handleShowNextLevel(scope.$index, scope.row)">查看下级
</el-button>
<el-button
size="mini"
@click="handleTransferProduct(scope.$index, scope.row)">转移商品
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import {fetchList,deleteProductCate,updateShowStatus,updateNavStatus} from '@/api/productCate'
export default {
name: "productCateList",
data() {
return {
list: null,
total: null,
listLoading: true,
listQuery: {
pageNum: 1,
pageSize: 5
},
parentId: 0
}
},
created() {
this.resetParentId();
this.getList();
},
watch: {
$route(route) {
this.resetParentId();
this.getList();
}
},
methods: {
resetParentId(){
this.listQuery.pageNum = 1;
if (this.$route.query.parentId != null) {
this.parentId = this.$route.query.parentId;
} else {
this.parentId = 0;
}
},
handleAddProductCate() {
this.$router.push('/pms/addProductCate');
},
getList() {
this.listLoading = true;
fetchList(this.parentId, this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleNavStatusChange(index, row) {
let data = new URLSearchParams();
let ids=[];
ids.push(row.id)
data.append('ids',ids);
data.append('navStatus',row.navStatus);
updateNavStatus(data).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
handleShowStatusChange(index, row) {
let data = new URLSearchParams();
let ids=[];
ids.push(row.id)
data.append('ids',ids);
data.append('showStatus',row.showStatus);
updateShowStatus(data).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
handleShowNextLevel(index, row) {
this.$router.push({path: '/pms/productCate', query: {parentId: row.id}})
},
handleTransferProduct(index, row) {
console.log('handleAddProductCate');
},
handleUpdate(index, row) {
this.$router.push({path:'/pms/updateProductCate',query:{id:row.id}});
},
handleDelete(index, row) {
this.$confirm('是否要删除该品牌', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteProductCate(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
}
},
filters: {
levelFilter(value) {
if (value === 0) {
return '一级';
} else if (value === 1) {
return '二级';
}
},
disableNextLevel(value) {
if (value === 0) {
return false;
} else {
return true;
}
}
}
}
</script>
<style scoped>
</style>
#abc
<template>
<!-- 最外层的 `div` 元素设置了类名为 `app-container`作为整个页面内容的容器用于包裹内部各个功能模块实现整体页面布局 -->
<div class="app-container">
<!-- 使用 Element UI `el-card` 组件创建一个卡片式容器类名为 `operate-container`设置阴影效果为 `never`无阴影用于放置与数据列表操作相关的元素比如操作按钮等 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 Element UI 的图标组件展示票务图标并设置 `margin-top: 5px`使其在垂直方向上距顶部有一定间距在视觉上辅助提示该区域与数据操作相关 -->
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<!-- 显示数据列表文字同样设置 `margin-top: 5px`明确该卡片容器内的操作是针对下方展示的数据列表起到功能说明作用 -->
<span style="margin-top: 5px">数据列表</span>
<!-- 使用 Element UI `el-button` 按钮组件设置类名为 `btn-add`点击时触发 `handleAddProductCate` 方法尺寸为 `mini`迷你型用于执行添加商品分类的操作 -->
<el-button
class="btn-add"
@click="handleAddProductCate()"
size="mini">
添加
</el-button>
</el-card>
<!-- `div` 元素类名为 `table-container`作为表格展示的容器用于包裹 `el-table` 组件使其在页面中以特定样式展示数据列表 -->
<div class="table-container">
<!-- 使用 Element UI `el-table` 表格组件设置引用名为 `productCateTable`宽度为 `100%`绑定数据为 `list`根据 `v-loading` 指令结合 `listLoading` 变量控制加载状态显示如显示加载动画等设置表格边框样式用于展示商品分类相关的数据列表 -->
<el-table ref="productCateTable"
style="width: 100%"
:data="list"
v-loading="listLoading" border>
<!-- 表格列标签显示为编号宽度为 `100px`内容在单元格中居中对齐通过插槽作用域`slot-scope`获取当前行数据展示商品分类的编号信息 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列标签显示为分类名称内容在单元格中居中对齐通过插槽作用域获取当前行数据展示商品分类的名称信息 -->
<el-table-column label="分类名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列标签显示为级别宽度为 `100px`内容在单元格中居中对齐通过管道符`|`使用 `levelFilter` 过滤器对 `scope.row.level` 的值进行处理后展示用于以更友好的文字形式一级二级展示商品分类的级别信息 -->
<el-table-column label="级别" width="100" align="center">
<template slot-scope="scope">{{scope.row.level | levelFilter}}</template>
</el-table-column>
<!-- 表格列标签显示为商品数量宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据展示该商品分类下包含的商品数量信息 -->
<el-table-column label="商品数量" width="100" align="center">
<template slot-scope="scope">{{scope.row.productCount }}</template>
</el-table-column>
<!-- 表格列标签显示为数量单位宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据展示商品数量对应的单位信息 -->
<el-table-column label="数量单位" width="100" align="center">
<template slot-scope="scope">{{scope.row.productUnit }}</template>
</el-table-column>
<!-- 表格列标签显示为导航栏宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据包含一个 `el-switch` 开关组件监听开关状态变化事件 `change` 并触发 `handleNavStatusChange` 方法双向绑定 `scope.row.navStatus` 数据用于控制商品分类在导航栏的显示状态如是否展示在导航栏等 -->
<el-table-column label="导航栏" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleNavStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.navStatus">
</el-switch>
</template>
</el-table-column>
<!-- 表格列标签显示为是否显示宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据包含一个 `el-switch` 开关组件监听开关状态变化事件 `change` 并触发 `handleShowStatusChange` 方法双向绑定 `scope.row.showStatus` 数据用于控制商品分类是否显示可能在页面其他位置的显示与否等情况 -->
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleShowStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.showStatus">
</el-switch>
</template>
</el-table-column>
<!-- 表格列标签显示为排序宽度为 `100px`内容在单元格中居中对齐通过插槽作用域获取当前行数据展示商品分类在排序方面的相关信息比如用于确定分类展示顺序等 -->
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort }}</template>
</el-table-column>
<!-- 表格列标签显示为设置宽度为 `200px`内容在单元格中居中对齐通过插槽作用域获取当前行数据包含两个按钮查看下级按钮根据 `scope.row.level` 通过 `disableNextLevel` 过滤器判断是否禁用如果是一级分类可能允许查看下级等逻辑点击触发 `handleShowNextLevel` 方法转移商品按钮点击触发 `handleTransferProduct` 方法用于相关的商品转移操作目前方法内仅打印日志可能后续完善具体逻辑 -->
<el-table-column label="设置" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
:disabled="scope.row.level | disableNextLevel"
@click="handleShowNextLevel(scope.$index, scope.row)">查看下级</ </el-button>
<el-button
size="mini"
@click="handleTransferProduct(scope.$index, scope.row)">转移商品</ </el-button>
</template>
</el-table-column>
<!-- 表格列标签显示为操作宽度为 `200px`内容在单元格中居中对齐通过插槽作用域获取当前行数据包含编辑和删除两个按钮分别点击可触发对应的 `handleUpdate` `handleDelete` 方法用于对单个商品分类进行编辑或删除操作 -->
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleUpdate(scope.$index, scope.row)">编辑</ </el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除</ </el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- `div` 元素类名为 `pagination-container`作为分页功能的容器用于包裹 `el-pagination` 分页组件实现数据列表的分页展示 -->
<div class="pagination-container">
<!-- 使用 Element UI `el-pagination` 分页组件设置 `background`背景色样式监听 `size-change`页面尺寸变化 `current-change`当前页码变化事件并分别触发对应的 `handleSizeChange` `handleCurrentChange` 方法设置分页布局样式绑定页面尺寸可选页面尺寸数组当前页码以及总数据量等数据实现数据列表的分页功能 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// `@/api/productCate` `fetchList``deleteProductCate``updateShowStatus``updateNavStatus` API
import {fetchList,deleteProductCate,updateShowStatus,updateNavStatus} from '@/api/productCate';
export default {
name: "productCateList",
data() {
return {
// `null`
list: null,
// `null`
total: null,
// `true` `false`
listLoading: true,
//
listQuery: {
pageNum: 1,
pageSize: 5
},
// ID `0`
parentId: 0
};
},
created() {
// `resetParentId` ID `getList`
this.resetParentId();
this.getList();
},
watch: {
// `$route` `resetParentId` ID `getList`
$route(route) {
this.resetParentId();
this.getList();
}
},
methods: {
resetParentId() {
// `listQuery` `pageNum` `1` `parentId` `null` `parentId` `parentId` `null` `parentId` `0` ID
this.listQuery.pageNum = 1;
if (this.$route.query.parentId!= null) {
this.parentId = this.$route.query.parentId;
} else {
this.parentId = 0;
}
},
handleAddProductCate() {
// `$router.push` `/pms/addProductCate`
this.$router.push('/pms/addProductCate');
},
getList() {
// `listLoading` `true`
this.listLoading = true;
// `fetchList` `parentId` ID `listQuery` `listLoading` `false` `list` `total`
fetchList(this.parentId, this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
handleSizeChange(val) {
// `listQuery` `pageNum` `1` `pageSize` `val` `getList`
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
// `listQuery` `pageNum` `val` `getList`
this.listQuery.pageNum = val;
this.getList();
},
handleNavStatusChange(index, row) {
// `URLSearchParams` `id` `ids` `navStatus` `updateNavStatus`
let data = new URLSearchParams();
let ids=[];
ids.push(row.id)
data.append('ids',ids);
data.append('navStatus',row.navStatus);
updateNavStatus(data).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
handleShowStatusChange(index, row) {
// `URLSearchParams` `id` `ids` `showStatus` `updateShowStatus`
let data = new URLSearchParams();
let ids=[];
ids.push(row.id)
data.append('ids',ids);
data.append('showStatus',row.showStatus);
updateShowStatus(data).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
handleShowNextLevel(index, row) {
// `$router.push` `/pms/productCate` `parentId` `id`
this.$router.push({path: '/pms/productCate', query: {parentId: row.id}})
},
handleTransferProduct(index, row) {
// `handleAddProductCate`
console.log('handleAddProductCate');
},
handleUpdate(index, row)
// `$router.push

@ -1,31 +0,0 @@
<template> 
<product-cate-detail :is-edit='true'></product-cate-detail>
</template>
<script>
import ProductCateDetail from './components/ProductCateDetail'
export default {
name: 'updateProductCate',
components: { ProductCateDetail }
}
</script>
<style>
</style>
#abc
<template>
<!-- 使用名为 `product-cate-detail` 的自定义组件并通过 `:is-edit='true'` 进行属性绑定传递了 `is-edit` 属性且其值设为 `true`这意味着当前处于编辑商品分类的操作模式与新增商品分类的模式相区别`product-cate-detail` 组件会依据这个属性值来展示对应的编辑界面以及执行相应的编辑相关逻辑例如展示已有的商品分类信息以供修改并处理保存修改后的数据等操作 -->
<product-cate-detail :is-edit='true'></product-cate-detail>
</template>
<script>
// `./components/` `ProductCateDetail` `./components/`
import ProductCateDetail from './components/ProductCateDetail';
export default {
name: 'updateProductCate',
// `components` `ProductCateDetail` 使 `updateProductCate` `<product-cate-detail>` Vue.js 便
components: { ProductCateDetail }
}
</script>
<style>
/* 这里的样式部分目前为空,后续可以根据 `updateProductCate` 组件整体的视觉呈现要求,添加相应的 CSS 样式规则。例如,可以设置组件在页面中的整体布局样式(如宽度、高度、外边距、内边距等),对组件内文本的字体、字号、颜色等样式属性进行定义,还能针对各种表单元素(如果有的话)设置其边框、背景色、圆角等外观样式,从而让组件在页面中展现出符合预期的视觉效果 */
</style>

@ -1,7 +1,5 @@
<template>
<!-- 容器用于包裹整个仪表盘 -->
<div class="app-container">
<!-- 学习教程链接部分 -->
<div class="address-layout">
<el-row :gutter="20">
<el-col :span="6">
@ -30,8 +28,6 @@
</el-col>
</el-row>
</div>
<!-- 订单统计部分 -->
<div class="total-layout">
<el-row :gutter="20">
<el-col :span="6">
@ -55,18 +51,16 @@
<div class="total-value">5000.00</div>
</div>
</el-col>
<!--<el-col :span="6">
<div class="total-frame">
<svg-icon icon-class="total-week" class="total-icon">
</svg-icon>
<div class="total-title">近7天销售总额</div>
<div class="total-value">50000.00</div>
</div>
</el-col>-->
<!--<el-col :span="6">-->
<!--<div class="total-frame">-->
<!--<svg-icon icon-class="total-week" class="total-icon">-->
<!--</svg-icon>-->
<!--<div class="total-title">近7天销售总额</div>-->
<!--<div class="total-value">50000.00</div>-->
<!--</div>-->
<!--</el-col>-->
</el-row>
</div>
<!-- 公众号二维码部分 -->
<el-card class="mine-layout">
<div style="text-align: center">
<img width="150px" height="150px" src="http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/banner/qrcode_for_macrozheng_258.jpg">
@ -74,8 +68,6 @@
<div style="text-align: center">mall全套学习教程连载中</div>
<div style="text-align: center;margin-top: 5px"><span class="color-main">关注公号</span>第一时间获取</div>
</el-card>
<!-- 待处理事务部分 -->
<div class="un-handle-layout">
<div class="layout-title">待处理事务</div>
<div class="un-handle-content">
@ -141,8 +133,6 @@
</el-row>
</div>
</div>
<!-- 商品总览和用户总览部分 -->
<div class="overview-layout">
<el-row :gutter="20">
<el-col :span="12">
@ -185,8 +175,6 @@
</el-col>
</el-row>
</div>
<!-- 订单统计图表部分 -->
<div class="statistics-layout">
<div class="layout-title">订单统计</div>
<el-row>
@ -255,15 +243,12 @@
</div>
</div>
</template>
<script>
//
import {str2Date} from '@/utils/date';
//
import img_home_order from '@/assets/images/home_order.png';
import img_home_today_amount from '@/assets/images/home_today_amount.png';
import img_home_yesterday_amount from '@/assets/images/home_yesterday_amount.png';
//
const DATA_FROM_BACKEND = {
columns: ['date', 'orderCount','orderAmount'],
rows: [
@ -284,12 +269,10 @@
{date: '2018-11-15', orderCount: 40, orderAmount: 4293}
]
};
export default {
name: 'home',
data() {
return {
//
pickerOptions: {
shortcuts: [{
text: '最近一周',
@ -307,68 +290,52 @@
}
}]
},
//
orderCountDate: '',
//
chartSettings: {
xAxisType: 'time',
area:true,
axisSite: { right: ['orderAmount']},
labelMap: {'orderCount': '订单数量', 'orderAmount': '订单金额'}
},
//
labelMap: {'orderCount': '订单数量', 'orderAmount': '订单金额'}},
chartData: {
columns: [],
rows: []
},
//
loading: false,
//
dataEmpty: false,
//
img_home_order,
img_home_today_amount,
img_home_yesterday_amount
}
},
created(){
//
this.initOrderCountDate();
//
this.getData();
},
methods:{
//
handleDateChange(){
this.getData();
},
//
initOrderCountDate(){
let start = new Date(2018,10,1);
const end = new Date(start.getTime() + 1000 * 60 * 60 * 24 * 7);
this.orderCountDate=[start,end];
},
//
getData(){
setTimeout(() => {
this.chartData = {
columns: ['date', 'orderCount','orderAmount'],
rows: []
};
//
for(let i=0;i<DATA_FROM_BACKEND.rows.length;i++){
let item=DATA_FROM_BACKEND.rows[i];
let currDate=str2Date(item.date);
let start=this.orderCountDate[0];
let end=this.orderCountDate[1];
//
if(currDate.getTime()>=start.getTime()&&currDate.getTime()<=end.getTime()){
this.chartData.rows.push(item);
}
}
//
this.dataEmpty = false;
//
this.loading = false
}, 1000)
}
@ -377,37 +344,31 @@
</script>
<style scoped>
/* 容器样式 */
.app-container {
margin-top: 40px;
margin-left: 120px;
margin-right: 120px;
}
/* 地址布局样式 */
.address-layout {
}
/* 总布局样式 */
.total-layout {
margin-top: 20px;
}
/* 总框架样式 */
.total-frame {
border: 1px solid #DCDFE6;
padding: 20px;
height: 100px;
}
/* 总图标样式 */
.total-icon {
color: #409EFF;
width: 60px;
height: 60px;
}
/* 总标题样式 */
.total-title {
position: relative;
font-size: 16px;
@ -416,7 +377,6 @@
top: -50px;
}
/* 总值样式 */
.total-value {
position: relative;
font-size: 18px;
@ -425,13 +385,11 @@
top: -40px;
}
/* 待处理布局样式 */
.un-handle-layout {
margin-top: 20px;
border: 1px solid #DCDFE6;
}
/* 布局标题样式 */
.layout-title {
color: #606266;
padding: 15px 20px;
@ -439,45 +397,37 @@
font-weight: bold;
}
/* 待处理内容样式 */
.un-handle-content {
padding: 20px 40px;
}
/* 待处理项样式 */
.un-handle-item {
border-bottom: 1px solid #EBEEF5;
padding: 10px;
}
/* 总览布局样式 */
.overview-layout {
margin-top: 20px;
}
/* 总览项值样式 */
.overview-item-value {
font-size: 24px;
text-align: center;
}
/* 总览项标题样式 */
.overview-item-title {
margin-top: 10px;
text-align: center;
}
/* 外边框样式 */
.out-border {
border: 1px solid #DCDFE6;
}
/* 统计布局样式 */
.statistics-layout {
margin-top: 20px;
border: 1px solid #DCDFE6;
}
/* 我的布局样式 */
.mine-layout {
position: absolute;
right: 140px;
@ -485,9 +435,8 @@
width: 250px;
height: 235px;
}
/* 地址内容样式 */
.address-content{
padding: 20px;
font-size: 18px
}
</style>
</style>

@ -2,622 +2,386 @@
<div class="detail-container">
<el-card shadow="never">
<span class="font-title-medium">退货商品</span>
<!--
使用el-table组件来展示表格数据
border属性用于给表格添加边框使其样式上更清晰的显示表格结构
class="standard-margin" 用于给这个表格元素添加一个自定义的类名通过这个类名可以在CSS中定义相应的外边距等样式规则以控制表格在页面中的布局显示效果
ref="productTable" 是给这个表格元素添加一个引用标识方便在Vue实例的JavaScript代码中通过this.$refs.productTable来获取这个表格组件的实例进而可以调用它的一些方法或者访问它的属性等
:data="productList" 是使用Vue的指令将名为productList的数据绑定到表格组件上这个productList应该是在Vue实例的数据对象中定义好的数组类型的数据表格组件会基于这个数据来渲染每一行的内容
-->
<el-table
<el-table
border
class="standard-margin"
ref="productTable"
:data="productList">
<!-- 这里可以添加<el-table-column>等子组件来定义表格的具体列信息比如列标题列对应的数据字段等 -->
</el-table>
<!--
el-table-column组件用于定义el-table中的列信息
label="商品图片" 属性指定了该列在表格头部显示的标题名称为商品图片这样用户就能直观知晓这一列所代表的数据含义
width="160" 属性设置了该列的宽度为160像素通过设置合适的宽度可以让表格各列布局更加合理美观避免内容显示过于拥挤或稀疏
align="center" 属性将该列中的内容在水平方向上进行居中对齐使展示效果更加整齐规范符合常见的页面布局审美要求
-->
<el-table-column label="商品图片" width="160" align="center">
<!--
template标签结合slot-scope="scope" 是一种在表格列中自定义内容渲染的方式
slot-scope="scope" 这里的scope是一个包含了当前行数据等相关信息的对象通过它可以访问到当前行对应的数据
-->
<template slot-scope="scope">
<!--
img标签用于在表格单元格中展示图片
style="height:80px" 是内联样式用于设置图片的高度为80像素以此来统一该列中图片展示的高度达到整齐美观的视觉效果
:src="scope.row.productPic" 是使用Vue的绑定语法将src属性绑定到scope.row.productPic上也就是从scope对象中获取当前行row对应的商品图片的路径productPic信息从而正确地显示对应的商品图片
-->
<img style="height:80px" :src="scope.row.productPic">
</template>
</el-table-column>
<!--
el-table-column 组件用于在 el-table 中定义具体的列信息
label="商品名称" 属性设定了此列在表格头部所显示的标题文字为商品名称方便用户明确该列所展示的数据内容大致范围
align="center" 属性将该列单元格内的内容在水平方向进行居中对齐让表格内的数据呈现更加规整美观符合常规的页面排版视觉效果要求
-->
<el-table-column label="商品名称" align="center">
<!--
template 标签结合 slot-scope="scope" 的写法是在 Element UI 组件的表格列中自定义单元格内容展示方式的常用手段
slot-scope="scope" 这里定义的 scope 是一个包含了当前行诸多相关信息的对象借助它可以访问到当前行对应表格中的一行数据的具体数据情况
-->
<template slot-scope="scope">
<!--
span 标签在这里用于包裹文本内容使其可以灵活地设置样式以及在 HTML 结构中进行布局
class="font-small" span 标签添加了一个名为font-small的类名通常是在项目的 CSS 文件或者是内联样式所在的样式作用域内中定义了对应的字体大小等样式规则以此来让文本以较小的字体呈现可能是为了在表格单元格内更合理地展示信息避免文字过大而影响整体布局美观性
{{scope.row.productName}} 这是 Vue 中的插值表达式它会将 scope 对象中 row 属性下的 productName 字段对应的值渲染显示出来也就是展示当前行对应的商品名称信息
-->
<span class="font-small">{{scope.row.productName}}</span><br>
<!--
这里同样使用 span 标签结合类名font-small来包裹文本内容用于控制文本的样式呈现
品牌{{scope.row.productBrand}}中的插值表达式 {{scope.row.productBrand}} 用于获取并显示当前行对应的商品品牌信息前面添加品牌这样的固定文字是为了更清晰地告知用户后面跟着的是商品的品牌内容整体在表格单元格内更直观地展示商品相关的关键信息
-->
<span class="font-small">品牌{{scope.row.productBrand}}</span>
</template>
</el-table-column>
<!--
el-table-column 组件用于在 el-table 中定义特定的列信息以此来控制表格每列的展示内容样式等相关属性
label="价格/货号" 属性用于指定该列在表格头部显示的标题内容为价格/货号使用这样的标题可以简洁地告知用户这一列将会呈现商品的价格以及货号相关信息
width="180" 属性设置了此列的宽度为 180 像素通过合理设置列宽能够让表格整体的布局更加协调美观避免不同列的内容显示出现过宽或过窄等影响阅读体验的情况
align="center" 属性使得该列单元格内的所有内容在水平方向上进行居中对齐确保数据展示整齐规范符合常规页面设计中对于表格数据排版的美观要求
-->
<el-table-column label="价格/货号" width="180" align="center">
<!--
template 标签配合 slot-scope="scope" 的写法是在 Element UI 组件的表格列中自定义单元格具体内容呈现方式的常见做法
slot-scope="scope" 这里定义的 scope 是一个包含了当前行各项相关信息的对象借助它可以访问到当前行也就是对应表格中的某一行完整数据的各个数据字段情况
-->
<template slot-scope="scope">
<!--
span 标签用于包裹具体的文本内容通过添加类名等操作可以方便地为其设置样式同时在 HTML 结构里实现灵活的布局效果
class="font-small" span 标签添加了一个名为font-small的类名一般情况下在项目的 CSS 样式文件或者所在的样式作用域内会针对这个类名预先定义相应的样式规则例如设置较小的字体大小等目的是为了让文本以更合适的尺寸在表格单元格内进行展示避免字体过大占据过多空间而影响整体的布局美观程度
价格{{scope.row.productRealPrice}}中的插值表达式 {{scope.row.productRealPrice}} 会从 scope 对象中 row 属性下对应的 productRealPrice 字段获取值并将其渲染显示出来在前面添加价格这样的固定文本描述能更清晰地向用户表明后面跟着的是商品的具体价格信息整体呈现出商品价格的展示形式
-->
<span class="font-small">价格{{scope.row.productRealPrice}}</span><br>
<!--
同样使用 span 标签并添加font-small类名来控制文本样式保持和前面价格展示文本在样式上的一致性
货号NO.{{scope.row.productId}}里的插值表达式 {{scope.row.productId}} 用于获取并展示当前行对应的商品货号信息在前面添加货号NO.的固定文本是为了更直观地告知用户后面显示的是商品的货号让用户可以更清晰地分辨出不同的数据内容符合良好的信息展示规范
-->
<span class="font-small">货号NO.{{scope.row.productId}}</span>
</template>
</el-table-column>
<!--
以下是一系列用于定义 el-table 中不同列信息的 el-table-column 组件
第一个 el-table-column 组件用于定义展示属性信息的列
label="属性" 属性指定了该列在表格头部显示的标题为属性方便用户知晓此列所呈现的数据范畴
width="180" 属性将该列的宽度设置为 180 像素通过合理设定宽度使表格布局更显协调美观避免列宽不合适影响整体展示效果
align="center" 属性让该列单元格内的内容在水平方向上居中对齐确保数据排列整齐规范符合常规的页面设计审美要求
其内部 template 标签结合 slot-scope="scope" 来获取当前行数据并展示相应内容具体来说{{scope.row.productAttr}} 这个插值表达式会从 scope 对象中 row 属性下的 productAttr 字段获取值并渲染显示出来也就是在单元格中展示当前行对应的商品属性信息
-->
<el-table-column label="属性" width="180" align="center">
<template slot-scope="scope">{{scope.row.productAttr}}</template>
</el-table-column>
<!--
第二个 el-table-column 组件用于定义展示数量信息的列
label="数量" 属性设定该列在表格头部的标题为数量清晰表明此列所展示的数据内容
width="100" 属性将列宽设定为 100 像素同样是为了优化表格整体的布局效果让各列宽度适配展示内容的多少
align="center" 属性使得该列内容在水平方向居中对齐增强表格数据展示的规整性
内部 template 标签中通过 {{scope.row.productCount}} 插值表达式 scope 对象的 row 属性下的 productCount 字段获取对应的值并将其展示在单元格中实现当前行商品数量信息的呈现
-->
<el-table-column label="数量" width="100" align="center">
<template slot-scope="scope">{{scope.row.productCount}}</template>
</el-table-column>
<!--
第三个 el-table-column 组件用于定义展示小计信息的列
label="小计" 属性指定了该列在表格头部显示的标题是小计让用户明白此处展示的是经过一定计算后的金额小计数据
width="100" 属性将该列宽度设为 100 像素以适配表格布局使各列看起来疏密得当
align="center" 属性保证该列内容在水平方向上居中对齐提升整体展示的美观度
内部 template 标签里的 {{totalAmount}} 插值表达式这里推测 totalAmount 应该是在 Vue 实例的 data 或者 computed 等相关属性中定义好的一个变量可能是基于商品的单价数量等计算得出的小计金额会将其对应的值渲染显示出来用于展示每一行对应的金额小计情况
-->
<el-table-column label="小计" width="100" align="center">
<template slot-scope="scope">{{totalAmount}}</template>
</el-table-column>
</el-table>
<div style="float:right;margin-top:15px;margin-bottom:15px">
<el-table-column label="商品图片" width="160" align="center">
<template slot-scope="scope">
<img style="height:80px" :src="scope.row.productPic">
</template>
</el-table-column>
<el-table-column label="商品名称" align="center">
<template slot-scope="scope">
<span class="font-small">{{scope.row.productName}}</span><br>
<span class="font-small">品牌{{scope.row.productBrand}}</span>
</template>
</el-table-column>
<el-table-column label="价格/货号" width="180" align="center">
<template slot-scope="scope">
<span class="font-small">价格{{scope.row.productRealPrice}}</span><br>
<span class="font-small">货号NO.{{scope.row.productId}}</span>
</template>
</el-table-column>
<el-table-column label="属性" width="180" align="center">
<template slot-scope="scope">{{scope.row.productAttr}}</template>
</el-table-column>
<el-table-column label="数量" width="100" align="center">
<template slot-scope="scope">{{scope.row.productCount}}</template>
</el-table-column>
<el-table-column label="小计" width="100" align="center">
<template slot-scope="scope">{{totalAmount}}</template>
</el-table-column>
</el-table>
<div style="float:right;margin-top:15px;margin-bottom:15px">
<span class="font-title-medium">合计</span>
<span class="font-title-medium color-danger">{{totalAmount}}</span>
</div>
</el-card>
<!--
使用 el-card 组件来创建一个卡片式的布局容器shadow="never" 属性表示该卡片不显示阴影效果class="standard-margin" 用于给卡片添加一个自定义的类名通过这个类名可以在 CSS 中定义相应的外边距等样式规则以控制卡片在页面中的布局显示效果此卡片用于展示服务单相关信息
-->
<el-card shadow="never" class="standard-margin">
<!--
使用 span 标签展示一个标题文本class="font-title-medium" span 标签添加了一个类名用于设置该标题的字体样式推测是中等大小的字体具体样式由项目中对应的 CSS 规则定义文本内容为服务单信息用于明确下方展示内容的主题
-->
<span class="font-title-medium">服务单信息</span>
<!--
div 标签作为一个容器添加了 class="form-container-border" 类名推测用于设置边框等样式来区分不同的信息块内部包含多个 el-row el-col 组件用于布局服务单的各项具体信息
-->
<div class="form-container-border">
<!--
el-row 组件用于创建行布局 Element UI 的栅格系统中多个 el-col 组件放置在 el-row 内来划分列实现灵活的页面布局
以下是第一组 el-row el-col 组件用于展示服务单号信息
-->
<el-card shadow="never" class="standard-margin">
<span class="font-title-medium">服务单信息</span>
<div class="form-container-border">
<el-row>
<!--
el-col 组件用于定义列:span="6" 表示该列占 6 在默认 24 份的栅格系统中class="form-border form-left-bg font-small" 给该列添加了类名用于设置边框背景可能是左边栏的背景色用于区分左右内容以及字体大小较小字体同样具体样式由对应 CSS 规则定义文本内容为服务单号作为该信息项的标题显示在左边栏
-->
<el-col :span="6" class="form-border form-left-bg font-small">服务单号</el-col>
<!--
el-col 组件占 18 用于展示服务单号的具体值通过插值表达式 {{orderReturnApply.id}} orderReturnApply 对象的 id 属性获取对应的值并渲染显示class="form-border font-small" 用于设置边框和较小字体样式
-->
<el-col class="form-border font-small" :span="18">{{orderReturnApply.id}}</el-col>
<el-col :span="6" class="form-border form-left-bg font-small">服务单号</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.id}}</el-col>
</el-row>
<!--
以下是第二组 el-row el-col 组件用于展示申请状态信息结构和功能与展示服务单号类似不同之处在于展示的值通过管道符|使用了 formatStatus 过滤器推测是在 Vue 实例中定义好的用于对状态值进行格式化处理比如转换为更友好的文字描述等
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">申请状态</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.status | formatStatus}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">申请状态</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.status | formatStatus}}</el-col>
</el-row>
<!--
以下是第三组 el-row el-col 组件用于展示订单编号信息除了通过插值表达式 {{orderReturnApply.orderSn}} 展示订单编号具体值外还添加了一个 el-button 组件
el-button 组件的 type="text" 表示是文本样式按钮外观上更简洁类似普通文本链接效果size="small" 表示小尺寸按钮@click="handleViewOrder" 绑定了点击事件点击该按钮会调用 Vue 实例中定义的 handleViewOrder 方法用于实现查看订单的相关操作
对应列设置了 height line-height 样式来控制高度和行高使布局更美观
-->
<el-row>
<el-col :span="6" class="form-border form-left-bg font-small" style="height:50px;line-height:30px">订单编号
</el-col>
<el-col class="form-border font-small" :span="18" style="height:50px">
{{orderReturnApply.orderSn}}
<el-button type="text" size="small" @click="handleViewOrder"></el-button>
</el-col>
<el-col :span="6" class="form-border form-left-bg font-small" style="height:50px;line-height:30px">订单编号
</el-col>
<el-col class="form-border font-small" :span="18" style="height:50px">
{{orderReturnApply.orderSn}}
<el-button type="text" size="small" @click="handleViewOrder"></el-button>
</el-col>
</el-row>
<!--
以下是第四组 el-row el-col 组件用于展示申请时间信息通过插值表达式 {{orderReturnApply.createTime | formatTime}} 展示申请时间具体值使用了 formatTime 过滤器推测用于将时间格式进行格式化比如转换为指定的日期时间格式等
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">申请时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.createTime | formatTime}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">申请时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.createTime | formatTime}}</el-col>
</el-row>
<!--
以下是第五组 el-row el-col 组件用于展示用户账号信息通过插值表达式 {{orderReturnApply.memberUsername}} 展示用户账号具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">用户账号</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.memberUsername}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">用户账号</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.memberUsername}}</el-col>
</el-row>
<!--
以下是第六组 el-row el-col 组件用于展示联系人信息通过插值表达式 {{orderReturnApply.returnName}} 展示联系人具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">联系人</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.returnName}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">联系人</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.returnName}}</el-col>
</el-row>
<!--
以下是第七组 el-row el-col 组件用于展示联系电话信息通过插值表达式 {{orderReturnApply.returnPhone}} 展示联系电话具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">联系电话</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.returnPhone}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">联系电话</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.returnPhone}}</el-col>
</el-row>
<!--
以下是第八组 el-row el-col 组件用于展示退货原因信息通过插值表达式 {{orderReturnApply.reason}} 展示退货原因具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">退货原因</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.reason}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">退货原因</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.reason}}</el-col>
</el-row>
<!--
以下是第九组 el-row el-col 组件用于展示问题描述信息通过插值表达式 {{orderReturnApply.description}} 展示问题描述具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">问题描述</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.description}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">问题描述</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.description}}</el-col>
</el-row>
<!--
以下是第十组 el-row el-col 组件用于展示凭证图片信息el-col 列设置了 height 样式控制高度内部使用 v-for 指令对 proofPics 数组进行循环遍历推测 proofPics 是一个包含图片路径等信息的数组对于每个元素 item通过 :src="item" 将其作为图片的 src 属性值展示对应的图片图片设置了 width height 样式控制大小为 80px×80px
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:100px;line-height:80px">凭证图片
</el-col>
<el-col class="form-border font-small" :span="18" style="height:100px">
<img v-for="item in proofPics" style="width:80px;height:80px" :src="item">
</el-col>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:100px;line-height:80px">凭证图片
</el-col>
<el-col class="form-border font-small" :span="18" style="height:100px">
<img v-for="item in proofPics" style="width:80px;height:80px" :src="item">
</el-col>
</el-row>
</div>
<!--
以下又是一个添加了 class="form-container-border" 类名的 div 容器用于展示另一部分服务单相关信息内部同样由多个 el-row el-col 组件构成
-->
<div class="form-container-border">
<!--
以下是第一组 el-row el-col 组件用于展示订单金额信息通过插值表达式 {{totalAmount}} 展示订单金额具体值前面添加符号表示人民币金额
-->
</div>
<div class="form-container-border">
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">订单金额</el-col>
<el-col class="form-border font-small" :span="18">{{totalAmount}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">订单金额</el-col>
<el-col class="form-border font-small" :span="18">{{totalAmount}}</el-col>
</el-row>
<!--
以下是第二组 el-row el-col 组件用于展示确认退款金额信息除了展示固定的符号外还使用了 el-input 组件
el-input 组件的 size="small" 表示小尺寸输入框v-model="updateStatusParam.returnAmount" 使用双向数据绑定将输入框的值与 Vue 实例中 updateStatusParam 对象的 returnAmount 属性进行绑定方便数据的获取和更新:disabled="orderReturnApply.status!==0" 根据服务单申请状态是否为 0 来决定输入框是否可用如果状态不是 0 则不可用并设置了 width 样式控制宽度以及 margin-left 样式控制左边距
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">确认退款金额
</el-col>
<el-col class="form-border font-small" style="height:52px" :span="18">
<el-input size="small" v-model="updateStatusParam.returnAmount"
:disabled="orderReturnApply.status!==0"
style="width:200px;margin-left: 10px"></el-input>
</el-col>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">确认退款金额
</el-col>
<el-col class="form-border font-small" style="height:52px" :span="18">
<el-input size="small" v-model="updateStatusParam.returnAmount"
:disabled="orderReturnApply.status!==0"
style="width:200px;margin-left: 10px"></el-input>
</el-col>
</el-row>
<!--
以下 v-show="orderReturnApply.status!==3" 指令根据服务单申请状态是否不等于 3 来决定是否显示内部包含的元素用于在特定状态下展示相关信息内部是一组与选择收货相关的 el-row el-col 组件
-->
<div v-show="orderReturnApply.status!==3">
<!--
以下是第一组用于展示选择收货点信息的 el-row el-col 组件el-col 中使用 el-select 组件来创建一个下拉选择框
el-select 组件的 size="small" 表示小尺寸下拉框style="width:200px" 设置宽度:disabled="orderReturnApply.status!==0" 根据服务单申请状态是否为 0 来决定下拉框是否可用v-model="updateStatusParam.companyAddressId" 通过双向数据绑定将选择的值与 Vue 实例中 updateStatusParam 对象的 companyAddressId 属性进行绑定内部通过 v-for 指令循环遍历 companyAddressList 数组推测是包含收货点地址信息的数组为每个元素 address 创建一个 el-option 选项通过 :key:value :label 属性分别设置选项的唯一标识对应的值以及显示的文本内容
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">选择收货点
</el-col>
<el-col class="form-border font-small" style="height:52px" :span="18">
<el-select size="small"
style="width:200px"
:disabled="orderReturnApply.status!==0"
v-model="updateStatusParam.companyAddressId">
<el-option v-for="address in companyAddressList"
:key="address.id"
:value="address.id"
:label="address.addressName">
</el-option>
</el-select>
</el-col>
</el-row>
<!--
以下是第二组用于展示收货人姓名信息的 el-row el-col 组件通过插值表达式 {{currentAddress.name}} 展示收货人姓名具体值推测 currentAddress 是当前选择或关联的收货地址对象
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">收货人姓名</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.name}}</el-col>
</el-row>
<!--
以下是第三组用于展示所在区域信息的 el-row el-col 组件通过插值表达式 {{currentAddress | formatRegion}} 展示所在区域具体值使用了 formatRegion 过滤器推测用于对地址区域信息进行格式化处理使其显示更规范等
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">所在区域</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress | formatRegion}}</el-col>
</el-row>
<!--
以下是第四组用于展示详细地址信息的 el-row el-col 组件通过插值表达式 {{currentAddress.detailAddress}} 展示详细地址具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">详细地址</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.detailAddress}}</el-col>
</el-row>
<!--
以下是第五组用于展示联系电话信息的 el-row el-col 组件通过插值表达式 {{currentAddress.phone}} 展示联系电话具体值
-->
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">联系电话</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.phone}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">选择收货点
</el-col>
<el-col class="form-border font-small" style="height:52px" :span="18">
<el-select size="small"
style="width:200px"
:disabled="orderReturnApply.status!==0"
v-model="updateStatusParam.companyAddressId">
<el-option v-for="address in companyAddressList"
:key="address.id"
:value="address.id"
:label="address.addressName">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">收货人姓名</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.name}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">所在区域</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress | formatRegion}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">详细地址</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.detailAddress}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">联系电话</el-col>
<el-col class="form-border font-small" :span="18">{{currentAddress.phone}}</el-col>
</el-row>
</div>
</div>
<!--
以下是一个添加了 class="form-container-border" 类名且通过 v-show="orderReturnApply.status!==0" 根据服务单申请状态是否不等于 0 来决定是否显示的 div 容器内部包含用于展示处理人员处理时间处理备注等相关信息的 el-row el-col 组件结构和功能与前面类似时间相关的值使用对应的时间格式化过滤器进行处理
-->
<div class="form-container-border" v-show="orderReturnApply.status!==0">
</div>
<div class="form-container-border" v-show="orderReturnApply.status!==0">
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">处理人员</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleMan}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">处理人员</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleMan}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">处理时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleTime | formatTime}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">处理时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleTime | formatTime}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">处理备注</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleNote}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">处理备注</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.handleNote}}</el-col>
</el-row>
</div>
<!--
以下是一个添加了 class="form-container-border" 类名且通过 v-show="orderReturnApply.status===2" 根据服务单申请状态是否等于 2 来决定是否显示的 div 容器内部包含用于展示收货人员收货时间收货备注等相关信息的 el-row el-col 组件结构和功能与前面类似时间相关的值使用对应的时间格式化过滤器进行处理
-->
<div class="form-container-border" v-show="orderReturnApply.status===2">
</div>
<div class="form-container-border" v-show="orderReturnApply.status===2">
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">收货人员</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveMan}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">收货人员</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveMan}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" >收货时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveTime | formatTime}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6" >收货时间</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveTime | formatTime}}</el-col>
</el-row>
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6">收货备注</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveNote}}</el-col>
<el-col class="form-border form-left-bg font-small" :span="6">收货备注</el-col>
<el-col class="form-border font-small" :span="18">{{orderReturnApply.receiveNote}}</el-col>
</el-row>
</div>
</div>
<div class="form-container-border" v-show="orderReturnApply.status===0">
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">处理备注</el-col>
<el-col class="form-border font-small" :span="18">
<el-input size="small" v-model="updateStatusParam.handleNote" style="width:200px;margin-left: 10px"></el-input>
</el-col>
</el-row>
</div>
<div class="form-container-border" v-show="orderReturnApply.status===1">
<el-row>
<el-col class="form-border form-left-bg font-small" :span="6" style="height:52px;line-height:32px">收货备注</el-col>
<el-col class="form-border font-small" :span="18">
<el-input size="small" v-model="updateStatusParam.receiveNote" style="width:200px;margin-left: 10px"></el-input>
</el-col>
</el-row>
</div>
<div style="margin-top:15px;text-align: center" v-show="orderReturnApply.status===0">
<el-button type="primary" size="small" @click="handleUpdateStatus(1)">退</el-button>
<el-button type="danger" size="small" @click="handleUpdateStatus(3)">退</el-button>
</div>
<div style="margin-top:15px;text-align: center" v-show="orderReturnApply.status===1">
<el-button type="primary" size="small" @click="handleUpdateStatus(2)"></el-button>
</div>
</el-card>
</div>
</template>
<script>
// @/api/returnApply getApplyDetail updateApplyStatus API
import {getApplyDetail, updateApplyStatus} from '@/api/returnApply';
// @/api/companyAddress fetchList API
import {fetchList} from '@/api/companyAddress';
// @/utils/date formatDate
import {formatDate} from '@/utils/date';
// defaultUpdateStatusParam
const defaultUpdateStatusParam = {
companyAddressId: null,
handleMan: 'admin',
handleNote: null,
receiveMan: 'admin',
receiveNote: null,
returnAmount: 0,
status: 0
};
// defaultOrderReturnApply null
const defaultOrderReturnApply = {
import {getApplyDetail,updateApplyStatus} from '@/api/returnApply';
import {fetchList} from '@/api/companyAddress';
import {formatDate} from '@/utils/date';
const defaultUpdateStatusParam = {
companyAddressId: null,
handleMan: 'admin',
handleNote: null,
receiveMan: 'admin',
receiveNote: null,
returnAmount: 0,
status: 0
};
const defaultOrderReturnApply = {
id: null,
orderId: null,
companyAddressId: null,
productId: null,
orderSn: null,
createTime: null,
memberUsername: null,
returnAmount: null,
returnName: null,
returnPhone: null,
status: null,
handleTime: null,
productPic: null,
productName: null,
productBrand: null,
productAttr: null,
productCount: null,
productPrice: null,
productRealPrice: null,
reason: null,
description: null,
proofPics: null,
handleNote: null,
handleMan: null,
receiveMan: null,
receiveTime: null,
receiveNote: null
};
export default {
name: 'returnApplyDetail',
data() {
return {
id: null,
orderId: null,
companyAddressId: null,
productId: null,
orderSn: null,
createTime: null,
memberUsername: null,
returnAmount: null,
returnName: null,
returnPhone: null,
status: null,
handleTime: null,
productPic: null,
productName: null,
productBrand: null,
productAttr: null,
productCount: null,
productPrice: null,
productRealPrice: null,
reason: null,
description: null,
orderReturnApply: Object.assign({},defaultOrderReturnApply),
productList: null,
proofPics: null,
handleNote: null,
handleMan: null,
receiveMan: null,
receiveTime: null,
receiveNote: null
};
// Vue returnApplyDetail
export default {
name: 'returnApplyDetail',
// Vue data
data() {
return {
// null
id: null,
// Object.assign orderReturnApply defaultOrderReturnApply
orderReturnApply: Object.assign({}, defaultOrderReturnApply),
// null
productList: null,
// null
proofPics: null,
// Object.assign updateStatusParam defaultUpdateStatusParam
updateStatusParam: Object.assign({}, defaultUpdateStatusParam),
// null
companyAddressList: null
}
},
// created
created() {
// id id
this.id = this.$route.query.id;
// getDetail
this.getDetail();
},
// computed
computed: {
// totalAmount
totalAmount() {
// orderReturnApply null
if (this.orderReturnApply!= null) {
// productRealPriceproductCount
return this.orderReturnApply.productRealPrice * this.orderReturnApply.productCount;
} else {
// orderReturnApply null 0
return 0;
}
},
// currentAddress
currentAddress() {
console.log("currentAddress()");
// updateStatusParam ID
let id = this.updateStatusParam.companyAddressId;
// null
if (this.companyAddressList == null) return {};
//
for (let i = 0; i < this.companyAddressList.length; i++) {
let address = this.companyAddressList[i];
// ID
if (address.id === id) {
return address;
}
}
// null
return null;
}
},
// filters
filters: {
// formatStatus
formatStatus(status) {
if (status === 0) {
return "待处理";
} else if (status === 1) {
return "退货中";
} else if (status === 2) {
return "已完成";
} else {
return "已拒绝";
}
},
// formatTime
formatTime(time) {
if (time == null || time === '') {
return 'N/A';
}
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
// formatRegion
formatRegion(address) {
let str = address.province;
if (address.city!= null) {
str += " " + address.city;
}
str += " " + address.region;
return str;
}
},
// methods
methods: {
// handleViewOrder
handleViewOrder() {
// 使 Vue Router $router.push /oms/orderDetail ID 便
this.$router.push({path: '/oms/orderDetail', query: {id: this.orderReturnApply.orderId}});
},
// getDetail
getDetail() {
console.log("getDetail")
// getApplyDetail API ID
getApplyDetail(this.id).then(response => {
// orderReturnApply
this.orderReturnApply = response.data;
//
this.productList = [];
//
this.productList.push(this.orderReturnApply);
// proofPics null proofPics 便
if (this.orderReturnApply.proofPics!= null) {
this.proofPics = this.orderReturnApply.proofPics.split(",")
}
// 1退 2退 ID 使
if (this.orderReturnApply.status === 1 || this.orderReturnApply.status === 2) {
this.updateStatusParam.returnAmount = this.orderReturnApply.returnAmount;
this.updateStatusParam.companyAddressId = this.orderReturnApply.companyAddressId;
}
// getCompanyAddressList
this.getCompanyAddressList();
});
},
// getCompanyAddressList
getCompanyAddressList() {
console.log("getCompanyAddressList()")
// fetchList API
fetchList().then(response => {
// companyAddressList
this.companyAddressList = response.data;
//
for (let i = 0; i < this.companyAddressList.length; i++) {
// 1 0 ID ID
if (this.companyAddressList[i].receiveStatus === 1 && this.orderReturnApply.status === 0) {
this.updateStatusParam.companyAddressId = this.companyAddressList[i].id;
}
}
});
},
// handleUpdateStatus
handleUpdateStatus(status) {
// status 使
this.updateStatusParam.status = status;
// 使 $confirm Element UI
this.$confirm('是否要进行此操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// updateApplyStatus API ID
updateApplyStatus(this.id, this.updateStatusParam).then(response => {
// 使 $message Element UI
this.$message({
type: 'success',
message: '操作成功!',
duration: 1000
});
// 使 $router.back() 退
this.$router.back();
});
});
}
updateStatusParam: Object.assign({}, defaultUpdateStatusParam),
companyAddressList: null
}
},
created() {
this.id = this.$route.query.id;
this.getDetail();
},
computed: {
totalAmount() {
if (this.orderReturnApply != null) {
return this.orderReturnApply.productRealPrice * this.orderReturnApply.productCount;
} else {
return 0;
}
},
currentAddress() {
console.log("currentAddress()");
let id = this.updateStatusParam.companyAddressId;
if(this.companyAddressList==null)return {};
for (let i = 0; i < this.companyAddressList.length; i++) {
let address = this.companyAddressList[i];
if (address.id === id) {
return address;
}
}
return null;
}
},
filters: {
formatStatus(status) {
if (status === 0) {
return "待处理";
} else if (status === 1) {
return "退货中";
} else if (status === 2) {
return "已完成";
} else {
return "已拒绝";
}
},
formatTime(time) {
if (time == null || time === '') {
return 'N/A';
}
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
formatRegion(address) {
let str = address.province;
if (address.city != null) {
str += " " + address.city;
}
str += " " + address.region;
return str;
}
},
methods: {
handleViewOrder(){
this.$router.push({path:'/oms/orderDetail',query:{id:this.orderReturnApply.orderId}});
},
getDetail() {
getApplyDetail(this.id).then(response => {
console.log("getDetail")
this.orderReturnApply = response.data;
this.productList = [];
this.productList.push(this.orderReturnApply);
if (this.orderReturnApply.proofPics != null) {
this.proofPics = this.orderReturnApply.proofPics.split(",")
}
//退
if(this.orderReturnApply.status===1||this.orderReturnApply.status===2){
this.updateStatusParam.returnAmount=this.orderReturnApply.returnAmount;
this.updateStatusParam.companyAddressId=this.orderReturnApply.companyAddressId;
}
this.getCompanyAddressList();
});
},
getCompanyAddressList() {
fetchList().then(response => {
console.log("getCompanyAddressList()")
this.companyAddressList = response.data;
for (let i = 0; i < this.companyAddressList.length; i++) {
if (this.companyAddressList[i].receiveStatus === 1&&this.orderReturnApply.status===0) {
this.updateStatusParam.companyAddressId = this.companyAddressList[i].id;
}
}
});
},
handleUpdateStatus(status){
this.updateStatusParam.status=status;
this.$confirm('是否要进行此操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
updateApplyStatus(this.id,this.updateStatusParam).then(response=>{
this.$message({
type: 'success',
message: '操作成功!',
duration:1000
});
this.$router.back();
});
});
}
}
}
</script>
<style scoped>
/* 定义名为 detail-container 的类选择器样式设置其定位为绝对定位水平方向铺满整个父容器left: 0; right: 0;),宽度为 1080 像素,设置内边距以及外边距,用于布局和样式展示,可能是整个服务单详情页面的主要容器样式 */
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #DCDFE6;
border-bottom: 1px solid #DCDFE6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #DCDFE6;
border-top: 1px solid #DCDFE6;
margin-top: 15px;
}
.form-left-bg {
background: #F2F6FC;
}
</style>
/* 定义名为 standard-margin 的类选择器样式,设置顶部外边距为 15 像素,用于给某些元素添加统一的间距,使页面布局更美观 */
.standard-margin {
margin-top: 15px;
}
/* 定义名为 form-border 的类选择器样式,设置右边框和下边框为 1 像素的实线,颜色为 #DCDFE6同时设置内边距用于给表单相关的元素添加边框和合适的内边距使其展示更清晰、美观 */
.form-border {
border-right: 1px solid #DCDFE6;
border-bottom: 1px solid #DCDFE6;
padding: 10px;
}
/* 定义名为 form-container-border 的类选择器样式,设置左边框和上边框为 1 像素的实线,颜色为 #DCDFE6同时设置顶部外边距用于给包含表单元素的容器添加边框区分不同的信息块 */
.form-container-border {
border-left: 1px solid #DCDFE6;
border-top: 1px solid #DCDFE6;
margin-top: 15px;
}
/* 定义名为 form-left-bg 的类选择器样式,设置背景颜色为 #F2F6FC可能用于给表单左边栏等特定区域设置背景色起到区分和美化的作用 */
.form-left-bg {
background: #F2F6FC;
}
</style>

@ -1,380 +1,275 @@
<template>
<!-- 整个页面内容的容器添加了 app-container 类名用于整体布局和样式控制 -->
<div class="app-container">
<!-- 使用 el-card 组件创建一个卡片式的容器用于放置筛选搜索相关的内容设置 shadow="never" 表示不显示阴影效果添加了 filter-container 类名用于样式定制 -->
<el-card class="filter-container" shadow="never">
<div>
<!-- 使用 el-icon-search 图标类Element UI 提供的图标展示一个搜索图标用于提示用户此处是筛选搜索功能区域 -->
<i class="el-icon-search"></i>
<!-- 展示一个文本标签内容为筛选搜索用于明确此区域的功能 -->
<span>筛选搜索</span>
<!-- 使用 el-button 组件创建一个按钮设置样式为右浮动float:right按钮类型为 primary通常是主要操作按钮的样式绑定了点击事件 handleSearchList()点击按钮会调用该方法按钮尺寸为 small小尺寸按钮按钮文本为查询搜索用于触发查询搜索的操作 -->
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<!-- 使用 el-button 组件创建一个按钮设置样式为右浮动且距离右边有 15 像素的外边距float:right;margin-right: 15px绑定了点击事件 handleResetSearch()点击按钮会调用该方法按钮尺寸为 small按钮文本为重置用于将筛选搜索的条件重置为默认状态 -->
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<!-- 使用 el-form 组件创建一个表单设置 :inline="true" 表示表单为行内表单各表单项在一行内排列:model="listQuery" 将表单数据与 listQuery 对象进行双向绑定size="small" 表示表单尺寸为小尺寸label-width="140px" 设置表单标签的宽度为 140 像素用于布局表单各项输入框和选择框等元素 -->
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<!-- el-form-item 组件用于定义表单中的每一项此处的标签文本为输入搜索用于提示用户此项的功能 -->
<el-form-item label="输入搜索:">
<!-- 使用 el-input 组件创建一个输入框通过 v-model="listQuery.id" 将输入框的值与 listQuery 对象中的 id 属性进行双向绑定添加了 input-width 类名推测用于设置宽度等样式 CSS 部分有定义placeholder="服务单号" 设置输入框的占位提示文本为服务单号用户可在此输入服务单号相关内容进行搜索 -->
<el-input v-model="listQuery.id" class="input-width" placeholder="服务单号"></el-input>
</el-form-item>
<el-form-item label="处理状态:">
<!-- 使用 el-select 组件创建一个下拉选择框通过 v-model="listQuery.status" 将选择框选中的值与 listQuery 对象中的 status 属性进行双向绑定placeholder="全部" 设置占位提示文本为全部clearable 表示可以清空选择框的值添加了 input-width 类名用于样式设置内部通过 v-for 指令循环遍历 statusOptions 数组 Vue 实例的 data 或其他地方定义为每个元素创建一个 el-option 选项用于展示不同的处理状态选项供用户选择 -->
<el-select v-model="listQuery.status" placeholder="全部" clearable class="input-width">
<el-option v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="申请时间:">
<!-- 使用 el-date-picker 组件创建一个日期选择器添加了 input-width 类名用于样式设置通过 v-model="listQuery.createTime" 将选择的日期值与 listQuery 对象中的 createTime 属性进行双向绑定value-format="yyyy-MM-dd" 定义日期选择器返回的日期格式为yyyy-MM-ddtype="date" 表示选择器类型为日期选择只选择年月日placeholder="请选择时间" 设置占位提示文本用户可在此选择申请时间进行筛选 -->
<el-date-picker
class="input-width"
v-model="listQuery.createTime"
value-format="yyyy-MM-dd"
type="date"
placeholder="请选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="操作人员:">
<!-- 使用 el-input 组件创建一个输入框通过 v-model="listQuery.handleMan" 将输入框的值与 listQuery 对象中的 handleMan 属性进行双向绑定添加了 input-width 类名用于样式设置placeholder="全部" 设置占位提示文本为全部用户可在此输入操作人员相关内容进行搜索 -->
<el-input v-model="listQuery.handleMan" class="input-width" placeholder="全部"></el-input>
</el-form-item>
<el-form-item label="处理时间:">
<!-- 使用 el-date-picker 组件创建一个日期选择器与上面申请时间的日期选择器类似通过 v-model="listQuery.handleTime" 将选择的日期值与 listQuery 对象中的 handleTime 属性进行双向绑定用于选择处理时间进行筛选 -->
<el-date-picker
class="input-width"
v-model="listQuery.handleTime"
value-format="yyyy-MM-dd"
type="date"
placeholder="请选择时间">
</el-date-picker>
</el-form-item>
</el-form>
</div>
</el-card>
<!-- 使用 el-card 组件创建一个卡片式的容器添加了 operate-container 类名用于样式定制内部只展示了一个图标和一个文本标签用于提示此区域是关于数据列表相关内容但目前看起来只是一个标题性质的展示可能后续会添加更多相关操作按钮等元素 -->
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
</el-card>
<!-- 创建一个 div 容器添加了 table-container 类名用于样式控制用于放置数据表格相关内容 -->
<div class="table-container">
<!-- 使用 el-table 组件创建一个表格ref="returnApplyTable" 给表格添加一个引用标识方便在 Vue 实例的 JavaScript 代码中通过 this.$refs.returnApplyTable 来获取这个表格组件的实例:data="list" 将表格的数据与 list 数组 Vue 实例中定义用于存储要展示的数据列表进行绑定设置表格宽度为 100%铺满父容器绑定了 @selection-change 事件当表格行的选择状态改变时会调用 handleSelectionChange 方法v-loading="listLoading" 根据 listLoading 的值布尔类型用于表示是否正在加载数据来显示或隐藏加载动画border 属性给表格添加边框使表格样式更清晰 -->
<el-table ref="returnApplyTable"
:data="list"
style="width: 100%;"
@selection-change="handleSelectionChange"
v-loading="listLoading" border>
<!-- 使用 el-table-column 组件定义表格的列type="selection" 表示此列为选择列用于勾选表格行width="60" 设置列宽为 60 像素align="center" 将列内容在水平方向居中对齐 -->
<el-table-column type="selection" width="60" align="center"></el-table-column>
<el-table-column label="服务单号" width="180" align="center">
<!-- 在表格列中使用 template 结合 slot-scope="scope" 的方式自定义单元格内容的展示通过插值表达式 {{scope.row.id}} scope 对象中 row 属性下的 id 字段获取对应的值并渲染显示也就是展示每一行对应的服务单号信息 -->
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="申请时间" width="180" align="center">
<!-- 同样使用 template slot-scope 自定义单元格内容展示通过插值表达式 {{scope.row.createTime | formatTime}} 展示申请时间信息使用了 formatTime 过滤器 Vue 实例的 filters 中定义用于将时间格式进行格式化处理对时间数据进行处理后再展示 -->
<template slot-scope="scope">{{scope.row.createTime | formatTime}}</template>
</el-table-column>
<el-table-column label="用户账号" align="center">
<!-- 通过插值表达式 {{scope.row.memberUsername}} 展示每一行对应的用户账号信息 scope 对象中获取相关数据 -->
<template slot-scope="scope">{{scope.row.memberUsername}}</template>
</el-table-column>
<el-table-column label="退款金额" width="180" align="center">
<!-- 通过插值表达式 {{scope.row | formatReturnAmount}} 展示退款金额信息使用了 formatReturnAmount 过滤器 Vue 实例的 filters 中定义用于根据业务逻辑计算并返回退款金额的值可能是基于商品价格数量等因素计算对数据进行处理后再展示前面添加符号表示人民币金额 -->
<template slot-scope="scope">{{scope.row | formatReturnAmount}}</template>
</el-table-column>
<el-table-column label="申请状态" width="180" align="center">
<!-- 通过插值表达式 {{scope.row.status | formatStatus}} 展示申请状态信息使用了 formatStatus 过滤器 Vue 实例的 filters 中定义用于将状态的数字值转换为对应的文字描述使展示更友好易懂对状态数据进行处理后再展示 -->
<template slot-scope="scope">{{scope.row.status | formatStatus}}</template>
</el-table-column>
<el-table-column label="处理时间" width="180" align="center">
<!-- 通过插值表达式 {{scope.row.handleTime | formatTime}} 展示处理时间信息使用 formatTime 过滤器对时间数据进行格式化处理后展示 -->
<template slot-scope="scope">{{scope.row.handleTime | formatTime}}</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<!-- 在表格列的单元格中使用 el-button 组件创建一个按钮设置按钮尺寸为 mini最小尺寸按钮绑定了点击事件 handleViewDetail(scope.$index, scope.row)点击按钮会调用该方法并传入当前行的索引scope.$index和当前行的数据对象scope.row按钮文本为查看详情用于跳转到对应服务单的详情页面查看详细信息 -->
<el-button
size="mini"
@click="handleViewDetail(scope.$index, scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 创建一个 div 容器添加了 batch-operate-container 类名用于样式控制用于放置批量操作相关的元素如下拉选择框和按钮等 -->
<div class="batch-operate-container">
<!-- 使用 el-select 组件创建一个下拉选择框设置尺寸为 small通过 v-model="operateType" 将选择框选中的值与 operateType 属性进行双向绑定placeholder="批量操作" 设置占位提示文本用于选择要进行的批量操作类型内部通过 v-for 指令循环遍历 operateOptions 数组 Vue 实例的 data 中定义为每个元素创建一个 el-option 选项展示不同的批量操作选项供用户选择 -->
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operateOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="输入搜索:">
<el-input v-model="listQuery.id" class="input-width" placeholder="服务单号"></el-input>
</el-form-item>
<el-form-item label="处理状态:">
<el-select v-model="listQuery.status" placeholder="全部" clearable class="input-width">
<el-option v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- 使用 el-button 组件创建一个按钮设置样式距离左边有 20 像素的外边距margin-left: 20px添加了 search-button 类名推测用于样式设置虽然 CSS 部分未看到具体样式定义绑定了点击事件 handleBatchOperate()点击按钮会调用该方法按钮类型为 primary按钮尺寸为 small按钮文本为确定用于触发批量操作的执行 -->
</el-form-item>
<el-form-item label="申请时间:">
<el-date-picker
class="input-width"
v-model="listQuery.createTime"
value-format="yyyy-MM-dd"
type="date"
placeholder="请选择时间">
</el-date-picker>
</el-form-item>
<el-form-item label="操作人员:">
<el-input v-model="listQuery.handleMan" class="input-width" placeholder="全部"></el-input>
</el-form-item>
<el-form-item label="处理时间:">
<el-date-picker
class="input-width"
v-model="listQuery.handleTime"
value-format="yyyy-MM-dd"
type="date"
placeholder="请选择时间">
</el-date-picker>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
</el-card>
<div class="table-container">
<el-table ref="returnApplyTable"
:data="list"
style="width: 100%;"
@selection-change="handleSelectionChange"
v-loading="listLoading" border>
<el-table-column type="selection" width="60" align="center"></el-table-column>
<el-table-column label="服务单号" width="180" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="申请时间" width="180" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatTime}}</template>
</el-table-column>
<el-table-column label="用户账号" align="center">
<template slot-scope="scope">{{scope.row.memberUsername}}</template>
</el-table-column>
<el-table-column label="退款金额" width="180" align="center">
<template slot-scope="scope">{{scope.row | formatReturnAmount}}</template>
</el-table-column>
<el-table-column label="申请状态" width="180" align="center">
<template slot-scope="scope">{{scope.row.status | formatStatus}}</template>
</el-table-column>
<el-table-column label="处理时间" width="180" align="center">
<template slot-scope="scope">{{scope.row.handleTime | formatTime}}</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<!-- 创建一个 div 容器添加了 pagination-container 类名用于样式控制用于放置分页相关的组件 -->
<div class="pagination-container">
<!-- 使用 el-pagination 组件创建分页器background 属性表示给分页按钮等添加背景色绑定了 @size-change 事件和 @current-change 事件分别在页面大小改变和当前页码改变时调用 handleSizeChange 方法和 handleCurrentChange 方法layout 属性定义分页器的布局显示哪些元素如总条数每页条数选择上一页页码下一页跳转到指定页等:current-page.sync="listQuery.pageNum" 通过双向绑定将当前页码与 listQuery 对象中的 pageNum 属性关联起来:page-size="listQuery.pageSize" 将每页显示的条数与 listQuery 对象中的 pageSize 属性关联起来:page-sizes="[5,10,15]" 定义可选择的每页条数的选项数组:total="total" 将总数据条数与 total 属性关联起来用于分页功能的展示和交互 -->
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:total="total">
</el-pagination>
</div>
size="mini"
@click="handleViewDetail(scope.$index, scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="batch-operate-container">
<el-select
size="small"
v-model="operateType" placeholder="批量操作">
<el-option
v-for="item in operateOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button
style="margin-left: 20px"
class="search-button"
@click="handleBatchOperate()"
type="primary"
size="small">
确定
</el-button>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// @/utils/date formatDate 使
import {formatDate} from '@/utils/date';
// @/api/returnApply fetchList deleteApply fetchList deleteApply API
import {fetchList, deleteApply} from '@/api/returnApply';
// defaultListQuery
//
// pageNum: 1
// pageSize: 10 10
// id: null
// receiverKeyword: null
// status: null
// createTime: null
// handleMan: null
// handleTime: null
const defaultListQuery = {
pageNum: 1,
pageSize: 10,
id: null,
receiverKeyword: null,
status: null,
createTime: null,
handleMan: null,
handleTime: null
};
// defaultStatusOptions
// 'label' '' 'value'使 0
const defaultStatusOptions = [
{
label: '待处理',
value: 0
},
{
label: '退货中',
import {formatDate} from '@/utils/date';
import {fetchList,deleteApply} from '@/api/returnApply';
const defaultListQuery = {
pageNum: 1,
pageSize: 10,
id: null,
receiverKeyword: null,
status: null,
createTime: null,
handleMan: null,
handleTime: null
};
const defaultStatusOptions=[
{
label: '待处理',
value: 0
},
{
label: '退货中',
value: 1
},
{
label: '已完成',
value: 2
},
{
label: '已拒绝',
value: 3
}
];
export default {
name:'returnApplyList',
data() {
return {
listQuery:Object.assign({},defaultListQuery),
statusOptions: Object.assign({},defaultStatusOptions),
list:null,
total:null,
listLoading:false,
multipleSelection:[],
operateType:1,
operateOptions: [
{
label: "批量删除",
value: 1
},
{
label: '已完成',
value: 2
},
{
label: '已拒绝',
value: 3
}
],
}
},
created(){
this.getList();
},
filters:{
formatTime(time) {
if(time==null||time===''){
return 'N/A';
}
];
// returnApplyList Vue
export default {
name:'returnApplyList',
// data
data() {
return {
// Object.assign listQuery defaultListQuery
listQuery: Object.assign({}, defaultListQuery),
// Object.assign statusOptions defaultStatusOptions
statusOptions: Object.assign({}, defaultStatusOptions),
// null fetchList
list: null,
// null便
total: null,
// false fetchList true false便
listLoading: false,
// handleSelectionChange
multipleSelection: [],
// 1 1
operateType: 1,
// 'label' "" 'value' 1
operateOptions: [
{
label: "批量删除",
value: 1
}
],
}
},
// created getList
created() {
this.getList();
},
// filters
filters: {
// formatTime
// time null 'N/A'
// time new Date(time) JavaScript Date formatDate @/utils/date 'yyyy-MM-dd hh:mm:ss'
formatTime(time) {
if (time == null || time === '') {
return 'N/A';
}
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
// formatStatus
// defaultStatusOptions status value label 便
formatStatus(status) {
for (let i = 0; i < defaultStatusOptions.length; i++) {
if (status === defaultStatusOptions[i].value) {
return defaultStatusOptions[i].label;
}
}
},
// formatReturnAmount 退
// row productRealPrice productCount退便退
formatReturnAmount(row) {
return row.productRealPrice * row.productCount;
}
},
// methods
methods: {
// handleSelectionChange
// val multipleSelection 使 multipleSelection 便
handleSelectionChange(val) {
this.multipleSelection = val;
},
// handleResetSearch
// listQuery defaultListQuery
handleResetSearch() {
this.listQuery = Object.assign({}, defaultListQuery);
},
// handleSearchList
// listQuery pageNum 1 getList listQuery
handleSearchList() {
this.listQuery.pageNum = 1;
this.getList();
},
// handleViewDetail
// index row
// 使 Vue Router $router.push '/oms/returnApplyDetail' id row.id 便 id
handleViewDetail(index, row) {
this.$router.push({path: '/oms/returnApplyDetail', query: {id: row.id}})
},
// handleBatchOperate
// multipleSelection null 1 $message Element UI
// operateType 1 $confirm Element UI
//
// 1. URLSearchParams URL
// 2. multipleSelection id ids
// 3. 使 params.append("ids", ids) ids URLSearchParams
// 4. deleteApply params then getList $message
handleBatchOperate() {
if (this.multipleSelection == null || this.multipleSelection.length < 1) {
this.$message({
message: '请选择要操作的申请',
type: 'warning',
duration: 1000
});
return;
}
if (this.operateType === 1) {
//
this.$confirm('是否要进行删除操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = new URLSearchParams();
let ids = [];
for (let i = 0; i < this.multipleSelection.length; i++) {
ids.push(this.multipleSelection[i].id);
}
params.append("ids", ids);
deleteApply(params).then(response => {
this.getList();
this.$message({
type: 'success',
message: '删除成功!'
});
});
})
}
},
// handleSizeChange
// val listQuery pageNum 1 listQuery pageSize val getList
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
// handleCurrentChange
// val listQuery pageNum val getList
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
// getList
// listLoading true
// fetchList listQuery then
// 1. listLoading false
// 2. list
// 3. total 便
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
},
formatStatus(status){
for(let i=0;i<defaultStatusOptions.length;i++){
if(status===defaultStatusOptions[i].value){
return defaultStatusOptions[i].label;
}
}
},
formatReturnAmount(row){
return row.productRealPrice*row.productCount;
}
},
methods:{
handleSelectionChange(val){
this.multipleSelection = val;
},
handleResetSearch() {
this.listQuery = Object.assign({}, defaultListQuery);
},
handleSearchList() {
this.listQuery.pageNum = 1;
this.getList();
},
handleViewDetail(index,row){
this.$router.push({path:'/oms/returnApplyDetail',query:{id:row.id}})
},
handleBatchOperate(){
if(this.multipleSelection==null||this.multipleSelection.length<1){
this.$message({
message: '请选择要操作的申请',
type: 'warning',
duration: 1000
});
return;
}
if(this.operateType===1){
//
this.$confirm('是否要进行删除操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = new URLSearchParams();
let ids=[];
for(let i=0;i<this.multipleSelection.length;i++){
ids.push(this.multipleSelection[i].id);
}
params.append("ids",ids);
deleteApply(params).then(response=>{
this.getList();
this.$message({
type: 'success',
message: '删除成功!'
});
});
})
}
},
handleSizeChange(val){
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val){
this.listQuery.pageNum = val;
this.getList();
},
getList(){
this.listLoading=true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
}
}
}
</script>
<style scoped>
/* .input-width 203
HTML 模板中那些添加了这个类名的元素比如某些输入框等就会应用这个宽度样式起到统一控制相关元素宽度使页面布局更规整的作用 */
.input-width {
width: 203px;
}
width: 203px;
}
</style>

@ -104,14 +104,6 @@
</el-dialog>
</div>
</template>
<script>
import {formatDate} from '@/utils/date';
import {fetchList,deleteReason,updateStatus,addReason,getReasonDetail,updateReason} from '@/api/returnReason';
@ -272,9 +264,6 @@
}
}
</script>
<style scoped>
.input-width {
width: 80%;

@ -1,26 +1,12 @@
<template>
<!-- el-dialog组件用于创建一个对话框这里用于展示订单跟踪相关内容 -->
<!-- title属性设置对话框的标题为"订单跟踪" -->
<!-- :visible.sync是双向绑定属性用于控制对话框的显示与隐藏绑定到组件实例中的visible属性 -->
<!-- :before-close绑定了一个关闭前的处理函数handleClose用于在关闭对话框时执行一些操作 -->
<!-- width属性设置对话框的宽度为页面宽度的40% -->
<template> 
<el-dialog title="订单跟踪"
:visible.sync="visible"
:before-close="handleClose"
width="40%">
<!-- el-steps组件用于创建竖向排列的步骤条用于展示订单物流的各个步骤 -->
<!-- direction="vertical"表示步骤条竖向排列 -->
<!-- :active="6"表示默认激活第6个步骤索引从0开始计数 -->
<!-- finish-status="success"表示已完成的步骤显示为成功状态通常有相应的样式体现 -->
<!-- space="50px"设置每个步骤之间的间距为50像素 -->
<el-steps direction="vertical"
:active="6"
finish-status="success"
space="50px">
<!-- 使用v-for指令循环遍历logisticsList数组为每个元素创建一个el-step组件用于展示物流的单个步骤 -->
<!-- :key属性绑定唯一标识这里用item.name便于Vue进行高效的DOM更新 -->
<!-- :title属性绑定步骤的标题对应item.name -->
<!-- :description属性绑定步骤的描述信息对应item.time -->
<el-step v-for="item in logisticsList"
:key="item.name"
:title="item.name"
@ -29,7 +15,6 @@
</el-dialog>
</template>
<script>
// nametime
const defaultLogisticsList=[
{name: '订单已提交,等待付款',time:'2017-04-01 12:00:00 '},
{name: '订单付款成功',time:'2017-04-01 12:00:00 '},
@ -41,17 +26,14 @@
];
export default {
name:'logisticsDialog',
// value
props: {
value: Boolean
},
computed:{
visible: {
// getvisiblevalue
get() {
return this.value;
},
// setvisiblevisiblevalue
set(visible){
this.value=visible;
}
@ -59,20 +41,19 @@
},
data() {
return {
// logisticsListlogisticsList
logisticsList:Object.assign({},defaultLogisticsList)
}
},
methods:{
// emitInput'input'val
emitInput(val) {
this.$emit('input', val)
},
// emitInputfalsevisible
handleClose(){
this.emitInput(false);
}
}
}
</script>
<style></style>
<style></style>

@ -1,134 +1,99 @@
<template>
<!-- 整个页面内容的外层容器添加了 app-container 类名用于整体的布局控制以及样式应用可能在对应的 CSS 文件中有相关样式定义 -->
<div class="app-container">
<!-- 使用 el-card 组件创建一个卡片式的容器添加了 operate-container 类名用于特定样式定制设置 shadow="never" 表示该卡片不显示阴影效果内部包含一个图标和一个文本标签用于提示此区域是和发货列表相关的内容 -->
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>发货列表</span>
</el-card>
<!-- 创建一个 div 容器添加了 table-container 类名用于样式控制用于放置包含发货信息的表格以及相关操作按钮等内容 -->
<div class="table-container">
<!-- 使用 el-table 组件创建一个表格ref="deliverOrderTable" 给表格添加了一个引用标识方便在 Vue 实例的 JavaScript 代码中通过 this.$refs.deliverOrderTable 来获取这个表格组件的实例设置表格宽度为 100%以铺满父容器通过 :data="list" 将表格要展示的数据与 list 数组 Vue 实例的 data 中定义进行绑定border 属性用于给表格添加边框使其样式更清晰美观 -->
<el-table ref="deliverOrderTable"
style="width: 100%;"
:data="list" border>
<!-- 使用 el-table-column 组件定义表格的列label="订单编号" 设置该列在表头显示的标题为订单编号width="180" 设置列宽为 180 像素align="center" 将列内容在水平方向上进行居中对齐内部使用 template 结合 slot-scope="scope" 的方式来自定义单元格内容展示通过插值表达式 {{scope.row.orderSn}} scope 对象中 row 属性下的 orderSn 字段获取对应的值并渲染显示也就是展示每一行对应的订单编号信息 -->
<el-table-column label="订单编号" width="180" align="center">
<template slot-scope="scope">{{scope.row.orderSn}}</template>
</el-table-column>
<el-table-column label="收货人" width="180" align="center">
<template slot-scope="scope">{{scope.row.receiverName}}</template>
</el-table-column>
<el-table-column label="手机号码" width="160" align="center">
<template slot-scope="scope">{{scope.row.receiverPhone}}</template>
</el-table-column>
<el-table-column label="邮政编码" width="160" align="center">
<template slot-scope="scope">{{scope.row.receiverPostCode}}</template>
</el-table-column>
<el-table-column label="收货地址" align="center">
<template slot-scope="scope">{{scope.row.address}}</template>
</el-table-column>
<el-table-column label="配送方式" width="160" align="center">
<template slot-scope="scope">
<!-- 在表格列的单元格中使用 el-select 组件创建一个下拉选择框placeholder="请选择物流公司" 设置下拉框的占位提示文本v-model="scope.row.deliveryCompany" 通过双向数据绑定将选择框选中的值与当前行数据对象scope.row中的 deliveryCompany 属性进行绑定方便数据的更新与获取size="small" 表示下拉框为小尺寸内部通过 v-for 指令循环遍历 companyOptions 数组 Vue 实例的 data 中定义用于存储物流公司名称列表为每个元素创建一个 el-option 选项:key:label :value 都设置为当前元素也就是每个选项的唯一标识显示文本以及对应的值都为物流公司名称用于展示可供选择的物流公司选项 -->
<el-select placeholder="请选择物流公司"
v-model="scope.row.deliveryCompany"
size="small">
<el-option v-for="item in companyOptions"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="物流单号" width="180" align="center">
<template slot-scope="scope">
<!-- 在表格列的单元格中使用 el-input 组件创建一个输入框size="small" 表示输入框为小尺寸v-model="scope.row.deliverySn" 通过双向数据绑定将输入框的值与当前行数据对象scope.row中的 deliverySn 属性进行绑定方便输入物流单号后的数据更新与获取 -->
<el-input size="small" v-model="scope.row.deliverySn"></el-input>
</template>
</el-table-column>
</el-table>
<!-- 创建一个 div 容器设置顶部外边距为 15 像素margin-top: 15px文本水平居中text-align: center用于放置操作按钮包括取消确定按钮 -->
<div style="margin-top: 15px;text-align: center">
<!-- 使用 el-button 组件创建一个按钮绑定了 click 事件点击按钮会调用 cancel 方法 Vue 实例的 methods 中定义按钮文本为取消用于取消当前操作并返回上一个页面等相关逻辑 -->
<el-button @click="cancel"></el-button>
<!-- 使用 el-button 组件创建一个按钮绑定了 click 事件点击按钮会调用 confirm 方法 Vue 实例的 methods 中定义按钮类型为 primary通常表示主要操作按钮样式上会有相应突出显示按钮文本为确定用于触发发货操作等相关业务逻辑 -->
<el-button @click="confirm" type="primary">确定</el-button>
</div>
</div>
<template> 
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>发货列表</span>
</el-card>
<div class="table-container">
<el-table ref="deliverOrderTable"
style="width: 100%;"
:data="list" border>
<el-table-column label="订单编号" width="180" align="center">
<template slot-scope="scope">{{scope.row.orderSn}}</template>
</el-table-column>
<el-table-column label="收货人" width="180" align="center">
<template slot-scope="scope">{{scope.row.receiverName}}</template>
</el-table-column>
<el-table-column label="手机号码" width="160" align="center">
<template slot-scope="scope">{{scope.row.receiverPhone}}</template>
</el-table-column>
<el-table-column label="邮政编码" width="160" align="center">
<template slot-scope="scope">{{scope.row.receiverPostCode}}</template>
</el-table-column>
<el-table-column label="收货地址" align="center">
<template slot-scope="scope">{{scope.row.address}}</template>
</el-table-column>
<el-table-column label="配送方式" width="160" align="center">
<template slot-scope="scope">
<el-select placeholder="请选择物流公司"
v-model="scope.row.deliveryCompany"
size="small">
<el-option v-for="item in companyOptions"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="物流单号" width="180" align="center">
<template slot-scope="scope">
<el-input size="small" v-model="scope.row.deliverySn"></el-input>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 15px;text-align: center">
<el-button @click="cancel"></el-button>
<el-button @click="confirm" type="primary">确定</el-button>
</div>
</div>
</div>
</template>
<script>
// @/api/order deliveryOrder API
import {deliveryOrder} from '@/api/order'
// defaultLogisticsCompanies
const defaultLogisticsCompanies = ["顺丰快递", "圆通快递", "中通快递", "韵达快递"];
// deliverOrderList Vue
export default {
name: 'deliverOrderList',
// data
data() {
return {
//
list: [],
// defaultLogisticsCompanies companyOptions 使
companyOptions: defaultLogisticsCompanies
}
},
// created list
created() {
// list list
this.list = this.$route.query.list;
// list instanceof Array list list
if (this.list instanceof Array === false) {
this.list = [];
}
},
// methods
methods: {
// cancel Vue Router $router.back() 退
cancel() {
this.$router.back();
},
// confirm
confirm() {
// 使 $confirm Element UI warning
this.$confirm('是否要进行发货操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// deliveryOrder API list then
// 1. $router.back() 退
// 2. 使 $message Element UI
deliveryOrder(this.list).then(response => {
this.$router.back();
this.$message({
type: 'success',
message: '发货成功!'
});
});
}).catch(() => {
// catch 使 $message
this.$message({
type: 'info',
message: '已取消发货'
});
});
}
}
import {deliveryOrder} from '@/api/order'
const defaultLogisticsCompanies=["顺丰快递","圆通快递","中通快递","韵达快递"];
export default {
name: 'deliverOrderList',
data() {
return {
list:[],
companyOptions:defaultLogisticsCompanies
}
},
created(){
this.list= this.$route.query.list;
//list
if(this.list instanceof Array===false){
this.list=[];
}
},
methods:{
cancel(){
this.$router.back();
},
confirm(){
this.$confirm('是否要进行发货操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deliveryOrder(this.list).then(response=>{
this.$router.back();
this.$message({
type: 'success',
message: '发货成功!'
});
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消发货'
});
});
}
}
}
</script>
<style></style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,207 +1,127 @@
<template>
<!-- 使用 el-card 组件创建一个卡片式的布局容器设置类名为 "form-container"阴影效果为 "never"即无阴影用于包裹整个订单设置的表单内容 -->
<el-card class="form-container" shadow="never">
<!-- 使用 el-form 组件创建表单绑定表单数据模型为 "orderSetting"设置表单的引用名为 "orderSettingForm"方便后续通过 $refs 来获取表单实例进行验证等操作
同时通过 :rules 绑定验证规则对象 "rules"设置表单标签的宽度为 150px用于统一表单中各个表单项标签的显示宽度 -->
<el-form :model="orderSetting"
ref="orderSettingForm"
:rules="rules"
label-width="150px">
<!-- 以下是各个表单项el-form-item的定义每个表单项对应一个订单设置的时间相关配置 -->
<!-- 秒杀订单超时未付款自动关闭的时间设置表单项 -->
<el-form-item label="秒杀订单超过:" prop="flashOrderOvertime">
<!-- 使用 el-input 组件创建一个输入框通过 v-model 双向绑定 "orderSetting.flashOrderOvertime" 数据意味着用户在输入框中输入的值会实时更新到这个数据属性中
同时设置输入框的类名为 "input-width"用于控制输入框的宽度样式在后面的 <style> 部分定义了该类对应的宽度为 50% -->
<el-input v-model="orderSetting.flashOrderOvertime" class="input-width">
<!-- 使用 slot="append" 定义一个后置插槽在输入框后面添加一个文本内容 "分"用于提示用户输入的时间单位是分钟 -->
<template slot="append"></template>
</el-input>
<!-- 展示一个提示文本设置类名为 "note-margin"在后面 <style> 部分定义了该类的左边距样式用于提示用户该项设置对应的业务含义即秒杀订单超过设定时间未付款会自动关闭 -->
<span class="note-margin">未付款订单自动关闭</span>
</el-form-item>
<!-- 正常订单超时未付款自动关闭的时间设置表单项结构和上面秒杀订单的类似 -->
<el-form-item label="正常订单超过:" prop="normalOrderOvertime">
<el-input v-model="orderSetting.normalOrderOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">未付款订单自动关闭</span>
</el-form-item>
<!-- 发货后超时未收货自动完成订单的时间设置表单项 -->
<el-form-item label="发货超过:" prop="confirmOvertime">
<el-input v-model="orderSetting.confirmOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">未收货订单自动完成</span>
</el-form-item>
<!-- 订单完成后超时自动结束交易且不能申请售后的时间设置表单项 -->
<el-form-item label="订单完成超过:" prop="finishOvertime">
<el-input v-model="orderSetting.finishOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">自动结束交易不能申请售后</span>
</el-form-item>
<!-- 订单完成后超时自动给予五星好评的时间设置表单项 -->
<el-form-item label="订单完成超过:" prop="commentOvertime">
<el-input v-model="orderSetting.commentOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">自动五星好评</span>
</el-form-item>
<!-- 定义一个提交按钮的表单项 -->
<el-form-item>
<!-- 使用 el-button 组件创建一个按钮设置按钮的点击事件为调用 "confirm('orderSettingForm')" 方法在后面的 methods 中定义按钮类型为 "primary"通常是主要的突出显示的按钮样式按钮文字为 "提交" -->
<el-button
@click="confirm('orderSettingForm')"
type="primary">提交</el-button>
</el-form-item>
</el-form>
</el-card>
<template> 
<el-card class="form-container" shadow="never">
<el-form :model="orderSetting"
ref="orderSettingForm"
:rules="rules"
label-width="150px">
<el-form-item label="秒杀订单超过:" prop="flashOrderOvertime">
<el-input v-model="orderSetting.flashOrderOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">未付款订单自动关闭</span>
</el-form-item>
<el-form-item label="正常订单超过:" prop="normalOrderOvertime">
<el-input v-model="orderSetting.normalOrderOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">未付款订单自动关闭</span>
</el-form-item>
<el-form-item label="发货超过:" prop="confirmOvertime">
<el-input v-model="orderSetting.confirmOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">未收货订单自动完成</span>
</el-form-item>
<el-form-item label="订单完成超过:" prop="finishOvertime">
<el-input v-model="orderSetting.finishOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">自动结束交易不能申请售后</span>
</el-form-item>
<el-form-item label="订单完成超过:" prop="commentOvertime">
<el-input v-model="orderSetting.commentOvertime" class="input-width">
<template slot="append"></template>
</el-input>
<span class="note-margin">自动五星好评</span>
</el-form-item>
<el-form-item>
<el-button
@click="confirm('orderSettingForm')"
type="primary">提交</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
// '@/api/orderSetting' getOrderSetting updateOrderSetting
import {getOrderSetting, updateOrderSetting} from '@/api/orderSetting';
// defaultOrderSetting
// 0 id null
//
const defaultOrderSetting = {
id: null,
flashOrderOvertime: 0,
normalOrderOvertime: 0,
confirmOvertime: 0,
finishOvertime: 0,
commentOvertime: 0
};
// checkTime
// rulevaluecallback
const checkTime = (rule, value, callback) => {
// callback Error ''
//
if (!value) {
return callback(new Error('时间不能为空'));
}
console.log("checkTime", value);
// 使 parseInt intValue
let intValue = parseInt(value);
// 使 Number.isInteger
// callback Error ''
if (!Number.isInteger(intValue)) {
return callback(new Error('请输入数字值'));
import {getOrderSetting,updateOrderSetting} from '@/api/orderSetting';
const defaultOrderSetting = {
id: null,
flashOrderOvertime: 0,
normalOrderOvertime: 0,
confirmOvertime: 0,
finishOvertime: 0,
commentOvertime: 0
};
const checkTime = (rule, value, callback) => {
if (!value) {
return callback(new Error('时间不能为空'));
}
console.log("checkTime",value);
let intValue = parseInt(value);
if (!Number.isInteger(intValue)) {
return callback(new Error('请输入数字值'));
}
callback();
};
export default {
name: 'orderSetting',
data() {
return {
orderSetting: Object.assign({}, defaultOrderSetting),
rules: {
flashOrderOvertime:{validator: checkTime, trigger: 'blur' },
normalOrderOvertime:{validator: checkTime, trigger: 'blur' },
confirmOvertime: {validator: checkTime, trigger: 'blur' },
finishOvertime: {validator: checkTime, trigger: 'blur' },
commentOvertime:{validator: checkTime, trigger: 'blur' }
}
// callback
callback();
};
// Vue 'orderSetting' Vue
export default {
// Vue 'orderSetting'
name: 'orderSetting',
// data 使 DOM
data() {
return {
// 使 Object.assign defaultOrderSetting orderSetting
// orderSetting 使
orderSetting: Object.assign({}, defaultOrderSetting),
// rules
// validator 使 checkTime trigger 'blur'
rules: {
flashOrderOvertime: {validator: checkTime, trigger: 'blur'},
normalOrderOvertime: {validator: checkTime, trigger: 'blur'},
confirmOvertime: {validator: checkTime, trigger: 'blur'},
finishOvertime: {validator: checkTime, trigger: 'blur'},
commentOvertime: {validator: checkTime, trigger: 'blur'}
}
}
},
// created getDetail methods
// 便
created() {
this.getDetail();
},
//
methods: {
// confirm formName 'orderSettingForm' el-form ref
confirm(formName) {
// $refs[formName] 'orderSettingForm' validate
// validate validtrue false
this.$refs[formName].validate((valid) => {
if (valid) {
// 使 $confirm Vue Element UI confirm
// '?' '' '' '' 'warning'
this.$confirm('是否要提交修改?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// '' updateOrderSetting API
// 1 1 this.orderSetting
//
updateOrderSetting(1, this.orderSetting).then(response => {
// updateOrderSetting
// 使 $message Vue Element UI
// 'success'绿 '!' 1000 1
this.$message({
type: 'success',
message: '提交成功!',
duration: 1000
});
})
});
} else {
// 使 $message 'warning'
//
this.$message({
message: '提交参数不合法',
type: 'warning'
});
return false;
}
}
},
created(){
this.getDetail();
},
methods:{
confirm(formName){
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('是否要提交修改?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
updateOrderSetting(1,this.orderSetting).then(response=>{
this.$message({
type: 'success',
message: '提交成功!',
duration:1000
});
},
// getDetail getOrderSetting API
// 1 1 orderSetting
// orderSetting
getDetail() {
getOrderSetting(1).then(response => {
this.orderSetting = response.data;
})
}
}
})
});
} else {
this.$message({
message: '提交参数不合法',
type: 'warning'
});
return false;
}
});
},
getDetail(){
getOrderSetting(1).then(response=>{
this.orderSetting=response.data;
})
}
}
}
</script>
<style scoped>
/* 定义一个类名为 "input-width" 的样式规则,设置元素的宽度为 50%,用于控制前面模板中 el-input 组件输入框的宽度,使其在页面上展示的宽度占父容器的一半 */
.input-width {
width: 50%;
}
.input-width {
width: 50%;
}
/* 定义一个类名为 "note-margin" 的样式规则,设置元素的左边距为 15px用于控制前面模板中那些提示文本span 元素)的左边距,使其与输入框等元素有一定的间隔,布局更加美观清晰 */
.note-margin {
margin-left: 15px;
}
.note-margin {
margin-left: 15px;
}
</style>

@ -1,236 +1,344 @@
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="输入搜索:">
<el-input v-model="listQuery.keyword" class="input-width" placeholder="帐号/姓名" clearable></el-input>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button size="mini" class="btn-add" @click="handleAdd()" style="margin-left: 20px">添加</el-button>
</el-card>
<div class="table-container">
<el-table ref="adminTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="帐号" align="center">
<template slot-scope="scope">{{scope.row.username}}</template>
</el-table-column>
<el-table-column label="姓名" align="center">
<template slot-scope="scope">{{scope.row.nickName}}</template>
</el-table-column>
<el-table-column label="邮箱" align="center">
<template slot-scope="scope">{{scope.row.email}}</template>
</el-table-column>
<el-table-column label="添加时间" width="160" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<el-table-column label="最后登录" width="160" align="center">
<template slot-scope="scope">{{scope.row.loginTime | formatDateTime}}</template>
</el-table-column>
<el-table-column label="是否启用" width="140" align="center">
<template slot-scope="scope">
<el-switch
@change="handleStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.status">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button size="mini"
type="text"
@click="handleSelectRole(scope.$index, scope.row)">分配角色
</el-button>
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">
编辑
</el-button>
<el-button size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:total="total">
</el-pagination>
</div>
<el-dialog
:title="isEdit?'编辑用户':'添加用户'"
:visible.sync="dialogVisible"
width="40%">
<el-form :model="admin"
ref="adminForm"
label-width="150px" size="small">
<el-form-item label="帐号:">
<el-input v-model="admin.username" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="姓名:">
<el-input v-model="admin.nickName" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="邮箱:">
<el-input v-model="admin.email" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="密码:">
<el-input v-model="admin.password" type="password" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="admin.note"
type="textarea"
:rows="5"
style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="是否启用:">
<el-radio-group v-model="admin.status">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
<el-dialog
title="分配角色"
:visible.sync="allocDialogVisible"
width="30%">
<el-select v-model="allocRoleIds" multiple placeholder="请选择" size="small" style="width: 80%">
<el-option
v-for="item in allRoleList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<span slot="footer" class="dialog-footer">
<el-button @click="allocDialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleAllocDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
//
import {str2Date} from '@/utils/date';
//
import img_home_order from '@/assets/images/home_order.png';
import img_home_today_amount from '@/assets/images/home_today_amount.png';
import img_home_yesterday_amount from '@/assets/images/home_yesterday_amount.png';
import {fetchList,createAdmin,updateAdmin,updateStatus,deleteAdmin,getRoleByAdmin,allocRole} from '@/api/login';
import {fetchAllRoleList} from '@/api/role';
import {formatDate} from '@/utils/date';
//
const DATA_FROM_BACKEND = {
columns: ['date', 'orderCount','orderAmount'],
rows: [
{date: '2018-11-01', orderCount: 10, orderAmount: 1093},
{date: '2018-11-02', orderCount: 20, orderAmount: 2230},
{date: '2018-11-03', orderCount: 33, orderAmount: 3623},
{date: '2018-11-04', orderCount: 50, orderAmount: 6423},
{date: '2018-11-05', orderCount: 80, orderAmount: 8492},
{date: '2018-11-06', orderCount: 60, orderAmount: 6293},
{date: '2018-11-07', orderCount: 20, orderAmount: 2293},
{date: '2018-11-08', orderCount: 60, orderAmount: 6293},
{date: '2018-11-09', orderCount: 50, orderAmount: 5293},
{date: '2018-11-10', orderCount: 30, orderAmount: 3293},
{date: '2018-11-11', orderCount: 20, orderAmount: 2293},
{date: '2018-11-12', orderCount: 80, orderAmount: 8293},
{date: '2018-11-13', orderCount: 100, orderAmount: 10293},
{date: '2018-11-14', orderCount: 10, orderAmount: 1293},
{date: '2018-11-15', orderCount: 40, orderAmount: 4293}
]
const defaultListQuery = {
pageNum: 1,
pageSize: 10,
keyword: null
};
const defaultAdmin = {
id: null,
username: null,
password: null,
nickName: null,
email: null,
note: null,
status: 1
};
export default {
name: 'home',
name: 'adminList',
data() {
return {
//
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
let start = new Date(2018,10,1);
const end = new Date(start.getTime() + 1000 * 60 * 60 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一月',
onClick(picker) {
let start = new Date(2018,10,1);
const end = new Date(start.getTime() + 1000 * 60 * 60 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}]
},
//
orderCountDate: '',
//
chartSettings: {
xAxisType: 'time',
area:true,
axisSite: { right: ['orderAmount']},
labelMap: {'orderCount': '订单数量', 'orderAmount': '订单金额'}
},
//
chartData: {
columns: [],
rows: []
},
//
loading: false,
//
dataEmpty: false,
//
img_home_order,
img_home_today_amount,
img_home_yesterday_amount
listQuery: Object.assign({}, defaultListQuery),
list: null,
total: null,
listLoading: false,
dialogVisible: false,
admin: Object.assign({}, defaultAdmin),
isEdit: false,
allocDialogVisible: false,
allocRoleIds:[],
allRoleList:[],
allocAdminId:null
}
},
created(){
//
this.initOrderCountDate();
//
this.getData();
created() {
this.getList();
this.getAllRoleList();
},
methods:{
//
handleDateChange(){
this.getData();
filters: {
formatDateTime(time) {
if (time == null || time === '') {
return 'N/A';
}
let date = new Date(time);
return formatDate(date, 'yyyy-MM-dd hh:mm:ss')
}
},
methods: {
handleResetSearch() {
this.listQuery = Object.assign({}, defaultListQuery);
},
handleSearchList() {
this.listQuery.pageNum = 1;
this.getList();
},
//
initOrderCountDate(){
let start = new Date(2018,10,1);
const end = new Date(start.getTime() + 1000 * 60 * 60 * 24 * 7);
this.orderCountDate=[start,end];
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
//
getData(){
setTimeout(() => {
this.chartData = {
columns: ['date', 'orderCount','orderAmount'],
rows: []
};
//
for(let i=0;i<DATA_FROM_BACKEND.rows.length;i++){
let item=DATA_FROM_BACKEND.rows[i];
let currDate=str2Date(item.date);
let start=this.orderCountDate[0];
let end=this.orderCountDate[1];
//
if(currDate.getTime()>=start.getTime()&&currDate.getTime()<=end.getTime()){
this.chartData.rows.push(item);
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleAdd() {
this.dialogVisible = true;
this.isEdit = false;
this.admin = Object.assign({},defaultAdmin);
},
handleStatusChange(index, row) {
this.$confirm('是否要修改该状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
updateStatus(row.id, {status: row.status}).then(response => {
this.$message({
type: 'success',
message: '修改成功!'
});
});
}).catch(() => {
this.$message({
type: 'info',
message: '取消修改'
});
this.getList();
});
},
handleDelete(index, row) {
this.$confirm('是否要删除该用户?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteAdmin(row.id).then(response => {
this.$message({
type: 'success',
message: '删除成功!'
});
this.getList();
});
});
},
handleUpdate(index, row) {
this.dialogVisible = true;
this.isEdit = true;
this.admin = Object.assign({},row);
},
handleDialogConfirm() {
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
updateAdmin(this.admin.id,this.admin).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
});
this.dialogVisible =false;
this.getList();
})
} else {
createAdmin(this.admin).then(response => {
this.$message({
message: '添加成功!',
type: 'success'
});
this.dialogVisible =false;
this.getList();
})
}
})
},
handleAllocDialogConfirm(){
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let params = new URLSearchParams();
params.append("adminId", this.allocAdminId);
params.append("roleIds", this.allocRoleIds);
allocRole(params).then(response => {
this.$message({
message: '分配成功!',
type: 'success'
});
this.allocDialogVisible = false;
})
})
},
handleSelectRole(index,row){
this.allocAdminId = row.id;
this.allocDialogVisible = true;
this.getRoleListByAdmin(row.id);
},
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
getAllRoleList() {
fetchAllRoleList().then(response => {
this.allRoleList = response.data;
});
},
getRoleListByAdmin(adminId) {
getRoleByAdmin(adminId).then(response => {
let allocRoleList = response.data;
this.allocRoleIds=[];
if(allocRoleList!=null&&allocRoleList.length>0){
for(let i=0;i<allocRoleList.length;i++){
this.allocRoleIds.push(allocRoleList[i].id);
}
}
//
this.dataEmpty = false;
//
this.loading = false
}, 1000)
});
}
}
}
</script>
<style></style>
<style scoped>
/* 容器样式 */
.app-container {
margin-top: 40px;
margin-left: 120px;
margin-right: 120px;
}
/* 地址布局样式 */
.address-layout {
}
/* 总布局样式 */
.total-layout {
margin-top: 20px;
}
/* 总框架样式 */
.total-frame {
border: 1px solid #DCDFE6;
padding: 20px;
height: 100px;
}
/* 总图标样式 */
.total-icon {
color: #409EFF;
width: 60px;
height: 60px;
}
/* 总标题样式 */
.total-title {
position: relative;
font-size: 16px;
color: #909399;
left: 70px;
top: -50px;
}
/* 总值样式 */
.total-value {
position: relative;
font-size: 18px;
color: #606266;
left: 70px;
top: -40px;
}
/* 待处理布局样式 */
.un-handle-layout {
margin-top: 20px;
border: 1px solid #DCDFE6;
}
/* 布局标题样式 */
.layout-title {
color: #606266;
padding: 15px 20px;
background: #F2F6FC;
font-weight: bold;
}
/* 待处理内容样式 */
.un-handle-content {
padding: 20px 40px;
}
/* 待处理项样式 */
.un-handle-item {
border-bottom: 1px solid #EBEEF5;
padding: 10px;
}
/* 总览布局样式 */
.overview-layout {
margin-top: 20px;
}
/* 总览项值样式 */
.overview-item-value {
font-size: 24px;
text-align: center;
}
/* 总览项标题样式 */
.overview-item-title {
margin-top: 10px;
text-align: center;
}
/* 外边框样式 */
.out-border {
border: 1px solid #DCDFE6;
}
/* 统计布局样式 */
.statistics-layout {
margin-top: 20px;
border: 1px solid #DCDFE6;
}
/* 我的布局样式 */
.mine-layout {
position: absolute;
right: 140px;
top: 107px;
width: 250px;
height: 235px;
}
/* 地址内容样式 */
.address-content{
padding: 20px;
font-size: 18px
}
</style>

@ -1,16 +1,14 @@
<template>
<!-- 使用 MenuDetail 组件并传递 is-edit 属性为 false -->
<template> 
<menu-detail :is-edit='false'></menu-detail>
</template>
<script>
// MenuDetail
import MenuDetail from './components/MenuDetail'
export default {
name: 'addMenu', // addMenu
components: { MenuDetail } // MenuDetail
name: 'addMenu',
components: { MenuDetail }
}
</script>
<style>
</style>

@ -1,18 +1,15 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="form-container" shadow="never">
<!-- 使用 el-form 组件创建表单绑定数据模型和验证规则 -->
<el-form :model="menu" :rules="rules" ref="menuFrom" label-width="150px">
<!-- 表单项菜单名称 -->
<el-form :model="menu"
:rules="rules"
ref="menuFrom"
label-width="150px">
<el-form-item label="菜单名称:" prop="title">
<!-- 使用 el-input 组件创建输入框双向绑定 menu.title -->
<el-input v-model="menu.title"></el-input>
</el-form-item>
<!-- 表单项上级菜单 -->
<el-form-item label="上级菜单:">
<!-- 使用 el-select 组件创建下拉选择框双向绑定 menu.parentId -->
<el-select v-model="menu.parentId" placeholder="请选择菜单">
<!-- 使用 v-for 指令遍历 selectMenuList生成 el-option 选项 -->
<el-select v-model="menu.parentId"
placeholder="请选择菜单">
<el-option
v-for="item in selectMenuList"
:key="item.id"
@ -21,33 +18,24 @@
</el-option>
</el-select>
</el-form-item>
<!-- 表单项前端名称 -->
<el-form-item label="前端名称:" prop="name">
<el-input v-model="menu.name"></el-input>
</el-form-item>
<!-- 表单项前端图标 -->
<el-form-item label="前端图标:" prop="icon">
<el-input v-model="menu.icon" style="width: 80%"></el-input>
<!-- 使用 svg-icon 组件显示图标 -->
<svg-icon style="margin-left: 8px" :icon-class="menu.icon"></svg-icon>
</el-form-item>
<!-- 表单项是否显示 -->
<el-form-item label="是否显示:">
<!-- 使用 el-radio-group 组件创建单选按钮组双向绑定 menu.hidden -->
<el-radio-group v-model="menu.hidden">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<!-- 表单项排序 -->
<el-form-item label="排序:">
<el-input v-model="menu.sort"></el-input>
</el-form-item>
<!-- 表单项操作按钮 -->
<el-form-item>
<!-- 提交按钮 -->
<el-button type="primary" @click="onSubmit('menuFrom')"></el-button>
<!-- 重置按钮仅在非编辑状态下显示 -->
<el-button v-if="!isEdit" @click="resetForm('menuFrom')"></el-button>
</el-form-item>
</el-form>
@ -55,10 +43,8 @@
</template>
<script>
// API
import {fetchList, createMenu, updateMenu, getMenu} from '@/api/menu';
//
const defaultMenu = {
title: '',
parentId: 0,
@ -67,10 +53,8 @@
hidden: 0,
sort: 0
};
export default {
name: "MenuDetail",
// isEdit
props: {
isEdit: {
type: Boolean,
@ -79,11 +63,8 @@
},
data() {
return {
//
menu: Object.assign({}, defaultMenu),
//
selectMenuList: [],
//
rules: {
title: [
{required: true, message: '请输入菜单名称', trigger: 'blur'},
@ -101,28 +82,22 @@
}
},
created() {
//
if (this.isEdit) {
getMenu(this.$route.query.id).then(response => {
this.menu = response.data;
});
} else {
//
this.menu = Object.assign({}, defaultMenu);
}
//
this.getSelectMenuList();
},
methods: {
//
getSelectMenuList() {
fetchList(0, {pageSize: 100, pageNum: 1}).then(response => {
this.selectMenuList = response.data.list;
//
this.selectMenuList.unshift({id: 0, title: '无上级菜单'});
});
},
//
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
@ -132,7 +107,6 @@
type: 'warning'
}).then(() => {
if (this.isEdit) {
// API
updateMenu(this.$route.query.id, this.menu).then(response => {
this.$message({
message: '修改成功',
@ -142,7 +116,6 @@
this.$router.back();
});
} else {
// API
createMenu(this.menu).then(response => {
this.$refs[formName].resetFields();
this.resetForm(formName);
@ -155,6 +128,7 @@
});
}
});
} else {
this.$message({
message: '验证失败',
@ -165,7 +139,6 @@
}
});
},
//
resetForm(formName) {
this.$refs[formName].resetFields();
this.menu = Object.assign({}, defaultMenu);
@ -176,4 +149,5 @@
</script>
<style scoped>
</style>

@ -1,142 +1,117 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<!-- 使用 el-span 组件显示文本 -->
<span style="margin-top: 5px">数据列表</span>
<!-- 使用 el-button 组件创建添加按钮点击时调用 handleAddMenu 方法 -->
<el-button
class="btn-add"
@click="handleAddMenu()"
size="mini">
添加
</el-button>
</el-card>
<!-- 使用 el-table 组件创建表格绑定数据模型和加载状态 -->
<div class="table-container">
<el-table ref="menuTable"
style="width: 100%"
:data="list"
v-loading="listLoading" border>
<!-- 表格列编号 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列菜单名称 -->
<el-table-column label="菜单名称" align="center">
<template slot-scope="scope">{{scope.row.title}}</template>
</el-table-column>
<!-- 表格列菜单级数 -->
<el-table-column label="菜单级数" width="100" align="center">
<template slot-scope="scope">{{scope.row.level | levelFilter}}</template>
</el-table-column>
<!-- 表格列前端名称 -->
<el-table-column label="前端名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列前端图标 -->
<el-table-column label="前端图标" width="100" align="center">
<template slot-scope="scope"><svg-icon :icon-class="scope.row.icon"></svg-icon></template>
</el-table-column>
<!-- 表格列是否显示 -->
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<!-- 使用 el-switch 组件创建开关双向绑定 scope.row.hidden -->
<el-switch
@change="handleHiddenChange(scope.$index, scope.row)"
:active-value="0"
:inactive-value="1"
v-model="scope.row.hidden">
</el-switch>
</template>
</el-table-column>
<!-- 表格列排序 -->
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort }}</template>
</el-table-column>
<!-- 表格列设置 -->
<el-table-column label="设置" width="120" align="center">
<template slot-scope="scope">
<!-- 使用 el-button 组件创建按钮点击时调用 handleShowNextLevel 方法 -->
<el-button
size="mini"
type="text"
:disabled="scope.row.level | disableNextLevel"
@click="handleShowNextLevel(scope.$index, scope.row)">查看下级
</el-button>
</template>
</el-table-column>
<!-- 表格列操作 -->
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<!-- 使用 el-button 组件创建按钮点击时调用 handleUpdate handleDelete 方法 -->
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 使用 el-pagination 组件创建分页器绑定数据模型和事件 -->
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button
class="btn-add"
@click="handleAddMenu()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="menuTable"
style="width: 100%"
:data="list"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="菜单名称" align="center">
<template slot-scope="scope">{{scope.row.title}}</template>
</el-table-column>
<el-table-column label="菜单级数" width="100" align="center">
<template slot-scope="scope">{{scope.row.level | levelFilter}}</template>
</el-table-column>
<el-table-column label="前端名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="前端图标" width="100" align="center">
<template slot-scope="scope"><svg-icon :icon-class="scope.row.icon"></svg-icon></template>
</el-table-column>
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleHiddenChange(scope.$index, scope.row)"
:active-value="0"
:inactive-value="1"
v-model="scope.row.hidden">
</el-switch>
</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort }}</template>
</el-table-column>
<el-table-column label="设置" width="120" align="center">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
:disabled="scope.row.level | disableNextLevel"
@click="handleShowNextLevel(scope.$index, scope.row)">查看下级
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
// API
import {fetchList,deleteMenu,updateMenu,updateHidden} from '@/api/menu'
export default {
name: "menuList",
data() {
return {
//
list: null,
//
total: null,
//
listLoading: true,
//
listQuery: {
pageNum: 1,
pageSize: 5
},
// ID
parentId: 0
}
},
created() {
// ID
this.resetParentId();
this.getList();
},
watch: {
//
$route(route) {
this.resetParentId();
this.getList();
}
},
methods: {
// ID
resetParentId(){
this.listQuery.pageNum = 1;
if (this.$route.query.parentId != null) {
@ -145,12 +120,9 @@
this.parentId = 0;
}
},
//
handleAddMenu() {
//
this.$router.push('/ums/addMenu');
},
//
getList() {
this.listLoading = true;
fetchList(this.parentId, this.listQuery).then(response => {
@ -159,20 +131,16 @@
this.total = response.data.total;
});
},
//
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
//
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
//
handleHiddenChange(index, row) {
//
updateHidden(row.id,{hidden:row.hidden}).then(response=>{
this.$message({
message: '修改成功',
@ -181,19 +149,13 @@
});
});
},
//
handleShowNextLevel(index, row) {
//
this.$router.push({path: '/ums/menu', query: {parentId: row.id}})
},
//
handleUpdate(index, row) {
//
this.$router.push({path:'/ums/updateMenu',query:{id:row.id}});
},
//
handleDelete(index, row) {
//
this.$confirm('是否要删除该菜单', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -211,7 +173,6 @@
}
},
filters: {
//
levelFilter(value) {
if (value === 0) {
return '一级';
@ -219,7 +180,6 @@
return '二级';
}
},
//
disableNextLevel(value) {
if (value === 0) {
return false;
@ -230,5 +190,7 @@
}
}
</script>
<style scoped>
</style>

@ -1,16 +1,14 @@
<template>
<!-- 使用 MenuDetail 组件并传递 is-edit 属性为 true -->
<template> 
<menu-detail :is-edit='true'></menu-detail>
</template>
<script>
// MenuDetail
import MenuDetail from './components/MenuDetail'
export default {
name: 'updateMenu', // updateMenu
components: { MenuDetail } // MenuDetail
name: 'updateMenu',
components: { MenuDetail }
}
</script>
<style>
</style>
</style>

@ -1,115 +1,84 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card shadow="never" class="operate-container">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-tickets"></i>
<!-- 使用 el-span 组件显示文本 -->
<span>数据列表</span>
<!-- 使用 el-button 组件创建添加按钮点击时调用 handleAdd 方法 -->
<el-button size="mini" class="btn-add" @click="handleAdd()"></el-button>
</el-card>
<!-- 使用 el-table 组件创建表格绑定数据模型和加载状态 -->
<div class="table-container">
<el-table ref="resourceCategoryTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<!-- 表格列编号 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列名称 -->
<el-table-column label="名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列创建时间 -->
<el-table-column label="创建时间" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<!-- 表格列排序 -->
<el-table-column label="排序" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<!-- 表格列操作 -->
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<!-- 使用 el-button 组件创建按钮点击时调用 handleUpdate handleDelete 方法 -->
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<template> 
<div class="app-container">
<el-card shadow="never" class="operate-container">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button size="mini" class="btn-add" @click="handleAdd()"></el-button>
</el-card>
<div class="table-container">
<el-table ref="resourceCategoryTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="创建时间" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<el-table-column label="排序" align="center">
<template slot-scope="scope">{{scope.row.sort}}</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog
title="添加分类"
:visible.sync="dialogVisible"
width="40%">
<el-form :model="resourceCategory"
ref="resourceCategoryForm"
label-width="150px" size="small">
<el-form-item label="名称:">
<el-input v-model="resourceCategory.name" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="排序:">
<el-input v-model="resourceCategory.sort" style="width: 250px"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</div>
<!-- 使用 el-dialog 组件创建对话框绑定数据模型和事件 -->
<el-dialog
title="添加分类"
:visible.sync="dialogVisible"
width="40%">
<!-- 使用 el-form 组件创建表单绑定数据模型和验证规则 -->
<el-form :model="resourceCategory"
ref="resourceCategoryForm"
label-width="150px" size="small">
<!-- 表单项名称 -->
<el-form-item label="名称:">
<!-- 使用 el-input 组件创建输入框双向绑定 resourceCategory.name -->
<el-input v-model="resourceCategory.name" style="width: 250px"></el-input>
</el-form-item>
<!-- 表单项排序 -->
<el-form-item label="排序:">
<!-- 使用 el-input 组件创建输入框双向绑定 resourceCategory.sort -->
<el-input v-model="resourceCategory.sort" style="width: 250px"></el-input>
</el-form-item>
</el-form>
<!-- 对话框底部按钮 -->
<span slot="footer" class="dialog-footer">
<!-- 使用 el-button 组件创建取消按钮点击时关闭对话框 -->
<el-button @click="dialogVisible = false" size="small"> </el-button>
<!-- 使用 el-button 组件创建确定按钮点击时调用 handleDialogConfirm 方法 -->
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</template>
<script>
// API
import {listAllCate, createResourceCategory, updateResourceCategory, deleteResourceCategory} from '@/api/resourceCategory';
//
import {listAllCate,createResourceCategory,updateResourceCategory,deleteResourceCategory} from '@/api/resourceCategory';
import {formatDate} from '@/utils/date';
//
const defaultResourceCategory = {
name: null,
sort: 0
const defaultResourceCategory={
name:null,
sort:0
};
export default {
name: 'resourceCategoryList',
data() {
return {
//
list: null,
//
listLoading: false,
//
dialogVisible: false,
//
isEdit: false,
//
resourceCategory: Object.assign({}, defaultResourceCategory)
dialogVisible:false,
isEdit:false,
resourceCategory:Object.assign({},defaultResourceCategory)
}
},
created() {
//
this.getList();
},
filters: {
//
filters:{
formatDateTime(time) {
if (time == null || time === '') {
return 'N/A';
@ -119,23 +88,17 @@
}
},
methods: {
//
handleAdd() {
// false
this.dialogVisible = true;
this.isEdit = false;
this.resourceCategory = Object.assign({}, defaultResourceCategory);
this.resourceCategory = Object.assign({},defaultResourceCategory);
},
//
handleUpdate(index, row) {
// true
handleUpdate(index,row){
this.dialogVisible = true;
this.isEdit = true;
this.resourceCategory = Object.assign({}, row);
this.resourceCategory = Object.assign({},row);
},
//
handleDelete(index, row) {
//
handleDelete(index,row){
this.$confirm('是否要删除该分类?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -146,45 +109,37 @@
type: 'success',
message: '删除成功!'
});
//
this.getList();
});
});
},
//
handleDialogConfirm() {
//
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
// API
updateResourceCategory(this.resourceCategory.id, this.resourceCategory).then(response => {
updateResourceCategory(this.resourceCategory.id,this.resourceCategory).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
});
//
this.dialogVisible = false;
this.dialogVisible =false;
this.getList();
})
} else {
// API
createResourceCategory(this.resourceCategory).then(response => {
this.$message({
message: '添加成功!',
type: 'success'
});
//
this.dialogVisible = false;
this.dialogVisible =false;
this.getList();
})
}
})
},
//
getList() {
this.listLoading = true;
listAllCate({}).then(response => {
@ -195,6 +150,7 @@
}
}
</script>
<style>
</style>

@ -1,153 +1,137 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="filter-container" shadow="never">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-search"></i>
<!-- 使用 el-span 组件显示文本 -->
<span>筛选搜索</span>
<!-- 使用 el-button 组件创建查询按钮点击时调用 handleSearchList 方法 -->
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<!-- 使用 el-button 组件创建重置按钮点击时调用 handleResetSearch 方法 -->
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</el-card>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-tickets"></i>
<!-- 使用 el-span 组件显示文本 -->
<span>数据列表</span>
<!-- 使用 el-button 组件创建添加按钮点击时调用 handleAdd 方法 -->
<el-button size="mini" class="btn-add" @click="handleAdd()" style="margin-left: 20px">添加</el-button>
<!-- 使用 el-button 组件创建资源分类按钮点击时调用 handleShowCategory 方法 -->
<el-button size="mini" class="btn-add" @click="handleShowCategory()"></el-button>
</el-card>
<!-- 使用 el-table 组件创建表格绑定数据模型和加载状态 -->
<div class="table-container">
<el-table ref="resourceTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<!-- 表格列编号 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列资源名称 -->
<el-table-column label="资源名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列资源路径 -->
<el-table-column label="资源路径" align="center">
<template slot-scope="scope">{{scope.row.url}}</template>
</el-table-column>
<!-- 表格列描述 -->
<el-table-column label="描述" align="center">
<template slot-scope="scope">{{scope.row.description}}</template>
</el-table-column>
<!-- 表格列添加时间 -->
<el-table-column label="添加时间" width="160" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<!-- 表格列操作 -->
<el-table-column label="操作" width="140" align="center">
<template slot-scope="scope">
<!-- 使用 el-button 组件创建编辑按钮点击时调用 handleUpdate 方法 -->
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">
编辑
</el-button>
<!-- 使用 el-button 组件创建删除按钮点击时调用 handleDelete 方法 -->
<el-button size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="资源名称:">
<el-input v-model="listQuery.nameKeyword" class="input-width" placeholder="资源名称" clearable></el-input>
</el-form-item>
<el-form-item label="资源路径:">
<el-input v-model="listQuery.urlKeyword" class="input-width" placeholder="资源路径" clearable></el-input>
</el-form-item>
<el-form-item label="资源分类:">
<el-select v-model="listQuery.categoryId" placeholder="全部" clearable class="input-width">
<el-option v-for="item in categoryOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button size="mini" class="btn-add" @click="handleAdd()" style="margin-left: 20px">添加</el-button>
<el-button size="mini" class="btn-add" @click="handleShowCategory()"></el-button>
</el-card>
<div class="table-container">
<el-table ref="resourceTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="资源名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="资源路径" align="center">
<template slot-scope="scope">{{scope.row.url}}</template>
</el-table-column>
<el-table-column label="描述" align="center">
<template slot-scope="scope">{{scope.row.description}}</template>
</el-table-column>
<el-table-column label="添加时间" width="160" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<el-table-column label="操作" width="140" align="center">
<template slot-scope="scope">
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">
编辑
</el-button>
<el-button size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:total="total">
</el-pagination>
</div>
<el-dialog
:title="isEdit?'编辑资源':'添加资源'"
:visible.sync="dialogVisible"
width="40%">
<el-form :model="resource"
ref="resourceForm"
label-width="150px" size="small">
<el-form-item label="资源名称:">
<el-input v-model="resource.name" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="资源路径:">
<el-input v-model="resource.url" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="资源分类:">
<el-select v-model="resource.categoryId" placeholder="全部" clearable style="width: 250px">
<el-option v-for="item in categoryOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述:">
<el-input v-model="resource.description"
type="textarea"
:rows="5"
style="width: 250px"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</div>
<!-- 使用 el-pagination 组件创建分页器绑定数据模型和事件 -->
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:total="total">
</el-pagination>
</div>
<!-- 使用 el-dialog 组件创建对话框绑定数据模型和事件 -->
<el-dialog
:title="isEdit?'编辑资源':'添加资源'"
:visible.sync="dialogVisible"
width="40%">
<!-- 使用 el-form 组件创建表单绑定数据模型和验证规则 -->
<el-form :model="resource"
ref="resourceForm"
label-width="150px" size="small">
<!-- 表单项资源名称 -->
<el-form-item label="资源名称:">
<!-- 使用 el-input 组件创建输入框双向绑定 resource.name -->
<el-input v-model="resource.name" style="width: 250px"></el-input>
</el-form-item>
<!-- 表单项资源路径 -->
<el-form-item label="资源路径:">
<!-- 使用 el-input 组件创建输入框双向绑定 resource.url -->
<el-input v-model="resource.url" style="width: 250px"></el-input>
</el-form-item>
<!-- 表单项资源分类 -->
<el-form-item label="资源分类:">
<!-- 使用 el-select 组件创建下拉选择框双向绑定 resource.categoryId -->
<el-select v-model="resource.categoryId" placeholder="全部" clearable style="width: 250px">
<!-- 使用 v-for 指令遍历 categoryOptions生成 el-option 选项 -->
<el-option v-for="item in categoryOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<!-- 表单项描述 -->
<el-form-item label="描述:">
<!-- 使用 el-input 组件创建文本域双向绑定 resource.description -->
<el-input v-model="resource.description"
type="textarea"
:rows="5"
style="width: 250px"></el-input>
</el-form-item>
</el-form>
<!-- 对话框底部按钮 -->
<span slot="footer" class="dialog-footer">
<!-- 使用 el-button 组件创建取消按钮点击时关闭对话框 -->
<el-button @click="dialogVisible = false" size="small"> </el-button>
<!-- 使用 el-button 组件创建确定按钮点击时调用 handleDialogConfirm 方法 -->
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</template>
<script>
// API
import {fetchList,createResource,updateResource,deleteResource} from '@/api/resource';
// API
import {listAllCate} from '@/api/resourceCategory';
//
import {formatDate} from '@/utils/date';
//
const defaultListQuery = {
pageNum: 1,
pageSize: 10,
@ -155,7 +139,6 @@
urlKeyword: null,
categoryId:null
};
//
const defaultResource = {
id: null,
name: null,
@ -163,38 +146,26 @@
categoryId: null,
description:''
};
export default {
name: 'resourceList',
data() {
return {
//
listQuery: Object.assign({}, defaultListQuery),
//
list: null,
//
total: null,
//
listLoading: false,
//
dialogVisible: false,
//
isEdit: false,
//
resource: Object.assign({}, defaultResource),
//
isEdit: false,
categoryOptions:[],
// ID
defaultCategoryId:null
}
},
created() {
//
this.getList();
this.getCateList();
},
filters: {
//
formatDateTime(time) {
if (time == null || time === '') {
return 'N/A';
@ -204,41 +175,29 @@
}
},
methods: {
//
handleResetSearch() {
//
this.listQuery = Object.assign({}, defaultListQuery);
},
//
handleSearchList() {
//
this.listQuery.pageNum = 1;
this.getList();
},
//
handleSizeChange(val) {
//
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
//
handleCurrentChange(val) {
//
this.listQuery.pageNum = val;
this.getList();
},
//
handleAdd() {
// false
this.dialogVisible = true;
this.isEdit = false;
this.resource = Object.assign({},defaultResource);
this.resource.categoryId = this.defaultCategoryId;
},
//
handleDelete(index, row) {
//
this.$confirm('是否要删除该资源?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -249,57 +208,45 @@
type: 'success',
message: '删除成功!'
});
//
this.getList();
});
});
},
//
handleUpdate(index, row) {
// true
this.dialogVisible = true;
this.isEdit = true;
this.resource = Object.assign({},row);
},
//
handleDialogConfirm() {
//
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
// API
updateResource(this.resource.id,this.resource).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
});
//
this.dialogVisible =false;
this.getList();
})
} else {
// API
createResource(this.resource).then(response => {
this.$message({
message: '添加成功!',
type: 'success'
});
//
this.dialogVisible =false;
this.getList();
})
}
})
},
//
handleShowCategory(){
//
this.$router.push({path: '/ums/resourceCategory'})
},
//
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
@ -308,21 +255,19 @@
this.total = response.data.total;
});
},
//
getCateList(){
listAllCate().then(response=>{
let cateList = response.data;
for(let i=0;i<cateList.length;i++){
let cate = cateList[i];
//
this.categoryOptions.push({label:cate.name,value:cate.id});
}
// ID
this.defaultCategoryId=cateList[0].id;
})
}
}
}
</script>
<style></style>

@ -1,7 +1,5 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="form-container" shadow="never">
<!-- 使用 el-tree 组件创建树形控件绑定数据模型和属性 -->
<el-tree
:data="menuTreeList"
show-checkbox
@ -11,17 +9,15 @@
highlight-current
:props="defaultProps">
</el-tree>
<!-- 使用 el-button 组件创建保存按钮点击时调用 handleSave 方法 -->
<div style="margin-top: 20px" align="center">
<el-button type="primary" @click="handleSave()"></el-button>
<!-- 使用 el-button 组件创建清空按钮点击时调用 handleClear 方法 -->
<el-button @click="handleClear()"></el-button>
</div>
</el-card>
</template>
<script>
// API
import {fetchTreeList} from '@/api/menu';
import {listMenuByRole,allocMenu} from '@/api/role';
@ -29,31 +25,25 @@
name: "allocMenu",
data() {
return {
//
menuTreeList: [],
//
defaultProps: {
children: 'children',
label: 'title'
},
// ID
roleId: null
roleId:null
};
},
created() {
// ID
this.roleId = this.$route.query.roleId;
this.treeList();
this.getRoleMenu(this.roleId);
},
methods: {
//
treeList() {
fetchTreeList().then(response => {
this.menuTreeList = response.data;
});
},
//
getRoleMenu(roleId){
listMenuByRole(roleId).then(response=>{
let menuList = response.data;
@ -66,13 +56,10 @@
}
}
}
//
this.$refs.tree.setCheckedKeys(checkedMenuIds);
});
},
//
handleSave() {
//
let checkedNodes = this.$refs.tree.getCheckedNodes();
let checkedMenuIds=new Set();
if(checkedNodes!=null&&checkedNodes.length>0){
@ -84,7 +71,6 @@
}
}
}
//
this.$confirm('是否分配菜单?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -99,14 +85,11 @@
type: 'success',
duration: 1000
});
//
this.$router.back();
})
})
},
//
handleClear() {
//
this.$refs.tree.setCheckedKeys([]);
}
}
@ -114,4 +97,5 @@
</script>
<style scoped>
</style>

@ -1,20 +1,14 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="form-container" shadow="never">
<!-- 使用 v-for 指令遍历 allResourceCate生成多个 div -->
<div v-for="(cate,index) in allResourceCate" :class="index===0?'top-line':null" :key="'cate'+cate.id">
<!-- 使用 el-row 组件创建行设置背景颜色 -->
<el-row class="table-layout" style="background: #F2F6FC;">
<!-- 使用 el-checkbox 组件创建复选框双向绑定 cate.checked点击时调用 handleCheckAllChange 方法 -->
<el-checkbox v-model="cate.checked"
:indeterminate="isIndeterminate(cate.id)"
@change="handleCheckAllChange(cate)">
{{cate.name}}
</el-checkbox>
</el-row>
<!-- 使用 el-row 组件创建行 -->
<el-row class="table-layout">
<!-- 使用 el-col 组件创建列遍历 getResourceByCate(cate.id)生成多个 el-checkbox -->
<el-col :span="8" v-for="resource in getResourceByCate(cate.id)" :key="resource.id" style="padding: 4px 0">
<el-checkbox v-model="resource.checked" @change="handleCheckChange(resource)">
{{resource.name}}
@ -22,17 +16,15 @@
</el-col>
</el-row>
</div>
<!-- 使用 el-button 组件创建保存按钮点击时调用 handleSave 方法 -->
<div style="margin-top: 20px" align="center">
<el-button type="primary" @click="handleSave()"></el-button>
<!-- 使用 el-button 组件创建清空按钮点击时调用 handleClear 方法 -->
<el-button @click="handleClear()"></el-button>
</div>
</el-card>
</template>
<script>
// API
import {fetchAllResourceList} from '@/api/resource';
import {listAllCate} from '@/api/resourceCategory';
import {allocResource,listResourceByRole} from '@/api/role';
@ -41,21 +33,16 @@
name: "allocResource",
data() {
return {
// ID
roleId: null,
//
allResource: null,
//
allResourceCate: null
};
},
created() {
// ID
this.roleId = this.$route.query.roleId;
this.getAllResourceCateList();
},
methods: {
//
getAllResourceList() {
fetchAllResourceList().then(response => {
this.allResource = response.data;
@ -65,7 +52,6 @@
this.getResourceByRole(this.roleId);
});
},
//
getAllResourceCateList() {
listAllCate().then(response => {
this.allResourceCate = response.data;
@ -75,7 +61,6 @@
this.getAllResourceList();
});
},
// ID
getResourceByCate(categoryId) {
let cateResource = [];
if (this.allResource == null) return null;
@ -87,7 +72,6 @@
}
return cateResource;
},
// ID
getResourceByRole(roleId){
listResourceByRole(roleId).then(response=>{
let allocResource = response.data;
@ -100,7 +84,6 @@
this.$forceUpdate();
});
},
//
getResourceChecked(resourceId,allocResource){
if(allocResource==null||allocResource.length===0) return false;
for(let i=0;i<allocResource.length;i++){
@ -110,7 +93,6 @@
}
return false;
},
//
isIndeterminate(categoryId) {
let cateResources = this.getResourceByCate(categoryId);
if (cateResources == null) return false;
@ -122,7 +104,6 @@
}
return !(checkedCount === 0 || checkedCount === cateResources.length);
},
//
isAllChecked(categoryId) {
let cateResources = this.getResourceByCate(categoryId);
if (cateResources == null) return false;
@ -137,25 +118,24 @@
}
return checkedCount === cateResources.length;
},
//
handleSave() {
this.$confirm('是否分配资源?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(()=>{
}).then(() => {
let checkedResourceIds = new Set();
if(this.allResource!=null&&this.allResource.length>0){
this.allResource.forEach(item=>{
if(item.checked){
if (this.allResource != null && this.allResource.length > 0) {
this.allResource.forEach(item => {
if (item.checked) {
checkedResourceIds.add(item.id);
}
});
}
let params = new URLSearchParams();
params.append("roleId",this.roleId);
params.append("resourceIds",Array.from(checkedResourceIds));
allocResource(params).then(response=>{
params.append("roleId", this.roleId);
params.append("resourceIds", Array.from(checkedResourceIds));
allocResource(params).then(response => {
this.$message({
message: '分配成功',
type: 'success',
@ -165,25 +145,22 @@
})
})
},
//
handleClear() {
this.allResourceCate.forEach(item=>{
this.allResourceCate.forEach(item => {
item.checked = false;
});
this.allResource.forEach(item=>{
this.allResource.forEach(item => {
item.checked = false;
});
this.$forceUpdate();
},
//
handleCheckAllChange(cate) {
let cateResources = this.getResourceByCate(cate.id);
for(let i=0;i<cateResources.length;i++){
for (let i = 0; i < cateResources.length; i++) {
cateResources[i].checked = cate.checked;
}
this.$forceUpdate();
},
//
handleCheckChange(resource) {
this.allResourceCate.forEach(item=>{
if(item.id===resource.categoryId){
@ -203,6 +180,7 @@
border-right: 1px solid #DCDFE6;
border-bottom: 1px solid #DCDFE6;
}
.top-line {
border-top: 1px solid #DCDFE6;
}

@ -1,88 +1,79 @@
<template>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="filter-container" shadow="never">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-search"></i>
<!-- 使用 el-span 组件显示文本 -->
<span>筛选搜索</span>
<!-- 使用 el-button 组件创建查询按钮点击时调用 handleSearchList 方法 -->
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<!-- 使用 el-button 组件创建重置按钮点击时调用 handleResetSearch 方法 -->
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</el-card>
<!-- 使用 el-card 组件创建一个卡片容器设置阴影效果 -->
<el-card class="operate-container" shadow="never">
<!-- 使用 el-icon 组件显示图标 -->
<i class="el-icon-tickets"></i>
<!-- 使用 el-span 组件显示文本 -->
<span>数据列表</span>
<!-- 使用 el-button 组件创建添加按钮点击时调用 handleAdd 方法 -->
<el-button size="mini" class="btn-add" @click="handleAdd()" style="margin-left: 20px">添加</el-button>
</el-card>
<!-- 使用 el-table 组件创建表格绑定数据模型和加载状态 -->
<div class="table-container">
<el-table ref="roleTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<!-- 表格列编号 -->
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<!-- 表格列角色名称 -->
<el-table-column label="角色名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<!-- 表格列描述 -->
<el-table-column label="描述" align="center">
<template slot-scope="scope">{{scope.row.description}}</template>
</el-table-column>
<!-- 表格列用户数 -->
<el-table-column label="用户数" width="100" align="center">
<template slot-scope="scope">{{scope.row.adminCount}}</template>
</el-table-column>
<!-- 表格列添加时间 -->
<el-table-column label="添加时间" width="160" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<!-- 表格列是否启用 -->
<el-table-column label="是否启用" width="140" align="center">
<template slot-scope="scope">
<!-- 使用 el-switch 组件创建开关双向绑定 scope.row.status -->
<el-switch
@change="handleStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.status">
</el-switch>
</template>
</el-table-column>
<!-- 表格列操作 -->
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<!-- 使用 el-button 组件创建按钮点击时调用 handleSelectMenu handleSelectResource handleUpdate handleDelete 方法 -->
<el-row>
<el-button size="mini"
type="text"
@click="handleSelectMenu(scope.$index, scope.row)">分配菜单
</el-button>
<el-button size="mini"
type="text"
@click="handleSelectResource(scope.$index, scope.row)">分配资源
</el-button>
</el-row>
<el-row>
<template> 
<div class="app-container">
<el-card class="filter-container" shadow="never">
<div>
<i class="el-icon-search"></i>
<span>筛选搜索</span>
<el-button
style="float:right"
type="primary"
@click="handleSearchList()"
size="small">
查询搜索
</el-button>
<el-button
style="float:right;margin-right: 15px"
@click="handleResetSearch()"
size="small">
重置
</el-button>
</div>
<div style="margin-top: 15px">
<el-form :inline="true" :model="listQuery" size="small" label-width="140px">
<el-form-item label="输入搜索:">
<el-input v-model="listQuery.keyword" class="input-width" placeholder="角色名称" clearable></el-input>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets"></i>
<span>数据列表</span>
<el-button size="mini" class="btn-add" @click="handleAdd()" style="margin-left: 20px">添加</el-button>
</el-card>
<div class="table-container">
<el-table ref="roleTable"
:data="list"
style="width: 100%;"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="角色名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="描述" align="center">
<template slot-scope="scope">{{scope.row.description}}</template>
</el-table-column>
<el-table-column label="用户数" width="100" align="center">
<template slot-scope="scope">{{scope.row.adminCount}}</template>
</el-table-column>
<el-table-column label="添加时间" width="160" align="center">
<template slot-scope="scope">{{scope.row.createTime | formatDateTime}}</template>
</el-table-column>
<el-table-column label="是否启用" width="140" align="center">
<template slot-scope="scope">
<el-switch
@change="handleStatusChange(scope.$index, scope.row)"
:active-value="1"
:inactive-value="0"
v-model="scope.row.status">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<el-row>
<el-button size="mini"
type="text"
@click="handleSelectMenu(scope.$index, scope.row)">分配菜单
</el-button>
<el-button size="mini"
type="text"
@click="handleSelectResource(scope.$index, scope.row)">分配资源
</el-button>
</el-row>
<el-row>
<el-button size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">
@ -92,78 +83,62 @@
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</el-row>
</template>
</el-table-column>
</el-table>
</el-row>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:total="total">
</el-pagination>
</div>
<el-dialog
:title="isEdit?'编辑角色':'添加角色'"
:visible.sync="dialogVisible"
width="40%">
<el-form :model="role"
ref="roleForm"
label-width="150px" size="small">
<el-form-item label="角色名称:">
<el-input v-model="role.name" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="描述:">
<el-input v-model="role.description"
type="textarea"
:rows="5"
style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="是否启用:">
<el-radio-group v-model="role.status">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</div>
<!-- 使用 el-pagination 组件创建分页器绑定数据模型和事件 -->
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:current-page.sync="listQuery.pageNum"
:page-size="listQuery.pageSize"
:page-sizes="[5,10,15]"
:total="total">
</el-pagination>
</div>
<!-- 使用 el-dialog 组件创建对话框绑定数据模型和事件 -->
<el-dialog
:title="isEdit?'编辑角色':'添加角色'"
:visible.sync="dialogVisible"
width="40%">
<!-- 使用 el-form 组件创建表单绑定数据模型和验证规则 -->
<el-form :model="role"
ref="roleForm"
label-width="150px" size="small">
<!-- 表单项角色名称 -->
<el-form-item label="角色名称:">
<!-- 使用 el-input 组件创建输入框双向绑定 role.name -->
<el-input v-model="role.name" style="width: 250px"></el-input>
</el-form-item>
<!-- 表单项描述 -->
<el-form-item label="描述:">
<!-- 使用 el-input 组件创建文本域双向绑定 role.description -->
<el-input v-model="role.description"
type="textarea"
:rows="5"
style="width: 250px"></el-input>
</el-form-item>
<!-- 表单项是否启用 -->
<el-form-item label="是否启用:">
<!-- 使用 el-radio-group 组件创建单选组双向绑定 role.status -->
<el-radio-group v-model="role.status">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 对话框底部按钮 -->
<span slot="footer" class="dialog-footer">
<!-- 使用 el-button 组件创建取消按钮点击时关闭对话框 -->
<el-button @click="dialogVisible = false" size="small"> </el-button>
<!-- 使用 el-button 组件创建确定按钮点击时调用 handleDialogConfirm 方法 -->
<el-button type="primary" @click="handleDialogConfirm()" size="small"> </el-button>
</span>
</el-dialog>
</template>
<script>
// API
import {fetchList,createRole,updateRole,updateStatus,deleteRole} from '@/api/role';
//
import {formatDate} from '@/utils/date';
//
const defaultListQuery = {
pageNum: 1,
pageSize: 5,
keyword: null
};
//
const defaultRole = {
id: null,
name: null,
@ -171,33 +146,23 @@
adminCount: 0,
status: 1
};
export default {
name: 'roleList',
data() {
return {
//
listQuery: Object.assign({}, defaultListQuery),
//
list: null,
//
total: null,
//
listLoading: false,
//
dialogVisible: false,
//
isEdit: false,
//
role: Object.assign({}, defaultRole)
role: Object.assign({}, defaultRole),
isEdit: false
}
},
created() {
//
this.getList();
},
filters: {
//
formatDateTime(time) {
if (time == null || time === '') {
return 'N/A';
@ -207,40 +172,28 @@
}
},
methods: {
//
handleResetSearch() {
//
this.listQuery = Object.assign({}, defaultListQuery);
},
//
handleSearchList() {
//
this.listQuery.pageNum = 1;
this.getList();
},
//
handleSizeChange(val) {
//
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
//
handleCurrentChange(val) {
//
this.listQuery.pageNum = val;
this.getList();
},
//
handleAdd() {
// false
this.dialogVisible = true;
this.isEdit = false;
this.role = Object.assign({},defaultRole);
},
//
handleStatusChange(index, row) {
//
this.$confirm('是否要修改该状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -260,9 +213,7 @@
this.getList();
});
},
//
handleDelete(index, row) {
//
this.$confirm('是否要删除该角色?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -281,57 +232,44 @@
});
});
},
//
handleUpdate(index, row) {
// true
this.dialogVisible = true;
this.isEdit = true;
this.role = Object.assign({},row);
},
//
handleDialogConfirm() {
//
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
// API
updateRole(this.role.id,this.role).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
});
//
this.dialogVisible =false;
this.getList();
})
} else {
// API
createRole(this.role).then(response => {
this.$message({
message: '添加成功!',
type: 'success'
});
//
this.dialogVisible =false;
this.getList();
})
}
})
},
//
handleSelectMenu(index,row){
//
this.$router.push({path:'/ums/allocMenu',query:{roleId:row.id}})
},
//
handleSelectResource(index,row){
//
this.$router.push({path:'/ums/allocResource',query:{roleId:row.id}})
},
//
getList() {
this.listLoading = true;
fetchList(this.listQuery).then(response => {
@ -343,5 +281,6 @@
}
}
</script>
<style></style>

Loading…
Cancel
Save