This commit is contained in:
shahaibo
2024-04-02 16:15:22 +08:00
commit 67f5ce46ee
61 changed files with 30215 additions and 0 deletions

View File

@@ -0,0 +1,241 @@
<template>
<div class="export_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'Role Name or Id'"><a-input v-model:value="name" size="large" placeholder="Please input Role Name or Id" @keydown.enter="searchList()"/></filterComponent>
<filterComponent :title="'Period'">
<a-select
v-model:value="type"
size="large"
style="width:280px"
:options="labelTypeList"
allowClear
></a-select>
</filterComponent>
<filterComponent :title="'Export Time'"> <a-range-picker size="large" v-model:value="date" :placeholder="['Start Time', 'End Time']" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList()">Reset</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="setExport(record,index)">Export</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { message,Modal } from "ant-design-vue";
import { Moment } from 'moment';
import { Https } from "@/tool/https";
import { WarningOutlined } from '@ant-design/icons-vue';
export default defineComponent({
name:'roleManage',
components:{filterComponent},
setup(){
let filter = reactive({
name:'',
type:'',
date:ref<Moment[]>([])
})
let tableLoading = ref(false)
let columns = reactive([
{ title: 'Name', align:'center', ellipsis: true, dataIndex: 'exportName', key: 'exportName', width:250 },
{ title: 'Create Time', align:'center', ellipsis: true, dataIndex: 'createTime', key: 'createTime'},
{ title: 'Type', align:'center', ellipsis: true, dataIndex: 'span', key: 'span'},
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
// width: 250,
dataIndex:'operation',
},
])
let collectionList = ref([])
let labelTypeList:any = ref([
{ value:'week',label:'Week'},
{ value:'month',label:'Month'},
{ value:'year',label:'Year'},
])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getExportList()
}
let getExportList = () =>{
let data = {
page:currentPage.value,
size:pageSize.value,
fileName:filter.name,
span:filter.type,
endTime:filter.date[1]?filter.date[1]:'',
startTime:filter.date[0]?filter.date[0]:'',
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.miTuExportPage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
if(currentPage.value > 1 && rv.content.length == 0){
currentPage.value = 1
getExportList()
}else{
collectionList.value = rv.content
total = rv.total
}
}
}
).catch((res:any)=>{
tableLoading.value = false
})
}
let searchList = () =>{
currentPage.value = 1
getExportList()
}
let resetList = () =>{
currentPage.value = 1
filter.name = ''
getExportList()
}
let setExport = (data:any,index:any) =>{
Https.axiosGet(Https.httpUrls.miTuExportExport+`/${data.id}`,{responseType: 'blob'}).then((rv)=>{
let name = rv.name.split('=')[1];
let url = window.URL.createObjectURL(new Blob([rv.data], { type: rv.type }));
const link = document.createElement('a');
link.download = name; //定义表格名称,后缀是文件格式
link.style.display = 'none';
link.href = url;
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href)
document.body.removeChild(link);
})
}
onMounted(() => {
getExportList()
})
return {
...toRefs(filter),
tableLoading,
columns,
labelTypeList,
collectionList,
currentPage,
pageSize,
total,
changePage,
searchList,
resetList,
setExport,
}
},
});
</script>
<style lang="less" scoped>
.export_manage_page{
padding-left: 28px;
.export_pic{
width: 50px;
}
.operate_list{
display: flex;
// justify-content: space-between;
justify-content: center;
padding: 0 50px;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
}
}
}
.form_check_all{
margin: 10px 0;
}
.permission_table{
width: 100%;
margin-top: 10px;
border-left:1px solid #DFDFDF;
border-top:1px solid #DFDFDF;
td{
border-bottom: 1px solid #DFDFDF;
border-right: 1px solid #DFDFDF;
.table_td_block{
padding: 16px 0 16px 20px;
border-bottom: 1px solid #DFDFDF;
&:last-child{
border-bottom: none;
}
}
.table_td_permission{
display: flex;
min-height: 23px;
}
}
.first_td{
width: 120px;
}
.second_td{
width: 150px;
}
}
</style>

View File

@@ -0,0 +1,533 @@
<template>
<div class="user_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'User Name'"><a-input v-model:value="userName" size="large" placeholder="Please input User Name" @keydown.enter="searchList()"/></filterComponent>
<filterComponent :title="'User Phone'"><a-input v-model:value="userPhone" size="large" placeholder="Please input User Phone" @keydown.enter="searchList()" /></filterComponent>
<filterComponent :title="'User Role'">
<a-select v-model:value="roleId" size="large" style="width:280px" placeholder="Please select" :options="userRoleList" allowClear></a-select>
</filterComponent>
<filterComponent :title="'User State'">
<a-select v-model:value="state" size="large" style="width:280px" placeholder="Please select" :options="userStateList" allowClear></a-select>
</filterComponent>
<filterComponent :title="'Add Time'"><a-range-picker v-model:value="addTime" size="large" :placeholder="['Start Time', 'End Time']" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList()">Reset</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="addUser()">+Add User</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'stateName'">
<div :class="['state_name_block', record.state == 1 ? 'enable_state' :'disable_state']">
<div class="state_round"></div>
<div>{{record.stateName}}</div>
</div>
</template>
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editUser(record)">Edit</div>
<div :class="['operate_item', record.state == 0 ? '' :'operate_disable_state']" @click="enableUser(record,index)">
<div v-if="record.state == 0">Enable</div>
<div v-else>Disable</div>
</div>
<div class="operate_item" @click="deleteUser(record,index)">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<a-modal class="edit_modal_component"
:destroyOnClose="true"
v-model:visible="editUserModal"
:footer="null"
:title="editUserTitle"
width="680px"
:maskClosable="false"
:centered="true"
@cancel="closeUser"
>
<a-form ref="formRef" :model="formState" :rules="rules" :layout="'vertical'" >
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="User Name" name="userName">
<a-input v-model:value="formState.userName" size="large" placeholder="Please input user name"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Account" name="userAccount">
<a-input v-model:value="formState.userAccount" size="large" placeholder="Please input user account"/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="User Code" name="userPassword">
<a-input v-model:value="formState.userPassword" size="large" placeholder="Please input user code" type="password"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Phone" name="userPhone">
<a-input v-model:value="formState.userPhone" size="large" placeholder="Please input user phone"/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="App User" name="appUser">
<a-select v-model:value="formState.appUser" size="large" :options="appUserList" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Role" name="roleId">
<a-select v-model:value="formState.roleId" size="large" :options="userRoleList" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="24">
<a-form-item label="Owner Store" name="storeIds">
<a-select v-model:value="formState.storeIds" size="large" :options="ownerStoreList" mode="multiple" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="24">
<a-form-item label ="Remarks" name="remarks">
<a-input v-model:value="formState.remarks" size="large" placeholder="Please input remarks"/>
</a-form-item>
</a-col>
</a-row>
</a-form>
<div class="modal_button_list">
<a-button class="default_button btn-margin-r-20" size="large" @click="closeUser">Cancel</a-button>
<a-button class="primary_button" type="primary" size="large" @click="confirmSubmit">Submit</a-button>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { Moment } from 'moment';
import { message,Modal } from "ant-design-vue";
import { Https } from "@/tool/https";
import { WarningOutlined } from '@ant-design/icons-vue';
import { encode, decode } from 'js-base64';
import { useRoute } from 'vue-router'
import { formatTime, startTime, endTime, exportExcil } from "@/tool/util"
export default defineComponent({
name:'userManage',
components:{filterComponent},
setup(){
const route = useRoute()
let filter:any = reactive({
userName:'',
userPhone:'',
roleId:[],
state:[],
addTime:ref<Moment[]>([]),
})
let tableLoading = ref(false)
let userRoleList:any = ref([])
let userStateList:any = ref([
{value:'1',label:'Activated'},
{value:'0',label:'Deactivated'},
])
let appUserList:any = ref([
{value:1,label:'Yes'},
{value:0,label:'No'},
])
let ownerStoreList:any = ref([])
let columns = reactive([
{ title: 'User Name', align:'center', ellipsis: true, dataIndex: 'userName', key: 'userName' },
{ title: 'User Account', align:'center', ellipsis: true, dataIndex: 'userAccount', key: 'userAccount'},
{ title: 'Add Role', align:'center', ellipsis: true, dataIndex: 'roleName', key: 'roleName' },
{ title: 'User Phone', align:'center', ellipsis: true, dataIndex: 'userPhone', key: 'userPhone' },
{ title: 'Owned Store', align:'center', ellipsis: true, dataIndex: 'storeName', key: 'storeName',customRender:(record:any)=>{
let storeNameNew = record.text.join(',')
return storeNameNew
}
},
{ title: 'Add Time', align:'center', ellipsis: true, dataIndex: 'createDate', key: 'createDate' ,customRender:(record:any)=>{
let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return time
},
},
{ title: 'Activated', align:'center', ellipsis: true, dataIndex: 'appUserName', key: 'appUserName' },
{ title: 'User State', align:'center', ellipsis: true, dataIndex: 'stateName', key: 'stateName' },
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 150,
dataIndex:'operation',
},
])
let collectionList:any = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let editUserModal = ref(false)
let editUserTitle = ref('Add user')
let formRef = ref();
let formState:any = ref({
id: '',
userName: '',
userAccount: '',
userPassword:'',
userPhone:'',
appUser:null,
roleId:null,
storeIds:[],
remarks:'',
});
let rules = {
userName: [
{ required: true, message: 'Please input user name', trigger: 'blur' },
],
userAccount: [
{ required: true, message: 'Please input user account', trigger: 'blur' },
{ min: 6, max: 20, message: 'Length should be 6 to 20', trigger: 'blur' },
],
userPassword: [
{ required: true, message: 'Please input user code', trigger: 'blur' },
{ min: 6, max: 20, message: 'Length should be 6 to 20', trigger: 'blur' },
],
userPhone: [
{ required: true, message: 'Please input user phone', trigger: 'blur' },
{ pattern: /^\d*$/, message: 'The format of the mobile phone number is incorrect', trigger: 'blur' },
],
appUser: [
{ required: true, message: 'Please select app user', trigger: 'blur' },
],
userRole: [
{ required: true, message: 'Please select user role', trigger: 'blur' },
],
ownerStore: [
{ required: true, message: 'Please select owner store', trigger: 'blur' },
],
}
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getUserlist()
}
let closeUser = () =>{
formState.value = {
id: '',
userName: '',
userAccount: '',
userPassword:'',
userPhone:'',
appUser:null,
roleId:null,
storeIds:[],
remarks:'',
}
editUserModal.value = false
}
let addUser = () =>{
editUserTitle.value = 'Add user'
editUserModal.value = true
// const data = [
// [
// ['12312312312'],
// ['姓名', '年龄', '性别'],
// ['张三', 20, '男'],
// ['李四', 25, '女']
// ],
// [
// ['城市', '人口'],
// ['北京', 21540000],
// ['上海', 24240000]
// ]
// ];
// const sheetNames = ['Sheet1', 'Sheet2'];
// const fileName = 'output.xlsx';
// const configuration = {
// width:15,
// titleCell:2,
// }
// exportExcil(data,sheetNames,fileName,configuration)
}
let editUser = (data:any,) =>{
editUserModal.value = true
editUserTitle.value = 'Eidt user'
formState.value = {
id: data.id,
userName: data.userName,
userAccount:data.userAccount,
userPassword:data.userPassword ? decode(data.userPassword) : '',
userPhone:data.userPhone,
appUser:data.appUser,
roleId:String(data.roleId),
storeIds:data.storeIds,
remarks:data.remarks,
}
}
let getUserlist = () =>{
let data = {
userName : filter.userName,
userPhone:filter.userPhone,
state:filter.state && filter.state.length ? filter.state : '',
roleId:filter.roleId && filter.roleId.length ? filter.roleId : '',
createDateStart:filter.addTime && filter.addTime.length ? startTime(filter.addTime[0]) :'',
createDateEnd:filter.addTime && filter.addTime.length ? endTime(filter.addTime[1]) :'',
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.accountQueryUserPage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content
total.value = rv.total
}
}
);
}
let getRolelist = () =>{
Https.axiosPost(Https.httpUrls.roleQueryAll, {}).then(
(rv: any) => {
if (rv) {
userRoleList.value = rv.map((v:any)=>{
let data = {
...v,
value:v.id,
label:v.name
}
return data
})
}
}
);
}
let searchList = () =>{
currentPage.value = 1
getUserlist()
}
let resetList = () =>{
currentPage.value = 1
filter.userName = ''
filter.userPhone = ''
filter.roleId = []
filter.state = []
filter.addTime = ref<Moment[]>([])
getUserlist()
}
let confirmSubmit = () =>{
let data = {
...formState.value,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
data.userPassword = encode(data.userPassword)
let submit = () =>{
Https.axiosPost(Https.httpUrls.accountSaveOrEdit, data).then(
(rv: any) => {
if (rv) {
let tip = !formState.value.id ? 'User added successfully' :'Edit user successfully'
message.success(tip)
resetList()
closeUser()
}
}
);
}
formRef.value.validate().then(()=>{
submit()
})
}
let enableUser = (record:any,index:any) =>{
let data ={
id:record.id,
enable:record.state == 1 ? 0 : 1
}
Https.axiosPost(Https.httpUrls.accountEnable, data).then(
(rv: any) => {
if (rv) {
let tip = record.state == 0? 'Enable successfully' :'Disable successfully'
message.success(tip)
collectionList.value[index].state = data.enable
collectionList.value[index].stateName = data.enable == 1 ? 'Activated' :'Deactivated'
}
}
);
}
let deleteUser = (data:any,index:any) =>{
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.accountDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: "Are you sure delete the user?",
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
let storeQueryAll = () =>{
Https.axiosPost(Https.httpUrls.storeQueryAll,{}).then(
(rv: any) => {
if (rv) {
ownerStoreList.value = rv.map((v:any)=>{
let data = {
...v,
value:v.id,
label:v.name
}
return data
})
}
}
);
}
onMounted(() => {
if(route.query && route.query.type === 'add'){
addUser()
}
getUserlist()
storeQueryAll()
getRolelist()
})
return {
...toRefs(filter),
tableLoading,
userRoleList,
userStateList,
appUserList,
ownerStoreList,
columns,
collectionList,
currentPage,
pageSize,
total,
editUserModal,
editUserTitle,
formRef,
formState,
rules,
changePage,
closeUser,
addUser,
editUser,
searchList,
resetList,
confirmSubmit,
enableUser,
deleteUser
}
},
});
</script>
<style lang="less" scoped>
.user_manage_page{
padding-left: 28px;
.user_pic{
width: 50px;
}
.state_name_block{
display: flex;
align-items: center;
font-size: 14px;
justify-content: center;
&.enable_state{
color: #47E417;
.state_round{
background: #47E417;
}
}
&.disable_state{
color: #E41335;
.state_round{
background: #E41335;
}
}
.state_round{
width: 14px;
height: 14px;
border-radius: 50%;
margin-right: 5px;
}
}
.operate_list{
display: flex;
justify-content: space-between;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
&.operate_disable_state{
color: #E41335;
}
}
}
}
</style>

