From 9ff9962d8d2d4cb1cd5d6abcb902e916c44cda03 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 08 五月 2025 14:28:29 +0800
Subject: [PATCH] 客户档案页面开发
---
src/assets/styles/ruoyi.scss | 3
src/views/tool/build/index.vue | 2
src/api/system/user.js | 7
src/views/basicData/customerFile/index.vue | 282 +++++++++++++++++++++++++++++++++-
src/views/login.vue | 2
src/main.js | 1
src/api/basicData/customerFile.js | 51 ++++++
src/assets/styles/element-ui.scss | 50 ++++++
src/components/PIMTable/PIMTable.vue | 66 +------
src/components/PIMTable/Pagination.vue | 4
src/store/modules/settings.js | 2
11 files changed, 401 insertions(+), 69 deletions(-)
diff --git a/src/api/basicData/customerFile.js b/src/api/basicData/customerFile.js
new file mode 100644
index 0000000..4386a80
--- /dev/null
+++ b/src/api/basicData/customerFile.js
@@ -0,0 +1,51 @@
+// 瀹㈡埛妗f椤甸潰鎺ュ彛
+import request from '@/utils/request'
+
+// 鍒嗛〉鏌ヨ
+export function listCustomer(query) {
+ return request({
+ url: '/basic/customer/list',
+ method: 'get',
+ params: query
+ })
+}
+// 鏌ヨ瀹㈡埛妗f璇︾粏
+export function getCustomer(id) {
+ return request({
+ url: '/basic/customer/' + id,
+ method: 'get'
+ })
+}
+// 鏂板瀹㈡埛妗f
+export function addCustomer(data) {
+ return request({
+ url: '/basic/customer/addCustomer',
+ method: 'post',
+ data: data
+ })
+}
+// 淇敼瀹㈡埛妗f
+export function updateCustomer(data) {
+ return request({
+ url: '/basic/customer/updateCustomer',
+ method: 'post',
+ data: data
+ })
+}
+// 瀵煎嚭瀹㈡埛妗f
+export function exportCustomer(query) {
+ return request({
+ url: '/basic/customer/export',
+ method: 'get',
+ params: query,
+ responseType: 'blob'
+ })
+}
+// 鍒犻櫎瀹㈡埛妗f
+export function delCustomer(id) {
+ return request({
+ url: '/basic/customer/' + id,
+ method: 'delete'
+ })
+}
+
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 2da13d4..3a45768 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -134,3 +134,10 @@
method: 'get'
})
}
+// 鏌ヨ鐢ㄦ埛鍒楄〃
+export function userListNoPage() {
+ return request({
+ url: '/system/user/userListNoPage',
+ method: 'get'
+ })
+}
diff --git a/src/assets/styles/element-ui.scss b/src/assets/styles/element-ui.scss
index bb5414d..82712af 100644
--- a/src/assets/styles/element-ui.scss
+++ b/src/assets/styles/element-ui.scss
@@ -52,6 +52,56 @@
left: 0;
position: relative;
margin: 0 auto;
+ border-radius: 8px;
+ padding: 0 !important;
+}
+.el-dialog__header {
+ background: #F5F6F7;
+ padding: 12px 16px;
+ border-radius: 8px 8px 0 0;
+}
+.el-dialog__title {
+ font-weight: 400;
+ font-size: 16px;
+ color: #2E3033;
+}
+.el-dialog__body {
+ padding: 16px 40px 0 40px;
+}
+.el-dialog__footer {
+ text-align: center;
+ padding: 16px;
+}
+.el-message-box {
+ padding: 0 !important;
+ border-radius: 8px;
+}
+.el-message-box__header {
+ background: #F5F6F7;
+ padding: 12px 16px;
+ border-radius: 8px 8px 0 0;
+}
+.el-message-box__title {
+ font-weight: 400;
+ font-size: 16px;
+ color: #2E3033;
+}
+.el-message-box__content {
+ padding: 16px 40px 0 40px;
+}
+.el-message-box__container {
+ justify-content: center;
+}
+.el-message-box__btns {
+ text-align: center;
+ padding: 16px;
+ display: flex;
+ flex-direction: row-reverse;
+ justify-content: center;
+ align-items: center;
+ .el-button--primary {
+ margin-right: 12px;
+ }
}
// refine element ui upload
diff --git a/src/assets/styles/ruoyi.scss b/src/assets/styles/ruoyi.scss
index 4ef1c78..c1549f5 100644
--- a/src/assets/styles/ruoyi.scss
+++ b/src/assets/styles/ruoyi.scss
@@ -71,7 +71,6 @@
overflow: auto;
overflow-x: hidden;
max-height: 70vh;
- padding: 10px 20px 0;
}
.el-table {
@@ -151,7 +150,7 @@
/** 琛ㄦ牸鏇村鎿嶄綔涓嬫媺鏍峰紡 */
.el-table .el-dropdown-link {
cursor: pointer;
- color: #3472D7;
+ color: #2C51D9;
margin-left: 10px;
}
diff --git a/src/components/PIMTable/PIMTable.vue b/src/components/PIMTable/PIMTable.vue
index 747ef53..c76cf45 100644
--- a/src/components/PIMTable/PIMTable.vue
+++ b/src/components/PIMTable/PIMTable.vue
@@ -1,11 +1,11 @@
<template>
<el-table ref="multipleTable" v-loading="tableLoading" :border="border" :data="tableData"
- :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" :height="height"
+ :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" height="calc(100vh - 18.5em)"
:highlight-current-row="highlightCurrentRow" :row-class-name="rowClassName" :row-style="rowStyle"
- :row-key="rowKey" :span-method="spanMethod" stripe style="width: 100%" tooltip-effect="dark" @row-click="rowClick"
+ :row-key="rowKey" stripe style="width: 100%" tooltip-effect="dark" @row-click="rowClick"
@current-change="currentChange" @selection-change="handleSelectionChange" class="lims-table">
- <el-table-column align="center" type="selection" width="55" v-if="isSelection" />
- <el-table-column align="center" label="搴忓彿" type="index" width="60" :index="indexMethod" />
+ <el-table-column align="center" type="selection" width="55" />
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
<el-table-column v-for="(item, index) in column" :key="index" :column-key="item.columnKey"
:filter-method="item.filterHandler" :filter-multiple="item.filterMultiple" :filtered-value="item.filteredValue"
@@ -51,12 +51,11 @@
</div>
<!-- 鎸夐挳 -->
- <div v-else-if="item.dataType == 'action'"
- :style="`min-width:${getWidth(item.operation, scope.row)}`">
+ <div v-else-if="item.dataType == 'action'">
<template v-for="(o, key) in item.operation" :key="key">
<el-button v-show="o.type != 'upload'" size="small" v-if="o.showHide ? o.showHide(scope.row) : true"
- :disabled="o.disabled ? o.disabled(scope.row) : false" :plain="o.plain"
- :style="{ color: (o.name === '鍒犻櫎' || o.name === 'delete') ? '#f56c6c' : o.color }" :type="typeFn(o.type, scope.row)"
+ :disabled="o.disabled ? o.disabled(scope.row) : false" :plain="o.plain" type="primary"
+ :style="{ color: (o.name === '鍒犻櫎' || o.name === 'delete') ? '#f56c6c' : o.color }" link
@click="o.clickFun(scope.row)" :key="key">
{{ o.name }}
</el-button>
@@ -71,7 +70,7 @@
:on-error="(error, file, fileList) => onError(error, file, fileList, scope.$index)"
:on-success="(response, file, fileList) => handleSuccessUp(response, file, fileList, scope.$index)"
:on-exceed="onExceed" :show-file-list="false">
- <el-button :size="o.size ? o.size : 'small'" type="text"
+ <el-button :size="o.size ? o.size : 'small'" link type="primary"
:disabled="o.disabled ? o.disabled(scope.row) : false">{{ o.name }}</el-button>
</el-upload>
</template>
@@ -89,7 +88,7 @@
</template>
</el-table-column>
</el-table>
- <pagination v-show="page.total > 0" :total="page.total" :layout="page.layout" :page="page.current"
+ <pagination v-show="total > 0" :total="total" :layout="page.layout" :page="page.current"
:limit="page.size" @pagination="paginationSearch" />
</template>
@@ -103,6 +102,8 @@
const uploadHeader = proxy.uploadHeader
const javaApi = proxy.javaApi
+const emit = defineEmits(["pagination"]);
+
// Filters
const typeFn = (val, row) => {
return typeof val === 'function' ? val(row) : val
@@ -114,14 +115,6 @@
// Props锛堜娇鐢� defineProps 鐨勯潪 TS 褰㈠紡锛�
const props = defineProps({
- isSelection: {
- type: Boolean,
- default: false
- },
- height: {
- type: [String, null],
- default: null
- },
tableLoading: {
type: Boolean,
default: false
@@ -178,50 +171,21 @@
size: 10,
layout: 'total, sizes, prev, pager, next, jumper'
})
+ },
+ total: {
+ type: Number,
+ default: 0
}
})
// Data
-const spanList = ref([])
const btnWidth = ref('120px')
const uploadRefs = ref([])
const currentFiles = ref({})
const uploadKeys = ref({})
-// 鍚堝苟鍗曞厓鏍兼柟娉�
-const spanMethod = ({ row, column, rowIndex, columnIndex }) => {
- if (column.find((m) => m.mergeCol)) {
- let i = Number(rowIndex)
- const obj = spanList.value.find((item, index) => {
- i = index
- return item.index == columnIndex
- })
- if (obj) {
- const _row = spanList[i].arr[rowIndex]
- const _col = _row > 0 ? 1 : 0
- return {
- rowspan: _row,
- colspan: _col
- }
- }
- }
-}
-
const indexMethod = (index) => {
return (props.page.current - 1) * props.page.size + index + 1
-}
-
-const getWidth = (row, row0) => {
- let count = 0
- row.forEach((a) => {
- if (a.showHide !== undefined && a.showHide(row0)) {
- count += a.name.length
- } else if (!a.showHide) {
- count += a.name.length
- }
- })
- btnWidth.value = count * 15 + 60 + "px"
- return count * 15 + 60 + "px"
}
// 鐐瑰嚮 link 浜嬩欢
diff --git a/src/components/PIMTable/Pagination.vue b/src/components/PIMTable/Pagination.vue
index 26d4dbc..7639e64 100644
--- a/src/components/PIMTable/Pagination.vue
+++ b/src/components/PIMTable/Pagination.vue
@@ -91,8 +91,8 @@
<style scoped>
.pagination-container {
background: #fff;
- padding: 28px 16px;
- margin-top: 10px;
+ padding: 16px 0;
+ margin-top: 0;
}
.pagination-container.hidden {
display: none;
diff --git a/src/main.js b/src/main.js
index 8112604..93b940f 100644
--- a/src/main.js
+++ b/src/main.js
@@ -90,5 +90,6 @@
// 鏀寔 large銆乨efault銆乻mall
size: Cookies.get('size') || 'default'
})
+app._context.components.ElDialog.props.closeOnClickModal.default = false
app.mount('#app')
diff --git a/src/store/modules/settings.js b/src/store/modules/settings.js
index 2e9c1d1..76a1136 100644
--- a/src/store/modules/settings.js
+++ b/src/store/modules/settings.js
@@ -14,7 +14,7 @@
{
state: () => ({
title: '',
- theme: storageSetting.theme || '#3472D7',
+ theme: storageSetting.theme || '#2C51D9',
sideTheme: storageSetting.sideTheme || sideTheme,
showSettings: showSettings,
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
diff --git a/src/views/basicData/customerFile/index.vue b/src/views/basicData/customerFile/index.vue
index b4d6199..1a2b476 100644
--- a/src/views/basicData/customerFile/index.vue
+++ b/src/views/basicData/customerFile/index.vue
@@ -4,38 +4,298 @@
<div>
<span class="search_title">瀹㈡埛鍚嶇О锛�</span>
<el-input
- v-model="input2"
+ v-model="searchForm.customerName"
style="width: 240px"
placeholder="璇疯緭鍏�"
+ @change="handleQuery"
+ clearable
:prefix-icon="Search"
/>
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
</div>
<div>
- <el-button type="primary">鏂板瀹㈡埛</el-button>
- <el-button>瀵煎嚭</el-button>
- <el-button type="danger" plain>鍒犻櫎</el-button>
+ <el-button type="primary" @click="openForm('add')">鏂板瀹㈡埛</el-button>
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
</div>
</div>
<div class="table_list">
- <PIMTable :column="tableColumn"></PIMTable>
+ <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :handleSelectionChange="handleSelectionChange"
+ :tableLoading="tableLoading" @pagination="pagination" :total="total"></PIMTable>
</div>
+ <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '鏂板瀹㈡埛淇℃伅' : '缂栬緫瀹㈡埛淇℃伅'" width="70%" @close="closeDia">
+ <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerName">
+ <el-input v-model="form.customerName" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="绾崇◣浜鸿瘑鍒彿锛�" prop="taxpayerIdentificationNumber">
+ <el-input v-model="form.taxpayerIdentificationNumber" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鍏徃鍦板潃锛�" prop="companyAddress">
+ <el-input v-model="form.companyAddress" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍏徃鐢佃瘽锛�" prop="companyPhone">
+ <el-input v-model="form.companyPhone" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴浜猴細" prop="contactPerson">
+ <el-input v-model="form.contactPerson" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鑱旂郴鐢佃瘽锛�" prop="contactPhone">
+ <el-input v-model="form.contactPhone" placeholder="璇疯緭鍏�" clearable/>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="缁存姢浜猴細" prop="maintainer">
+ <el-select v-model="form.maintainer" placeholder="璇烽�夋嫨" clearable>
+ <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="缁存姢鏃堕棿锛�" prop="maintenanceTime">
+ <el-date-picker
+ style="width: 100%"
+ v-model="form.maintenanceTime"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="primary" @click="submitForm">纭</el-button>
+ <el-button @click="closeDia">鍙栨秷</el-button>
+ </div>
+ </template>
+ </el-dialog>
</div>
</template>
<script setup>
import { ref } from 'vue'
import {Search} from "@element-plus/icons-vue";
+import {addCustomer, delCustomer, getCustomer, listCustomer, updateCustomer} from "@/api/basicData/customerFile.js";
+import {ElMessageBox } from "element-plus";
+import {userListNoPage} from "@/api/system/user.js";
+const { proxy } = getCurrentInstance()
-const input2 = ref('')
const tableColumn = ref([
{
- label: '鎵瑰噯鍐呭',
- prop: 'ratifyRemark'
- }, {
- label: '鎵瑰噯浜�',
- prop: 'ratifyName',
+ label: '瀹㈡埛鍚嶇О',
+ prop: 'customerName'
+ },
+ {
+ label: '绾崇◣浜鸿瘑鍒爜',
+ prop: 'taxpayerIdentificationNumber'
+ },
+ {
+ label: '鍦板潃鍙婅仈绯绘柟寮�',
+ prop: 'addressPhone'
+ },
+ {
+ label: '鑱旂郴浜�',
+ prop: 'contactPerson'
+ },
+ {
+ label: '鑱旂郴鐢佃瘽',
+ prop: 'contactPhone',
+ },
+ {
+ label: '缁存姢浜�',
+ prop: 'maintainer',
+ },
+ {
+ label: '缁存姢鏃堕棿',
+ prop: 'maintenanceTime',
+ },
+ {
+ dataType: "action",
+ label: "鎿嶄綔",
+ operation: [
+ {
+ name: "缂栬緫",
+ type: "text",
+ clickFun: (row) => {
+ openForm('edit', row);
+ },
+ },
+ ],
},
])
+const tableData = ref([])
+const selectedRows = ref([])
+const userList = ref([])
+const tableLoading = ref(false)
+const page = reactive({
+ current: 1,
+ size: 10,
+})
+const total = ref(0)
+
+// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+const operationType = ref('')
+const dialogFormVisible = ref(false)
+const data = reactive({
+ searchForm: {
+ customerName: '',
+ },
+ form: {
+ customerName: '',
+ taxpayerIdentificationNumber: '',
+ companyAddress: '',
+ companyPhone: '',
+ contactPerson: '',
+ contactPhone: '',
+ maintainer: '',
+ maintenanceTime: '',
+ },
+ rules: {
+ customerName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ taxpayerIdentificationNumber: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ companyAddress: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ companyPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactPerson: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ contactPhone: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
+ maintainer: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ maintenanceTime: [{ required: false, message: "璇烽�夋嫨", trigger: "change" }],
+ }
+})
+const { searchForm, form, rules } = toRefs(data)
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ page.current = 1
+ getList()
+}
+const pagination = ({ current, limit }) => {
+ page.current = current;
+ page.size = limit;
+ getList()
+}
+const getList = () => {
+ tableLoading.value = true
+ listCustomer({...searchForm.value, ...page}).then(res => {
+ tableLoading.value = false
+ tableData.value = res.rows
+ total.value = res.total
+ })
+}
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+ selectedRows.value = selection
+}
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+ operationType.value = type
+ form.value = {}
+ userListNoPage().then(res => {
+ userList.value = res.data
+ })
+ if (type === 'edit') {
+ getCustomer(row.id).then(res => {
+ form.value = {...res.data}
+ })
+ }
+ dialogFormVisible.value = true
+}
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ if (operationType.value === "edit") {
+ submitEdit()
+ } else {
+ submitAdd()
+ }
+ }
+ })
+}
+// 鎻愪氦鏂板
+const submitAdd = () => {
+ addCustomer(form.value).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
+ closeDia()
+ getList()
+ })
+}
+// 鎻愪氦淇敼
+const submitEdit = () => {
+ updateCustomer(form.value).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
+ closeDia()
+ getList()
+ })
+}
+// 鍏抽棴寮规
+const closeDia = () => {
+ proxy.resetForm("formRef")
+ dialogFormVisible.value = false
+}
+// 瀵煎嚭
+const handleOut = () => {
+ ElMessageBox.confirm(
+ '閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�',
+ '瀵煎嚭', {
+ confirmButtonText: '纭',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ }
+ ).then(() => {
+ proxy.download("/basic/customer/export", {}, '瀹㈡埛妗f.xlsx')
+ }).catch(() => {
+ proxy.$modal.msg("宸插彇娑�")
+ })
+}
+// 鍒犻櫎
+const handleDelete = () => {
+ let ids = []
+ if (selectedRows.value.length > 0) {
+ ids = selectedRows.value.map(item => item.id);
+ } else {
+ proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁')
+ return
+ }
+ ElMessageBox.confirm(
+ '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
+ '瀵煎嚭', {
+ confirmButtonText: '纭',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ }
+ ).then(() => {
+ delCustomer(ids).then(res => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
+ })
+ getList()
+ }).catch(() => {
+ proxy.$modal.msg("宸插彇娑�")
+ })
+}
+getList()
</script>
<style scoped lang="scss">
diff --git a/src/views/login.vue b/src/views/login.vue
index 88fb248..29d691b 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -175,7 +175,7 @@
.title {
margin: 20px auto 14px auto;
text-align: center;
- color: #3472D7;
+ color: #2C51D9;
font-size: 28px;
font-weight: 700;
}
diff --git a/src/views/tool/build/index.vue b/src/views/tool/build/index.vue
index e4c319a..0895955 100644
--- a/src/views/tool/build/index.vue
+++ b/src/views/tool/build/index.vue
@@ -307,7 +307,7 @@
</script>
<style lang='scss'>
-$lighterBlue: #3472D7;
+$lighterBlue: #2C51D9;
.container {
position: relative;
--
Gitblit v1.9.3