View File

@@ -0,0 +1,321 @@
<template>
<div class="label_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'Label Name'"><a-input v-model:value="name" size="large" placeholder="Please input Label Name or Id" @keydown.enter="searchList"/></filterComponent>
<filterComponent :title="'Label attributes'">
<a-select
v-model:value="type"
size="large"
style="width:280px"
:options="labelTypeList"
placeholder="Please select"
allowClear
></a-select>
</filterComponent>
<filterComponent :title="'Add Time'"><a-range-picker v-model:value="addTime" size="large" :placeholder="['Start Time', 'End Time']" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList()">Reset</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="addLabel()">+Add Label</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editLabel(record)">Edit</div>
<div class="operate_item" @click="deleteLabel(record,index)">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<a-modal class="edit_modal_component"
:destroyOnClose="true"
v-model:visible="editLabelModal"
:footer="null"
:title="editLabelTitle"
width="560px"
:maskClosable="false"
:centered="true"
@cancel="closeLabel"
>
<a-form ref="formRef" :model="formState" :rules="rules" :layout="'vertical'" >
<a-form-item label="Label Name" name="name">
<a-input v-model:value="formState.name" size="large" placeholder="Please input label name" />
</a-form-item>
<a-form-item label="Label attributes" name="type">
<a-select v-model:value="formState.type" size="large" :options="labelTypeList" placeholder="Please select label attributes"></a-select>
</a-form-item>
<a-form-item label="Remarks" name="remarks">
<a-input v-model:value="formState.remarks" size="large" placeholder="Please input remarks"/>
</a-form-item>
</a-form>
<div class="modal_button_list">
<a-button class="default_button btn-margin-r-20" size="large" @click="closeLabel">Cancel</a-button>
<a-button class="primary_button" type="primary" size="large" @click="confirmSubmit">Submit</a-button>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { Moment } from 'moment';
import { message,Modal } from "ant-design-vue";
import { WarningOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https";
import { formatTime, startTime, endTime } from "@/tool/util"
export default defineComponent({
name:'labelManage',
components:{filterComponent},
setup(){
let filter:any = reactive({
name:'',
type:'',
addTime:ref<Moment[]>([])
})
let tableLoading = ref(false)
let labelTypeList:any = ref([
{ value:'CUSTOM',label:'Custom tags'},
{ value:'NEW_PRODUCT',label:'New in'},
{ value:'SALE',label:'Discount'},
])
let labelTypeData:any = {
'CUSTOM':'Custom tags',
'NEW_PRODUCT':'New in',
'SALE':'Discount'
}
let columns = reactive([
{ title: 'Label Name', align:'center', ellipsis: true, dataIndex: 'name', key: 'name' },
{ title: 'Label attributes', align:'center', ellipsis: true, dataIndex: 'type', key: 'type', customRender:(record:any)=>{
let labelType = labelTypeData[record.text]
return labelType },
},
{ title: 'Add User', align:'center', ellipsis: true, dataIndex: 'createUserName', key: 'createUserName' },
{ title: 'Label Product Counts', align:'center', ellipsis: true, dataIndex: 'counts', key: 'counts' },
{ title: 'Remarks', align:'center', ellipsis: true, dataIndex: 'remarks', key: 'remarks' },
{ title: 'Add Time', align:'center', ellipsis: true, dataIndex: 'createDate', key: 'createDate',customRender:(record:any)=>{
let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return time },
},
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 150,
dataIndex:'operation',
},
])
let collectionList = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let editLabelModal = ref(false)
let editLabelTitle = ref('Add Label')
let formRef = ref();
let formState = ref({
id: '',
name: '',
type:[],
remarks:'',
});
let rules = reactive({
name: [
{ required: true, message: 'Please input label name', trigger: 'blur' },
],
type: [
{ required: true, message: 'Please select label attributes', trigger: 'blur' },
],
})
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getLabelist()
}
let closeLabel = () =>{
formState.value = {
id: '',
name: '',
type:[],
remarks:''
}
editLabelModal.value = false
}
let addLabel = () =>{
editLabelTitle.value = 'Add Label'
editLabelModal.value = true
}
let editLabel = (data:any,) =>{
editLabelModal.value = true
editLabelTitle.value = 'Eidt Label'
formState.value = {
id: data.id,
name: data.name,
type:data.type,
remarks:data.remarks,
}
}
let getLabelist = () =>{
let data = {
name : filter.name,
type:filter.type,
createDateStart:filter.addTime && filter.addTime.length ? startTime(filter.addTime[0]) : '',
createDateEnd:filter.addTime && filter.addTime.length ? endTime(filter.addTime[1]) : '',
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.labelQueryStorePage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content
total.value = rv.total
}
}
);
}
let confirmSubmit = () =>{
let data = {
...formState.value,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
formRef.value.validate().then(()=>{
submit()
})
let submit = () => {
Https.axiosPost(Https.httpUrls.labelSaveOrEdit, data).then(
(rv: any) => {
if (rv) {
let tip = !formState.value.id ? 'Label added successfully' :'Edit label successfully'
message.success(tip)
resetList()
closeLabel()
}
}
);
}
}
let searchList = () =>{
currentPage.value = 1
getLabelist()
}
let resetList = () =>{
currentPage.value = 1
filter.name = ''
filter.type = ''
filter.addTime = ref<Moment[]>([])
getLabelist()
}
let deleteLabel = (data:any,index:any) =>{
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.labelDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: "Are you sure about the label? The label associated with the product will become invalid after deletion!",
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
onMounted(() => {
getLabelist()
})
return {
...toRefs(filter),
tableLoading,
labelTypeList,
columns,
collectionList,
currentPage,
pageSize,
total,
editLabelModal,
editLabelTitle,
formRef,
formState,
rules,
changePage,
closeLabel,
addLabel,
editLabel,
confirmSubmit,
searchList,
resetList,
deleteLabel
}
},
});
</script>
<style lang="less" scoped>
.label_manage_page{
padding-left: 28px;
.operate_list{
display: flex;
justify-content: space-between;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,485 @@
<template>
<div class="productDetail_page">
<div class="productDetail_page_cotent">
<div class="productDetail_page_cotent_center">
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Product image</div>
</div>
<div class="product_master_diagram">
<img class="product_master_img" :src="formState.pictureUrl">
</div>
</div>
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Product label(s)</div>
</div>
<div class="detail_item_content">
<div class="productCategory_block">
<div class="produce_label_item" :style="{background:colorMap[label.type]}" v-for="label in productLabelList" :key="label.id">{{label.name}}</div>
</div>
</div>
</div>
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Pirce</div>
</div>
<div class="detail_item_content">
<div class="productCategory_block">${{formState.price}}</div>
</div>
</div>
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Inventory</div>
</div>
<div class="detail_item_content">
<a-table class="form_width_100" :columns="columns" :data-source="formState.storeList" bordered
:pagination="false" :scroll="{y: 400 }">
</a-table>
</div>
</div>
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Label attributes</div>
</div>
<div class="detail_item_content">
<div class="productCategory_block">{{formState.productCategory}}</div>
</div>
<div>
<div class="detail_item_sec_title sec_title_margin">Attribute(s)</div>
<div class="detail_item_content">
<div class="attribute_block" v-if="formState.productAttribute?.length">
<div class="attribute_block_item" v-for="attr in formState.productAttribute" :key="attr.value">
<div class="attribute_block_item_content">
<div class="attribute_item_title">{{attr.labelType}}</div>
<div class="attribute_item_value" :title="attr.attributeValueList.join(',')">{{attr.attributeValueList.join(',')}}</div>
</div>
</div>
</div>
<div v-else class="null_data_block">
<img class="null_data_img" src="@/assets/images/null_img.png">
</div>
</div>
</div>
</div>
<div class="detail_item_block">
<div class="detail_item_title_block">
<span class="icon iconfont icon-a-gengduocaidangongneng detail_icon"></span>
<div>Mix and Match(es)</div>
</div>
<div class="detail_item_content">
<div class="product_match_block">
<div class="product_match_item" v-for="(match,index) in formState.assortmentList" :key="match.title" v-show="index<5 || assortmentShowMore">
<div class="product_match_item_header">
<div>Look{{index+1}}</div>
</div>
<div class="product_match_item_content">
<div class="match_item_img_content" v-for="img in match" :key="img">
<div class="match_item_img_block" @click="showMatchDetail(img.productId)">
<img :src="img.generatePictureUrl">
</div>
<div class="product_price">${{img.price}}</div>
</div>
</div>
</div>
</div>
<a-button class="primary_button show_more_button" type="primary" @click="assortmentListShowMore()" v-show="formState.assortmentList.length>5">{{assortmentShowMore?'Hide':'See More'}}</a-button>
</div>
</div>
</div>
</div>
<ProductDetailModal ref="productDetailModalDom"></ProductDetailModal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,onMounted,reactive } from "vue";
import { message } from "ant-design-vue";
import { useRouter,useRoute } from 'vue-router'
import { Https } from "@/tool/https";
import ProductDetailModal from '@/component/productComponent/productDetailModal.vue'
export default defineComponent({
name:'productDetail',
components:{ProductDetailModal},
setup(){
const route = useRoute()
let productDetail:any = ref([])
let productDetailModalDom:any = ref()
let formState:any = ref({
productPic:'',
productLabel:[],
inventoryData:[],
storeList:[],
storeNameList:[],
productCategory:'',
productAttribute:[],
assortmentList:[]
});
let assortmentShowMore = ref(false)
let productCategoryList:any = ref([])
let productAttributeList = ref([])
let columns = reactive([
{ title: 'Store', align:'center', ellipsis: true, dataIndex: 'storeName', key: 'storeName',width:"200px" },
{
title: 'Inventory',
align:'center',
ellipsis: true,
dataIndex: 'inventory',
key: 'inventory',
children: [
{title: 'XS',dataIndex: 'XS',key: 'XS', align:'center', },
{title: 'S',dataIndex: 'S',key: 'S', align:'center',},
{title: 'M',dataIndex: 'M',key: 'M', align:'center',},
{title: 'L',dataIndex: 'L',key: 'L', align:'center',},
{title: 'XL',dataIndex: 'XL',key: 'XL', align:'center',},
{title: 'XXL',dataIndex: 'XXL',key: 'XXL', align:'center',},
],
},
])
let colorMap = ref({
CUSTOM:'#798BD9',
NEW_PRODUCT:'#FFC384',
SALE:'#79D97C',
})
let productLabelList:any = ref([])
let getProductLabelList = () =>{
Https.axiosPost(Https.httpUrls.queryProductLabel).then(
(rv: any) => {
if (rv) {
productLabelList.value = rv.filter((v:any) => formState.value.productLabel.indexOf(v.id) > -1)
}
}
);
}
let getStoreInfo = (storeInfo:any) =>{
let storeList = []
let storeNameList:any = []
for(let item of storeInfo){
let sizeData:any = {}
for(let size of item.stock){
sizeData[size.size] = size.num
}
let data = {
storeName:item.storeName,
storeId:item.storeId,
...sizeData,
}
storeList.push(data)
}
storeInfo.forEach((item:any) => {
item.stock.forEach((stockItem:any) => {
storeNameList.push(stockItem.size);
});
});
// 排序并去重
storeNameList = storeNameList.sort().filter((value:any, index:any, array:any) => {
return array.indexOf(value) === index;
});
let children:any = []
storeNameList.forEach((item:any) => {
children.push({
title:item,
dataIndex:item,
key:item,
align:'center'
})
});
columns[1].children = children
return {storeList,storeNameList}
}
let getProductDetail = (id:any) =>{
return new Promise((resolve:any,rj:any)=>{
Https.axiosGet(Https.httpUrls.productDetail+'?id='+id).then(
(rv: any) => {
if (rv) {
let store = getStoreInfo(rv.storeInfoList)
formState.value = {
pictureUrl:rv.pictureUrl,
productLabel:rv.productLabelInfo.map((v:any)=>v.id),
price:rv.price,
productCategory:rv.attributeItemInfo.labelItem,
productAttribute:rv.attributeItemInfo.attributeTypeList,
storeList:store.storeList,
storeNameList:store.storeNameList,
assortmentList:rv.assortmentList,
}
productDetail.value = rv
resolve(rv)
}
}
);
})
}
let showMatchDetail = (productId:any) =>{
productDetailModalDom.value.openProductDetailModal(productId)
}
let assortmentListShowMore = () =>{
assortmentShowMore.value = !assortmentShowMore.value
}
onMounted(() => {
getProductDetail(route.query.id).then(rv=>{
getProductLabelList()
})
})
return {
productDetailModalDom,
columns,
formState,
assortmentShowMore,
productCategoryList,
productAttributeList,
colorMap,
productLabelList,
showMatchDetail,
assortmentListShowMore,
}
},
});
</script>
<style lang="less" scoped>
.productDetail_page{
padding-left: 28px;
height: 100%;
.productDetail_page_cotent{
width: 100%;
min-height: 100%;
background: #fff;
.productDetail_page_cotent_center{
width: 1150px;
padding: 20px 70px 30px 30px;
margin: 0 auto;
height: 100%;
}
.detail_item_block{
margin-bottom: 15px;
.detail_icon{
color: #80B8F8;
font-size: 24px;
margin-right: 14px;
}
.detail_item_title_block{
display: flex;
align-items: center;
font-size: 16px;
font-family: Adobe Heiti Std;
font-weight: normal;
color: #030303;
margin-bottom: 10px;
}
.detail_item_content{
padding-left: 10px;
width: 100%;
position: relative;
}
.produce_label_item{
padding: 0 11px;
margin: 9px 27px 9px 0;
height: 27px;
line-height: 27px;
box-sizing: border-box;
border-radius: 4px;
font-size: 16px;
color: #fff;
display: inline-block;
vertical-align: top;
}
.productCategory_block{
width: 100%;
line-height: 46px;
padding-left: 20px;
font-size: 18px;
color: #030303;
height: 46px;
border: 1px solid #DFDFDF;
}
.detail_item_sec_title{
padding-left: 38px;
font-size: 16px;
font-family: Adobe Heiti Std;
font-weight: normal;
color: #030303;
margin-bottom: 10px;
}
.sec_title_margin{
margin: 10px 0;
}
.attribute_block{
background: #F7F8FC;
border: 1px solid #DFDFDF;
padding-top: 30px;
.attribute_block_item{
padding: 0 22px;
display: inline-block;
margin-bottom: 30px;
width: 50%;
.attribute_block_item_content{
display: flex;
align-items: center;
.attribute_item_title{
width: 120px;
margin-right: 20px;
}
.attribute_item_value{
width: 200px;
height: 36px;
line-height: 36px;
border: 1px solid #DFDFDF;
border-radius: 4px;
font-size: 16px;
padding-left: 18px;
color: #030303;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
}
.null_data_block{
background: #F7F8FC;
border: 1px solid #DFDFDF;
padding: 30px 0;
text-align: center;
.null_data_img{
width: 130px;
}
}
.product_match_block{
.product_match_item{
background: #F7F8FC;
border: 1px solid #DFDFDF;
padding: 0 16px 26px;
margin-bottom: 20px;
.product_match_item_header{
height: 83px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 18px;
color: #030303;
}
.product_match_item_content{
display: flex;
.match_item_img_content{
margin-right: 20px;
width: 160px;
}
.match_item_img_block{
display: flex;
align-items: center;
justify-content: center;
width: 160px;
height: 100px;
position: relative;
border: 1px solid #DFDFDF;
cursor: pointer;
img{
max-width: 100%;
max-height: 100%;
}
&:last-child{
margin-right: 0;
}
}
.product_price{
text-align: center;
margin-top: 5px;
color: #030303;
}
}
}
}
.show_more_button{
margin: 20px auto;
display: block;
}
}
.form_width_100{
width: 100%;
}
.product_master_diagram{
width: 400px;
height: 400px;
margin: 30px auto;
display: flex;
align-items: center;
justify-content: center;
.product_master_img{
max-width: 100%;
max-height: 100%;
}
}
}
}
</style>

View File

@@ -0,0 +1,580 @@
<template>
<div class="product_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'Product Label'">
<a-select v-model:value="productLabelIds" size="large" style="width:280px" optionFilterProp="label" :options="productLabelList" placeholder="Please select" allowClear show-search></a-select>
</filterComponent>
<filterComponent :title="'Category'">
<a-select v-model:value="labelItem" size="large" style="width:280px" :options="labelItemList" placeholder="Please select" allowClear @change="labelItemChange" optionFilterProp="label" show-search></a-select>
</filterComponent>
<filterComponent :title="'On Sale State'">
<a-select v-model:value="onSaleState" size="large" style="width:280px" :options="onSaleStateList" placeholder="Please select" allowClear optionFilterProp="label" show-search></a-select>
</filterComponent>
<filterComponent :title="'Label attributes'">
<a-select v-model:value="labelTypeMap" size="large" style="width:280px" :options="labelTypeList" placeholder="Please select" allowClear @change="labelTypeChange" optionFilterProp="label" show-search></a-select>
</filterComponent>
<filterComponent :title="'Add Time'"><a-range-picker v-model:value="addTime" size="large" :placeholder="['Start Time', 'End Time']" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD"/></filterComponent>
<filterComponent :title="'Store'">
<a-select v-model:value="storeIds" size="large" style="width:280px" :options="shopList" placeholder="Please select" allowClear optionFilterProp="label" show-search></a-select>
</filterComponent>
</div>
</div>
<div class="list_top_button_content" :style="{width: '255px'}">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button btn-margin-r-20" size="large" @click="resetList()">Reset</a-button>
<a-button class="primary_button btn-margin-t-35 btn-margin-r-20" type="primary" size="large" @click="addProduct()" v-if="operatePermission.ADD">+Add product</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="exportProduct()" :loading="exportLoading">Export</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:getPopupContainer="(triggerNode) => getPopupContainer(triggerNode)"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'pictureUrl'">
<img class="product_pic" :src="record.pictureUrl">
</template>
<template v-if="column.dataIndex === 'productLabel'">
<a-popover placement="top" :getPopupContainer="(triggerNode) => getPopupContainer(triggerNode)" arrowPointAtCenter>
<template #content>
<div class="record_pop_block">{{record.productLabel}}</div>
</template>
<div class="record_pop_content">{{record.productLabel}}</div>
</a-popover>
</template>
<template v-if="column.dataIndex === 'labelType'">
<a-popover placement="top" :getPopupContainer="(triggerNode) => getPopupContainer(triggerNode)">
<template #content>
<div class="record_pop_block">{{record.labelType}}</div>
</template>
<div class="record_pop_content">{{record.labelType}}</div>
</a-popover>
</template>
<template v-if="column.dataIndex === 'shop'" >
<a-popover placement="top" :getPopupContainer="(triggerNode) => getPopupContainer(triggerNode)">
<template #content>
<div class="record_pop_block">{{record.shop}}</div>
</template>
<div class="record_pop_content">{{record.shop}}</div>
</a-popover>
</template>
<template v-if="column.dataIndex === 'onSaleState'">
<a-switch checked-children="open" un-checked-children="close" v-model:checked="record.onSaleState" @change="change_on_sale(record)"/>
</template>
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editProduct(record)" v-if="operatePermission.EDIT">Edit</div>
<div class="operate_item" @click="toProductDteail(record)" v-if="operatePermission.DETAIL">Detail</div>
<div class="operate_item" @click="deleteProduct(record,index)" v-if="operatePermission.DELETE">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<AddProduct ref="addproductComponent" :productLabelList="productLabelList" @confirmSubmitAdd="confirmSubmitAdd"></AddProduct>
<EditProduct ref="editProductComponent" :productLabelList="productLabelList" @refreshList="getProductlist"></EditProduct>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode,computed } from "vue";
import { useRouter,useRoute } from 'vue-router'
import filterComponent from '@/component/filterComponent.vue'
import AddProduct from '@/component/productComponent/addProduct.vue'
import EditProduct from '@/component/productComponent/editProduct.vue'
import { Moment } from 'moment';
import { message,Modal } from "ant-design-vue";
import { WarningOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https";
import { formatTime, startTime, endTime } from "@/tool/util"
type TableDataType = {
key: string;
name: string;
age: number;
createDate: string;
};
export default defineComponent({
name:'productManage',
components:{filterComponent,AddProduct,EditProduct},
setup(){
const router = useRouter()
const route = useRoute()
let filter:any = reactive({
productLabelIds:[],
labelItem:[],
onSaleState:[],
labelTypeMap:[],
addTime:ref<Moment[]>([]),
storeIds:[],
})
let filterLabelTypeMap :any = ref({})
let tableLoading = ref(false)
let exportLoading = ref(false)
let addproductComponent:any = ref(null)
let editProductComponent:any = ref(null)
let productLabelList:any = ref([])
let labelItemList:any = ref([])
let labelTypeList:any = ref([])
let onSaleStateList:any = ref([{
value:'1',label:'Open'
},{
value:'0',label:'Close'
}])
let shopList:any = ref([])
const columns = computed(() => {
const sorted = sortedInfo.value || {};
return [
{ title: 'Product Pic', align:'center', ellipsis: true, dataIndex: 'pictureUrl', key: 'pictureUrl' },
{ title: 'Product Label', align:'center', dataIndex: 'productLabel', key: 'productLabel'},
{ title: 'Category', align:'center', ellipsis: true, dataIndex: 'labelItem', key: 'labelItem'},
{ title: 'Label attributes', align:'center', dataIndex: 'labelType', key: 'labelType'},
{ title: 'Shop', align:'center', dataIndex: 'shop', key: 'shop' },
{ title: 'Inventory', align:'center', ellipsis: true, dataIndex: 'total', key: 'total', sorter:()=>{},
sortOrder: sorted.columnKey === 'total' && sorted.order,
},
{ title: 'price', align:'center', ellipsis: true, dataIndex: 'price', key: 'price',customRender:(record:any)=>{
let newPrrice = '$' + record.text
return newPrrice },
sorter:()=>{},
sortOrder: sorted.columnKey === 'price' && sorted.order,
},
{ title: 'Add Time', align:'center', ellipsis: true, dataIndex: 'createDate', key: 'createDate',customRender:(record:any)=>{
let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return time },
sorter:()=>{},
sortOrder: sorted.columnKey === 'createDate' && sorted.order,
},
{ title: 'On Sale State', align:'center', ellipsis: true, dataIndex: 'onSaleState', key: 'onSaleState' },
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 150,
dataIndex:'operation',
},
]
})
let collectionList = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let editProductTitle = ref('Add Product')
let formState = ref({
productId: '',
productName: '',
productType:'',
remarks:'',
});
let columnSortListData:any = []; //排序参数
let sortedInfo:any = ref()
let typeMap:any = {
dress:'Dress_Type',
top:'Top_Type',
bottom:'BTM_Type',
outer:'Outer_Type',
jumpsuit:'Jumpsuit_subtype'
}
let rules = {
productName: [
{ required: true, message: 'Please input product name', trigger: 'blur' },
],
productType: [
{ required: true, message: 'Please select product type', trigger: 'blur' },
],
}
let operatePermission:any = reactive({
DETAIL:false,
ADD:false,
EDIT:false,
DELETE:false,
})
let getPopupContainer = (triggerNode:any) =>{
return triggerNode.parentNode || document.body
}
let changePage = (e:any, filters: any, sorter: any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
if(sorter.order){
columnSortListData = [{
column:getSortField(sorter.field),
style:sorter.order == 'ascend' ? 'asc' : 'desc'
}]
sortedInfo.value = sorter
}else{
columnSortListData = []
sortedInfo.value = sorter
}
getProductlist()
}
let getSortField = (field:string) =>{
let fieldData:any = {
createDate: 'create_date',
price:'price',
total:'total',
}
return fieldData[field]
}
let closeProduct = () =>{
formState.value = {
productId: '',
productName: '',
productType:'',
remarks:'',
}
}
let addProduct = () =>{
addproductComponent.value.showModal()
}
let change_on_sale = (record:any) =>{
let data = {
id:record.id,
onSaleState:record.onSaleState ? 1 : 0
}
Https.axiosPost(Https.httpUrls.doOnSale, data).then(
(rv: any) => {
if (rv) {
}
}
);
}
let editProduct = (record:any) =>{
editProductComponent.value.showModal({record:record,labelItemList:labelItemList.value})
}
let toProductDteail = (record:any) =>{
router.push({path:'/home/productDetail',query:{id:record.id}})
}
let getProductlist = () =>{
let data = {
columnSortList:columnSortListData,
productLabelIds:filter.productLabelIds && filter.productLabelIds.length ? [filter.productLabelIds] : [],
labelItem:filter.labelItem && filter.labelItem.length ? filter.labelItem : '',
onSaleState:filter.onSaleState && filter.onSaleState.length ? filter.onSaleState : '',
labelTypeMap:filterLabelTypeMap.value,
storeIds:filter.storeIds && filter.storeIds.length ? [filter.storeIds] : [],
createDateStart:filter.addTime && filter.addTime.length ? startTime(filter.addTime[0]) : '',
createDateEnd:filter.addTime && filter.addTime.length ? endTime(filter.addTime[1]) : '',
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.queryProductPage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content.map((v:any)=>{
return {
...v,
onSaleState:v.onSaleState == 1? true :false,
productLabel:getProductLabel(v.productLabelInfo),
labelItem:v.attributeItemInfo.labelItem,
labelType:getLabelType(v.attributeItemInfo || []),
shop:getStoreName(v.storeInfoList)
}
})
getProductPromission()
total.value = rv.total
}
}
).catch((err:any)=>{
tableLoading.value = false
})
}
let getProductLabel = (productLabelInfo:any) =>{
let productLabel = productLabelInfo.map((v:any) => v.name).join(',')
return productLabel
}
let getLabelType = (attributeItemInfo:any) => {
// let labelType = attributeItemInfo.attributeTypeList ? attributeItemInfo.attributeTypeList.filter((v:any) => v.labelType === typeMap[attributeItemInfo.labelItem]) :[]
// labelType = labelType.map(((v:any)=>v.attributeValueList)).join(',')
let labelType = attributeItemInfo.labelTypeValueList && attributeItemInfo.labelTypeValueList.length ? attributeItemInfo.labelTypeValueList.join(',') : ''
return labelType
}
let getStoreName = (storeInfoList:any) =>{
let storeName = storeInfoList.map((v:any) => v.storeName).join(',')
return storeName
}
let getProductLabelList = () =>{
Https.axiosPost(Https.httpUrls.queryProductLabel).then(
(rv: any) => {
if (rv) {
productLabelList.value = rv.map((v:any)=>{
return {
...v,
value:v.id,
label:v.name
}
})
}
}
);
}
let getStoreList = () =>{
Https.axiosPost(Https.httpUrls.queryProductStore).then(
(rv: any) => {
if (rv) {
shopList.value = rv.map((v:any)=>{
return {
...v,
value:v.id,
label:v.name
}
})
}
}
);
}
let getAttributeList = () =>{
Https.axiosGet(Https.httpUrls.attributeQueryAll).then(
(rv: any) => {
if (rv) {
labelItemList.value = rv.map((v:any)=>{
return {
...v,
value:v.labelItem,
label:v.labelItem
}
})
}
}
);
}
let labelItemChange = (event:any,selectedOptions:any) =>{
filter.labelTypeMap =[]
filterLabelTypeMap.value = {}
if(selectedOptions){
labelTypeList.value = selectedOptions.labelTypeValueList.map((v:any)=>{
return {
value:v,
label:v
}
})
}else{
labelTypeList.value = []
}
}
let labelTypeChange = (event:any,selectedOptions:any) => {
let key = typeMap[filter.labelItem]
if(selectedOptions){
filterLabelTypeMap.value[key] = [event]
}else{
filterLabelTypeMap.value = {}
}
}
let searchList = () =>{
currentPage.value = 1
getProductlist()
}
let exportProduct = () =>{
let data = {
columnSortList:columnSortListData,
productLabelIds:filter.productLabelIds && filter.productLabelIds.length ? [filter.productLabelIds] : [],
labelItem:filter.labelItem && filter.labelItem.length ? filter.labelItem : '',
onSaleState:filter.onSaleState && filter.onSaleState.length ? filter.onSaleState : '',
labelTypeMap:filterLabelTypeMap.value,
storeIds:filter.storeIds && filter.storeIds.length ? [filter.storeIds] : [],
createDateStart:filter.addTime && filter.addTime.length ? startTime(filter.addTime[0]) : '',
createDateEnd:filter.addTime && filter.addTime.length ? endTime(filter.addTime[1]) : '',
}
exportLoading.value = true
Https.axiosPost(Https.httpUrls.exportProduct, data).then(
(rv: any) => {
if (rv) {
exportLoading.value = false
window.location.href= rv
}
}
).catch((err:any)=>{
exportLoading.value = false
})
}
let resetList = () =>{
currentPage.value = 1
filter.productLabelIds = []
filter.labelItem = []
filter.onSaleState = []
filter.labelTypeMap = []
filter.addTime = ref<Moment[]>([])
filter.storeIds = []
sortedInfo.value = null
columnSortListData = []
getProductlist()
}
let deleteProduct = (data:any,index:any) =>{
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.productDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: "Are you sure about the product? The product associated with the product will become invalid after deletion!",
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
let getProductPromission = () =>{
let menuList:any = sessionStorage.getItem('menuList')
menuList= JSON.parse(menuList)
for(let item of menuList){
if(item.name === 'Product Management'){
for(let operate of item.operationList){
operatePermission[operate.code] = operate.select == 1 ? true :false
}
}
}
}
let confirmSubmitAdd = () =>{
resetList()
}
onMounted(() => {
if(route.query && route.query.type === 'add'){
addProduct()
}
getProductlist()
getProductLabelList()
getStoreList()
getAttributeList()
})
return {
...toRefs(filter),
addproductComponent,
editProductComponent,
tableLoading,
exportLoading,
productLabelList,
labelItemList,
labelTypeList,
onSaleStateList,
shopList,
columns,
collectionList,
currentPage,
pageSize,
total,
editProductTitle,
formState,
rules,
operatePermission,
getPopupContainer,
changePage,
closeProduct,
addProduct,
change_on_sale,
editProduct,
toProductDteail,
labelItemChange,
labelTypeChange,
searchList,
exportProduct,
resetList,
deleteProduct,
confirmSubmitAdd,
getProductlist
}
},
});
</script>
<style lang="less" scoped>
.product_manage_page{
padding-left: 28px;
.product_pic{
width: 50px;
}
.operate_list{
display: flex;
justify-content: space-between;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
}
}
.record_pop_block{
max-width: 300px;
// word-break: break-all;
}
.record_pop_content{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
</style>

View File

@@ -0,0 +1,292 @@
<template>
<div class="store_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'Store Name'"><a-input v-model:value="name" size="large" placeholder="Please input Store Name or Id" @keydown.enter="searchList"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList">Reset</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="addStore()">+Add Store</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editStore(record)">Edit</div>
<div class="operate_item" @click="deleteStore(record,index)">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<a-modal class="edit_modal_component"
:destroyOnClose="true"
v-model:visible="editStoreModal"
:footer="null"
:title="editStoreTitle"
width="560px"
:maskClosable="false"
:centered="true"
@cancel="closeStore"
>
<a-form ref="formRef" :model="formState" :rules="rules" :layout="'vertical'" >
<a-form-item label="Store Name" name="name">
<a-input v-model:value="formState.name" size="large" placeholder="Please input store name"/>
</a-form-item>
<a-form-item label="Store Adress" name="address">
<a-input v-model:value="formState.address" size="large" placeholder="Please select"/>
</a-form-item>
<a-form-item label="Remarks" name="remarks">
<a-input v-model:value="formState.remarks" size="large" placeholder="Please input remarks"/>
</a-form-item>
</a-form>
<div class="modal_button_list">
<a-button class="default_button btn-margin-r-20" size="large" @click="closeStore">Cancel</a-button>
<a-button class="primary_button" type="primary" size="large" @click="confirmSubmit">Submit</a-button>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef, onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { message,Modal } from "ant-design-vue";
import { formatTime } from "@/tool/util"
import { Https } from "@/tool/https";
import { useRoute } from 'vue-router'
import { WarningOutlined } from '@ant-design/icons-vue';
export default defineComponent({
name:'storeManage',
components:{filterComponent},
setup(){
const route = useRoute()
let filter = reactive({
name:''
})
let columns = reactive([
{ title: 'Store Id', align:'center', ellipsis: true, dataIndex: 'id', key: 'id' },
{ title: 'Store Name', align:'center', ellipsis: true, dataIndex: 'name', key: 'name',
},
{ title: 'Store Adress', align:'center', ellipsis: true, dataIndex: 'address', key: 'address' },
{ title: 'Remarks', align:'center', ellipsis: true, dataIndex: 'remarks', key: 'remarks' },
{ title: 'Add Time', align:'center', ellipsis: true, dataIndex: 'createDate', key: 'createDate',customRender:(record:any)=>{
let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return time },
},
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 150,
dataIndex:'operation',
},
])
let tableLoading = ref(false)
let collectionList = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(0)
let editStoreModal = ref(false)
let editStoreTitle = ref('Add Store')
let formRef = ref()
let formState = ref({
id: '',
name: '',
address:'',
remarks:'',
});
let rules = {
name: [
{ required: true, message: 'Please input store name', trigger: 'blur' },
],
address: [
{ required: true, message: 'Please input store address', trigger: 'blur' },
],
}
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getStoreList()
}
let closeStore = () =>{
formState.value = {
id: '',
name: '',
address:'',
remarks:'',
}
editStoreModal.value = false
}
let addStore = () =>{
editStoreTitle.value = 'Add Store'
editStoreModal.value = true
}
let editStore = (data:any,) =>{
editStoreModal.value = true
editStoreTitle.value = 'Eidt Store'
formState.value = {
id: data.id,
name: data.name,
address:data.address,
remarks:data.remarks,
}
}
let getStoreList = () =>{
let data = {
name : filter.name,
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.queryStorePage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content
total.value = rv.total
}
}
);
}
let searchList = () =>{
currentPage.value = 1
getStoreList()
}
let resetList = () =>{
currentPage.value = 1
filter.name = ''
getStoreList()
}
let confirmSubmit = () =>{
let data = {
...formState.value,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
formRef.value.validate().then(()=>{
submit()
})
let submit = () =>{
Https.axiosPost(Https.httpUrls.sotreSaveOrEdit, data).then(
(rv: any) => {
if (rv) {
let tip = !formState.value.id ? 'Store added successfully' :'Edit store successfully'
message.success(tip)
resetList()
closeStore()
}
}
);
}
}
let deleteStore = (data:any,index:any) => {
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.storeDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: 'Are you sure to delete the store?',
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Yes',
cancelText: 'No',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
onMounted(() => {
if(route.query && route.query.type === 'add'){
addStore()
}
getStoreList()
})
return {
...toRefs(filter),
columns,
collectionList,
currentPage,
tableLoading,
pageSize,
total,
editStoreModal,
editStoreTitle,
formRef,
formState,
rules,
changePage,
closeStore,
addStore,
editStore,
searchList,
resetList,
confirmSubmit,
deleteStore
}
},
});
</script>
<style lang="less" scoped>
.store_manage_page{
padding-left: 28px;
.operate_list{
display: flex;
justify-content: space-between;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,469 @@
<template>
<div class="role_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'Role Name or Id'"><a-input v-model:value="name" size="large" placeholder="Please input Role Name or Id" @keydown.enter="searchList()"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList()">Reset</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="addRole()">+Add Role</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editRole(record)">Edit</div>
<div class="operate_item" @click="deleteRole(record,index)">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<a-modal class="edit_modal_component"
v-model:visible="editRoleModal"
:footer="null"
:title="editRoleTitle"
width="680px"
:maskClosable="false"
:centered="true"
@cancel="closeRole"
>
<a-form ref="formRef" :model="formState" :rules="rules" :layout="'vertical'" >
<a-form-item label="Role Name" name="name">
<a-input v-model:value="formState.name" size="large" placeholder="Please input role name"/>
</a-form-item>
<div>
<div class="form_item_title required">Role Permission</div>
<a-checkbox class="form_check_all" size="large" v-model:checked="permissionCheckAll" @change="perCheckAll">All</a-checkbox>
<table class="permission_table">
<tr v-for="(role) in rolePermission" :key="role.code">
<td class="first_td">
<div class="table_td_block"><a-checkbox size="large" v-model:checked="role.select" @change="checkLevelFirst(role)">{{role.resource}}</a-checkbox></div>
</td>
<td class="second_td">
<div class="table_td_block" v-for="(menu) in role.level2ResourceList" :key="menu.code"><a-checkbox size="large" v-model:checked="menu.select" @change="checkLevelSec(role,menu)">{{menu.resource}}</a-checkbox></div>
</td>
<td class="third_td">
<div class="table_td_block" v-for="(menu) in role.level2ResourceList" :key="menu.code">
<div class="table_td_permission">
<div v-for="(per) in menu.operationList" :key="per.code"><a-checkbox :disabled="!menu.select" size="large" v-model:checked="per.select">{{per.resource}}</a-checkbox></div>
</div>
</div>
</td>
</tr>
</table>
</div>
</a-form>
<div class="modal_button_list">
<a-button class="default_button btn-margin-r-20" size="large" @click="closeRole()">Cancel</a-button>
<a-button class="primary_button" type="primary" size="large" @click="confirmSubmit()">Submit</a-button>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { message,Modal } from "ant-design-vue";
import { Https } from "@/tool/https";
import { WarningOutlined } from '@ant-design/icons-vue';
export default defineComponent({
name:'roleManage',
components:{filterComponent},
setup(){
let filter = reactive({
name:'',
})
let tableLoading = ref(false)
let columns = reactive([
{ title: 'Role Name', align:'center', ellipsis: true, dataIndex: 'name', key: 'name', width:250 },
{ title: 'Role Permission', align:'center', ellipsis: true, dataIndex: 'permission', key: 'permission'},
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 250,
dataIndex:'operation',
},
])
let collectionList = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let editRoleModal = ref(false)
let editRoleTitle = ref('Add Role')
let permissionCheckAll=ref(false)
let rolePermission:any = ref([])
let backupRolePermission:any = ref([])
let formRef = ref();
let formState = ref({
id: '',
name: '',
});
let rules = {
name: [
{ required: true, message: 'Please input role name', trigger: 'blur' },
],
roleType: [
{ required: true, message: '', trigger: 'blur' },
],
}
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getRoleList()
}
let closeRole = () =>{
formState.value = {
id: '',
name: '',
}
permissionCheckAll.value = false
rolePermission.value = JSON.parse(JSON.stringify(backupRolePermission.value))
editRoleModal.value = false
}
let addRole = () =>{
editRoleTitle.value = 'Add Role'
editRoleModal.value = true
}
let editRole = (data:any,) =>{
editRoleModal.value = true
editRoleTitle.value = 'Eidt Role'
formState.value = {
id: data.id,
name: data.name,
}
rolePermission.value = changeSelectBoolean(data.rolePermission.level1ResourceList)
permissionCheckAll.value = data.rolePermission.allSelect
}
let getRoleList = () =>{
let data = {
name : filter.name,
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.roleQueryRolePage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content.map((v:any) =>{
let data = {
...v,
permission:v.rolePermission.level1ResourceList.filter((v:any)=>v.select).map((per:any) => per.resource).join('、')
}
return data
})
total.value = rv.total
}
}
);
}
let getMenuListPer = () =>{
Https.axiosGet(Https.httpUrls.roleQueryPermissionList).then(
(rv: any) => {
if (rv) {
rolePermission.value = changeSelectBoolean(rv)
backupRolePermission.value = changeSelectBoolean(rv)
console.log(rolePermission.value);
}
}
);
}
let changeSelectBoolean = (data:any) =>{
let newData = JSON.parse(JSON.stringify(data))
for(let first of newData){
first.select = changeBooleanNumber(first.select)
for(let sec of first.level2ResourceList){
sec.select = changeBooleanNumber(sec.select)
for(let third of sec.operationList){
third.select = changeBooleanNumber(third.select)
}
}
}
return newData
}
//判断是布尔值则转为数字,数字则转布尔值
let changeBooleanNumber = (data:any) => {
let newData = data
if(newData.constructor === Boolean){
newData = newData ? 1 :0
}else{
newData = newData ? true :false
}
return newData
}
let searchList = () =>{
currentPage.value = 1
getRoleList()
}
let resetList = () =>{
currentPage.value = 1
filter.name = ''
getRoleList()
}
let deleteRole = (data:any,index:any) =>{
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.roleDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: "Are you sure delete the role?",
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
let perCheckAll = () =>{
for(let first of rolePermission.value){
first.select = permissionCheckAll.value
for(let sec of first.level2ResourceList){
sec.select = permissionCheckAll.value
for(let third of sec.operationList){
third.select = permissionCheckAll.value
}
}
}
}
let checkLevelFirst = (firstDdata:any) =>{
for(let sec of firstDdata.level2ResourceList){
sec.select = firstDdata.select
for(let third of sec.operationList){
third.select = firstDdata.select
}
}
checkIsAllPer()
}
let checkLevelSec = (firstData:any, secondData:any) =>{
for(let third of secondData.operationList){
third.select = secondData.select
}
let status = false
for(let item of firstData.level2ResourceList){
if(item.select){
status = true
break
}
}
firstData.select = status
checkIsAllPer()
}
//判断是否已经全部勾选
let checkIsAllPer = () =>{
let status = true
for(let first of rolePermission.value){
if(!first.select){
status = false
break
}
for(let sec of first.level2ResourceList){
if(!sec.select){
status = false
break
}
}
if(!status){break}
}
permissionCheckAll.value = status
}
let confirmSubmit = () =>{
let data = {
...formState.value,
rolePermission:{
allSelect:permissionCheckAll.value ? 1 : 0,
level1ResourceList:changeSelectBoolean(rolePermission.value)
},
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
formRef.value.validate().then(()=>{
let status = false
for(let first of rolePermission.value){
if(first.select){
status = true
break
}
for(let sec of first.level2ResourceList){
if(sec.select){
status = true
break
}
}
if(status){break}
}
if(!status){
message.error('Please check role permission')
return
}
submit()
})
let submit = () => {
Https.axiosPost(Https.httpUrls.roleSaveOrEdit, data).then(
(rv: any) => {
if (rv) {
let tip = !formState.value.id ? 'Role added successfully' :'Edit role successfully'
message.success(tip)
resetList()
closeRole()
}
}
);
}
}
onMounted(() => {
getRoleList()
getMenuListPer()
})
return {
...toRefs(filter),
tableLoading,
columns,
collectionList,
currentPage,
pageSize,
total,
permissionCheckAll,
rolePermission,
editRoleModal,
editRoleTitle,
formRef,
formState,
rules,
changePage,
closeRole,
addRole,
editRole,
searchList,
resetList,
deleteRole,
perCheckAll,
checkLevelFirst,
checkLevelSec,
confirmSubmit,
}
},
});
</script>
<style lang="less" scoped>
.role_manage_page{
padding-left: 28px;
.role_pic{
width: 50px;
}
.operate_list{
display: flex;
justify-content: space-between;
padding: 0 50px;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
}
}
}
.form_check_all{
margin: 10px 0;
}
.permission_table{
width: 100%;
margin-top: 10px;
border-left:1px solid #DFDFDF;
border-top:1px solid #DFDFDF;
td{
border-bottom: 1px solid #DFDFDF;
border-right: 1px solid #DFDFDF;
.table_td_block{
padding: 16px 0 16px 20px;
border-bottom: 1px solid #DFDFDF;
&:last-child{
border-bottom: none;
}
}
.table_td_permission{
display: flex;
min-height: 23px;
}
}
.first_td{
width: 120px;
}
.second_td{
width: 150px;
}
}
</style>

View File

@@ -0,0 +1,513 @@
<template>
<div class="user_manage_page list_page">
<div class="list_page_content">
<div class="list_top_content">
<div class="list_top_search_content">
<div class="search_content_left">
<filterComponent :title="'User Name'"><a-input v-model:value="userName" size="large" placeholder="Please input User Name" @keydown.enter="searchList()"/></filterComponent>
<filterComponent :title="'User Phone'"><a-input v-model:value="userPhone" size="large" placeholder="Please input User Phone" @keydown.enter="searchList()" /></filterComponent>
<filterComponent :title="'User Role'">
<a-select v-model:value="roleId" size="large" style="width:280px" placeholder="Please select" :options="userRoleList" allowClear></a-select>
</filterComponent>
<filterComponent :title="'User State'">
<a-select v-model:value="state" size="large" style="width:280px" placeholder="Please select" :options="userStateList" allowClear></a-select>
</filterComponent>
<filterComponent :title="'Add Time'"><a-range-picker v-model:value="addTime" size="large" :placeholder="['Start Time', 'End Time']" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD"/></filterComponent>
</div>
</div>
<div class="list_top_button_content">
<a-button class="primary_button btn-margin-r-20" type="primary" size="large" @click="searchList()">Seach</a-button>
<a-button class="default_button" size="large" @click="resetList()">Reset</a-button>
<a-button class="primary_button btn-margin-t-35" type="primary" size="large" @click="addUser()">+Add User</a-button>
</div>
</div>
<div class="list_table_content">
<a-table :columns="columns" :data-source="collectionList" @change="changePage" :loading="tableLoading"
:pagination="{
showSizeChanger:true,
current: currentPage,
pageSize:pageSize,
total: total,
showQuickJumper:true,
bordered:false,
pageSizeOptions:['10','20','50'],
}">
<template v-slot:bodyCell="{column,record, index}" >
<template v-if="column.dataIndex === 'stateName'">
<div :class="['state_name_block', record.state == 1 ? 'enable_state' :'disable_state']">
<div class="state_round"></div>
<div>{{record.stateName}}</div>
</div>
</template>
<template v-if="column.dataIndex === 'operation'">
<div class="operate_list">
<div class="operate_item" @click="editUser(record)">Edit</div>
<div :class="['operate_item', record.state == 0 ? '' :'operate_disable_state']" @click="enableUser(record,index)">
<div v-if="record.state == 0">Enable</div>
<div v-else>Disable</div>
</div>
<div class="operate_item" @click="deleteUser(record,index)">Delete</div>
</div>
</template>
</template>
</a-table>
</div>
</div>
<a-modal class="edit_modal_component"
:destroyOnClose="true"
v-model:visible="editUserModal"
:footer="null"
:title="editUserTitle"
width="680px"
:maskClosable="false"
:centered="true"
@cancel="closeUser"
>
<a-form ref="formRef" :model="formState" :rules="rules" :layout="'vertical'" >
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="User Name" name="userName">
<a-input v-model:value="formState.userName" size="large" placeholder="Please input user name"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Account" name="userAccount">
<a-input v-model:value="formState.userAccount" size="large" placeholder="Please input user account"/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="User Code" name="userPassword">
<a-input v-model:value="formState.userPassword" size="large" placeholder="Please input user code" type="password"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Phone" name="userPhone">
<a-input v-model:value="formState.userPhone" size="large" placeholder="Please input user phone"/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="12">
<a-form-item label="App User" name="appUser">
<a-select v-model:value="formState.appUser" size="large" :options="appUserList" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="User Role" name="roleId">
<a-select v-model:value="formState.roleId" size="large" :options="userRoleList" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="24">
<a-form-item label="Owner Store" name="storeIds">
<a-select v-model:value="formState.storeIds" size="large" :options="ownerStoreList" mode="multiple" placeholder="Please select"></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="[16,16]">
<a-col :span="24">
<a-form-item label ="Remarks" name="remarks">
<a-input v-model:value="formState.remarks" size="large" placeholder="Please input remarks"/>
</a-form-item>
</a-col>
</a-row>
</a-form>
<div class="modal_button_list">
<a-button class="default_button btn-margin-r-20" size="large" @click="closeUser">Cancel</a-button>
<a-button class="primary_button" type="primary" size="large" @click="confirmSubmit">Submit</a-button>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,UnwrapRef,onMounted,createVNode } from "vue";
import filterComponent from '@/component/filterComponent.vue'
import { Moment } from 'moment';
import { message,Modal } from "ant-design-vue";
import { Https } from "@/tool/https";
import { WarningOutlined } from '@ant-design/icons-vue';
import { encode, decode } from 'js-base64';
import { useRoute } from 'vue-router'
import { formatTime, startTime, endTime } from "@/tool/util"
export default defineComponent({
name:'userManage',
components:{filterComponent},
setup(){
const route = useRoute()
let filter:any = reactive({
userName:'',
userPhone:'',
roleId:[],
state:[],
addTime:ref<Moment[]>([]),
})
let tableLoading = ref(false)
let userRoleList:any = ref([])
let userStateList:any = ref([
{value:'1',label:'Activated'},
{value:'0',label:'Deactivated'},
])
let appUserList:any = ref([
{value:1,label:'Yes'},
{value:0,label:'No'},
])
let ownerStoreList:any = ref([])
let columns = reactive([
{ title: 'User Name', align:'center', ellipsis: true, dataIndex: 'userName', key: 'userName' },
{ title: 'User Account', align:'center', ellipsis: true, dataIndex: 'userAccount', key: 'userAccount'},
{ title: 'Add Role', align:'center', ellipsis: true, dataIndex: 'roleName', key: 'roleName' },
{ title: 'User Phone', align:'center', ellipsis: true, dataIndex: 'userPhone', key: 'userPhone' },
{ title: 'Owned Store', align:'center', ellipsis: true, dataIndex: 'storeName', key: 'storeName',customRender:(record:any)=>{
let storeNameNew = record.text.join(',')
return storeNameNew
}
},
{ title: 'Add Time', align:'center', ellipsis: true, dataIndex: 'createDate', key: 'createDate' ,customRender:(record:any)=>{
let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return time
},
},
{ title: 'Activated', align:'center', ellipsis: true, dataIndex: 'appUserName', key: 'appUserName' },
{ title: 'User State', align:'center', ellipsis: true, dataIndex: 'stateName', key: 'stateName' },
{
title: 'Operations',
key: 'operation',
align:'center',
fixed: 'right',
width: 150,
dataIndex:'operation',
},
])
let collectionList:any = ref([])
let currentPage = ref(1)
let pageSize = ref(10)
let total = ref(1)
let editUserModal = ref(false)
let editUserTitle = ref('Add user')
let formRef = ref();
let formState:any = ref({
id: '',
userName: '',
userAccount: '',
userPassword:'',
userPhone:'',
appUser:null,
roleId:null,
storeIds:[],
remarks:'',
});
let rules = {
userName: [
{ required: true, message: 'Please input user name', trigger: 'blur' },
],
userAccount: [
{ required: true, message: 'Please input user account', trigger: 'blur' },
{ min: 6, max: 20, message: 'Length should be 6 to 20', trigger: 'blur' },
],
userPassword: [
{ required: true, message: 'Please input user code', trigger: 'blur' },
{ min: 6, max: 20, message: 'Length should be 6 to 20', trigger: 'blur' },
],
userPhone: [
{ required: true, message: 'Please input user phone', trigger: 'blur' },
{ pattern: /^\d*$/, message: 'The format of the mobile phone number is incorrect', trigger: 'blur' },
],
appUser: [
{ required: true, message: 'Please select app user', trigger: 'blur' },
],
userRole: [
{ required: true, message: 'Please select user role', trigger: 'blur' },
],
ownerStore: [
{ required: true, message: 'Please select owner store', trigger: 'blur' },
],
}
let changePage = (e:any) =>{
currentPage.value = e.current
pageSize.value = e.pageSize
getUserlist()
}
let closeUser = () =>{
formState.value = {
id: '',
userName: '',
userAccount: '',
userPassword:'',
userPhone:'',
appUser:null,
roleId:null,
storeIds:[],
remarks:'',
}
editUserModal.value = false
}
let addUser = () =>{
editUserTitle.value = 'Add user'
editUserModal.value = true
}
let editUser = (data:any,) =>{
editUserModal.value = true
editUserTitle.value = 'Eidt user'
formState.value = {
id: data.id,
userName: data.userName,
userAccount:data.userAccount,
userPassword:data.userPassword ? decode(data.userPassword) : '',
userPhone:data.userPhone,
appUser:data.appUser,
roleId:String(data.roleId),
storeIds:data.storeIds,
remarks:data.remarks,
}
}
let getUserlist = () =>{
let data = {
userName : filter.userName,
userPhone:filter.userPhone,
state:filter.state && filter.state.length ? filter.state : '',
roleId:filter.roleId && filter.roleId.length ? filter.roleId : '',
createDateStart:filter.addTime && filter.addTime.length ? startTime(filter.addTime[0]) :'',
createDateEnd:filter.addTime && filter.addTime.length ? endTime(filter.addTime[1]) :'',
page:currentPage.value,
size:pageSize.value
}
tableLoading.value = true
Https.axiosPost(Https.httpUrls.accountQueryUserPage, data).then(
(rv: any) => {
if (rv) {
tableLoading.value = false
collectionList.value = rv.content
total.value = rv.total
}
}
);
}
let getRolelist = () =>{
Https.axiosPost(Https.httpUrls.roleQueryAll, {}).then(
(rv: any) => {
if (rv) {
userRoleList.value = rv.map((v:any)=>{
let data = {
...v,
value:v.id,
label:v.name
}
return data
})
}
}
);
}
let searchList = () =>{
currentPage.value = 1
getUserlist()
}
let resetList = () =>{
currentPage.value = 1
filter.userName = ''
filter.userPhone = ''
filter.roleId = []
filter.state = []
filter.addTime = ref<Moment[]>([])
getUserlist()
}
let confirmSubmit = () =>{
let data = {
...formState.value,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
data.userPassword = encode(data.userPassword)
let submit = () =>{
Https.axiosPost(Https.httpUrls.accountSaveOrEdit, data).then(
(rv: any) => {
if (rv) {
let tip = !formState.value.id ? 'User added successfully' :'Edit user successfully'
message.success(tip)
resetList()
closeUser()
}
}
);
}
formRef.value.validate().then(()=>{
submit()
})
}
let enableUser = (record:any,index:any) =>{
let data ={
id:record.id,
enable:record.state == 1 ? 0 : 1
}
Https.axiosPost(Https.httpUrls.accountEnable, data).then(
(rv: any) => {
if (rv) {
let tip = record.state == 0? 'Enable successfully' :'Disable successfully'
message.success(tip)
collectionList.value[index].state = data.enable
collectionList.value[index].stateName = data.enable == 1 ? 'Activated' :'Deactivated'
}
}
);
}
let deleteUser = (data:any,index:any) =>{
let confirmDelete = (data:any,index:any) =>{
let newData = {
id:data.id
}
Https.axiosPost(Https.httpUrls.accountDelete, newData).then(
(rv: any) => {
if (rv) {
message.success('Delete success')
collectionList.value.splice(index,1)
}
}
);
}
Modal.confirm({
title: "Are you sure delete the user?",
icon: createVNode(WarningOutlined),
class:'confirm_style',
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
confirmDelete(data,index)
}
});
}
let storeQueryAll = () =>{
Https.axiosPost(Https.httpUrls.storeQueryAll,{}).then(
(rv: any) => {
if (rv) {
ownerStoreList.value = rv.map((v:any)=>{
let data = {
...v,
value:v.id,
label:v.name
}
return data
})
}
}
);
}
onMounted(() => {
if(route.query && route.query.type === 'add'){
addUser()
}
getUserlist()
storeQueryAll()
getRolelist()
})
return {
...toRefs(filter),
tableLoading,
userRoleList,
userStateList,
appUserList,
ownerStoreList,
columns,
collectionList,
currentPage,
pageSize,
total,
editUserModal,
editUserTitle,
formRef,
formState,
rules,
changePage,
closeUser,
addUser,
editUser,
searchList,
resetList,
confirmSubmit,
enableUser,
deleteUser
}
},
});
</script>
<style lang="less" scoped>
.user_manage_page{
padding-left: 28px;
.user_pic{
width: 50px;
}
.state_name_block{
display: flex;
align-items: center;
font-size: 14px;
justify-content: center;
&.enable_state{
color: #47E417;
.state_round{
background: #47E417;
}
}
&.disable_state{
color: #E41335;
.state_round{
background: #E41335;
}
}
.state_round{
width: 14px;
height: 14px;
border-radius: 50%;
margin-right: 5px;
}
}
.operate_list{
display: flex;
justify-content: space-between;
.operate_item{
font-size: 14px;
font-family: Roboto;
font-weight: 400;
color: #343579;
cursor: pointer;
&.operate_disable_state{
color: #E41335;
}
}
}
}
</style>

View File

@@ -0,0 +1,265 @@
<template>
<div class="worktable_page">
<div class="worktable_top_info">
<img class="worktable_logo" src="@/assets/images/worktable_logo.png">
<div class="worktable_top_left">
<div class="top_left_header">{{nowHours > 12 ? 'Afternoon':'Morning'}},{{userName}}.Have a nice day!</div>
<div class="work_user_info"><span class="user_info_margin">{{roleName}}</span><span class="user_info_margin">|</span><span>{{storeAddress}}{{storeName}}</span></div>
</div>
<div class="work_statistical_data_list">
<div class="work_statistical_data_item">
<div class="work_statistical_data_title">Store(s)</div>
<div class="work_statistical_data_num color_FF6D60">{{storeCount}}</div>
</div>
<div class="work_statistical_data_item">
<div class="work_statistical_data_title">Product(s)</div>
<div class="work_statistical_data_num color_0CB4B3">{{onSaleProductCount}}</div>
</div>
<div class="work_statistical_data_item">
<div class="work_statistical_data_title">Order(s)</div>
<div class="work_statistical_data_num color_FEAD75">{{orderSuccessCount}}</div>
</div>
</div>
</div>
<div class="worktable_content">
<div class="worktable_content_header">
<span class="icon iconfont icon-a-gengduocaidangongneng"></span>
<div>Quick access</div>
</div>
<div class="worktable_content_entry_list">
<div class="worktable_content_entry_item" @click="turnToPage({path:'/home/productmanage',type:''})" v-if="buttonShow.PRODUCT_LIST">
<img class="entry_bg" src="@/assets/images/green_bg.png">
<div class="entry_name">Product List</div>
</div>
<div class="worktable_content_entry_item" @click="turnToPage({path:'/home/productmanage',type:'add'})" v-if="buttonShow.PRODUCT_LIST">
<img class="entry_bg" src="@/assets/images/purple_bg.png">
<div class="entry_name">Add Product</div>
</div>
<div class="worktable_content_entry_item" @click="turnToPage({path:'/home/storemanage',type:''})" v-if="buttonShow.STORE_LIST">
<img class="entry_bg" src="@/assets/images/pink_bg.png">
<div class="entry_name">Store List</div>
</div>
<div class="worktable_content_entry_item" @click="turnToPage({path:'/home/storemanage',type:'add'})" v-if="buttonShow.STORE_LIST">
<img class="entry_bg" src="@/assets/images/orange_bg.png">
<div class="entry_name">Add Store</div>
</div>
<div class="worktable_content_entry_item" @click="turnToPage({path:'/home/usermanage',type:'add'})" v-if="buttonShow.USER_MANAGER">
<img class="entry_bg" src="@/assets/images/blue_bg.png">
<div class="entry_name">Add User</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,reactive,ref,toRefs,onMounted } from "vue";
import { message } from "ant-design-vue";
import { useRouter,useRoute } from 'vue-router'
import { Https } from "@/tool/https";
export default defineComponent({
name:'worktable',
setup(){
const router = useRouter()
const workData = reactive({
userName:'',
roleName:'',
storeAddress:'',
storeName:'',
storeCount:0,
onSaleProductCount:0,
orderSuccessCount:0,
})
let userInfo:any = ref({})
let buttonShow:any = reactive({
PRODUCT_LIST:false,
STORE_LIST:false,
USER_MANAGER:false,
})
let nowHours = ref(0)
const turnToPage = (data:any) =>{
router.push({path:data.path,query:data.type?{type:data.type}:{}})
}
const getWorkData = () =>{
Https.axiosGet(Https.httpUrls.countWorkBench).then(
(rv: any) => {
if (rv) {
workData.userName = rv.userName
workData.roleName = rv.roleName
workData.storeAddress = rv.storeAddress
workData.storeName = rv.storeName
workData.storeCount = rv.storeCount
workData.onSaleProductCount = rv.onSaleProductCount
workData.orderSuccessCount = rv.orderSuccessCount
}
}
);
}
const getButtonRole = (menuList:any) =>{
let keyList = ['PRODUCT_LIST',"STORE_LIST","USER_MANAGER"]
for(let item of menuList){
if(!item.children){
if(keyList.includes(item.code)){
buttonShow[item.code] = item.isShow
}
}else{
getButtonRole(item.children)
}
}
}
onMounted(() => {
let menuList:any = sessionStorage.getItem('menuList')
menuList = JSON.parse(menuList)
let date = new Date()
nowHours.value = date.getHours()
getButtonRole(menuList)
getWorkData()
})
return {
turnToPage,
...toRefs(workData),
userInfo,
buttonShow,
nowHours,
}
},
});
</script>
<style lang="less" scoped>
.worktable_page{
padding-left: 28px;
.worktable_top_info{
background: #fff;
height: 120px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 117px;
position: relative;
margin-bottom: 30px;
.worktable_logo{
width: 100px;
height: 96px;
position: absolute;
left: 0;
bottom: 0;
}
.top_left_header{
font-size: 16px;
font-weight: normal;
color: #333333;
margin-bottom: 10px;
}
.work_user_info{
font-size: 16px;
color: #A0A1A6;
.user_info_margin{
margin-right: 10px;
}
}
.work_statistical_data_list{
display: flex;
align-items: center;
.work_statistical_data_item{
padding: 8px 40px 0;
height: 60px;
border-right:1px solid #E7E7E7;
:last-child{
border: none;
}
.work_statistical_data_title{
font-size: 16px;
line-height: 16px;
color: #333333;
margin-bottom: 12px;
}
.work_statistical_data_num{
font-size: 24px;
line-height: 24px;
text-align: center;
}
.color_FF6D60{
color: #FF6D60;
}
.color_0CB4B3{
color: #0CB4B3;
}
.color_FEAD75{
color: #FEAD75;
}
}
}
}
.worktable_content{
padding: 20px 25px 30px;
background: #fff;
.worktable_content_header{
display: flex;
align-items: center;
font-size: 16px;
color: #333333;
margin-bottom: 40px;
.icon-a-gengduocaidangongneng{
font-size: 24px;
color: #80B8F8;
margin-right: 14px;
}
}
.worktable_content_entry_list{
display: flex;
.worktable_content_entry_item{
position: relative;
width: 200px;
height: 114px;
padding-left: 20px;
display: flex;
align-items: center;
cursor: pointer;
margin-right: 20px;
.entry_bg{
position: absolute;
left: 0;
top: 0;
}
.entry_name{
color: #fff;
z-index: 2;
font-size: 19px;
}
}
}
}
}
</style>