123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- <template>
- <div class="app-container">
- <!-- 搜索区域 -->
- <el-card class="search-card" shadow="never">
- <el-form :model="queryParams" ref="queryForm" @submit.native.prevent :inline="true" label-width="90px">
- <el-form-item label="派送员" prop="appUserName">
- <el-input
- v-model="queryParams.appUserName"
- placeholder="派送员姓名"
- clearable
- prefix-icon="el-icon-user"
- style="width: 200px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="手机号" prop="phoneNumber">
- <el-input
- v-model="queryParams.phoneNumber"
- placeholder="手机号码"
- clearable
- prefix-icon="el-icon-mobile-phone"
- style="width: 200px"
- maxlength="11"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- </el-card>
- <!-- 操作按钮区域 -->
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- @click="handleAdd"
- v-hasPermi="['app:delivery:add']"
- >新增派送员</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['app:delivery:edit']"
- >编辑</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
- <!-- 派送员列表 -->
- <Page
- uri="/mapi/app/delivery/page"
- :request-params="queryParams"
- ref="pagination"
- >
- <el-table-column label="ID" align="center" prop="id" width="100" />
- <el-table-column label="派送员姓名" align="left" prop="realName" width="130" />
- <el-table-column label="派送员电话" align="left" prop="phoneNumber" width="130" />
- <el-table-column label="绑定门店" align="center" width="120">
- <template slot-scope="scope">
- <el-button type="text" @click="showStoreList(scope.row)">
- <span class="store-count">{{ scope.row.relationStoreNum || 0 }}</span>
- <span class="store-text">家门店</span>
- </el-button>
- </template>
- </el-table-column>
- <el-table-column label="注册时间" align="left" prop="createTime" width="150" />
- <el-table-column label="简介" align="left" min-width="250">
- <template slot-scope="scope">
- <div class="level-desc">
- <div class="description text-gray">{{ scope.row.description || '暂无简介' }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="状态" align="center" width="100">
- <template slot-scope="scope">
- <el-switch
- v-model="scope.row.status"
- active-value="0"
- inactive-value="1"
- @change="handleStatusChange(scope.row)"
- >
- </el-switch>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" width="200" fixed="right">
- <template slot-scope="scope">
- <el-button
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['app:delivery:edit']"
- >编辑</el-button>
- <el-button
- type="text"
- icon="el-icon-tickets"
- @click="recordDetail(scope.row)"
- >接单记录</el-button>
- </template>
- </el-table-column>
- </Page>
- <!-- 添加或修改派送员对话框 -->
- <el-dialog
- :title="title"
- :visible.sync="open"
- width="700px"
- :close-on-click-modal="false"
- :before-close="handleDialogClose"
- append-to-body
- >
- <!-- 选择用户弹窗 -->
- <el-dialog
- width="500px"
- title="选择用户"
- :visible.sync="userSelectVisible"
- append-to-body
- :close-on-click-modal="false"
- >
- <div class="user-search">
- <el-form :inline="true">
- <el-form-item label="手机号">
- <el-input
- v-model="searchPhone"
- placeholder="请输入手机号"
- clearable
- style="width: 200px"
- >
- <el-button slot="append" icon="el-icon-search" @click="searchUser"></el-button>
- </el-input>
- </el-form-item>
- </el-form>
- <div v-if="searchUserInfo" class="user-result">
- <el-card shadow="never" class="user-card">
- <div class="user-info">
- <el-avatar :size="60" icon="el-icon-user"></el-avatar>
- <div class="info-content">
- <div class="name">{{ searchUserInfo.realName }}</div>
- <div class="phone">{{ searchUserInfo.phoneNumber }}</div>
- <div class="tags">
- <el-tag size="small" type="warning">Level {{ searchUserInfo.level }}</el-tag>
- <el-tag size="small" type="info">积分: {{ searchUserInfo.pointBalance }}</el-tag>
- </div>
- </div>
- </div>
- <div class="select-btn">
- <el-button type="primary" size="small" @click="confirmSelectUser">选择此用户</el-button>
- </div>
- </el-card>
- </div>
- <div v-else-if="searchPhone && !searchUserInfo" class="no-result">
- <i class="el-icon-warning-outline"></i>
- <span>未找到该用户</span>
- </div>
- </div>
- </el-dialog>
- <div v-if="!appUserInfo && !form.id" class="select-user-tip">
- <el-empty description="请先选择用户">
- <el-button type="primary" @click="userSelectVisible = true">选择用户</el-button>
- </el-empty>
- </div>
- <template v-else>
- <el-tabs v-model="activeTab">
- <el-tab-pane label="基本信息" name="basic">
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <!-- 用户信息展示区 -->
- <div class="user-info-card">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="用户姓名">
- <span class="primary-text">{{ appUserInfo.realName }}</span>
- </el-descriptions-item>
- <el-descriptions-item label="手机号码">
- {{ appUserInfo.phoneNumber }}
- </el-descriptions-item>
- <el-descriptions-item label="用户等级">
- <el-tag size="small" type="warning">Level {{ appUserInfo.level }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="积分">
- {{ appUserInfo.pointBalance }}
- </el-descriptions-item>
- </el-descriptions>
- </div>
- <el-form-item label="派送员简介" prop="description">
- <el-input
- v-model="description"
- type="textarea"
- :rows="4"
- placeholder="请输入派送员简介信息"
- maxlength="500"
- show-word-limit
- style="width: 100%"
- />
- </el-form-item>
- </el-form>
- </el-tab-pane>
- <el-tab-pane label="绑定门店" name="store">
- <div class="store-transfer">
- <el-transfer
- v-model="orgValue"
- :data="orgData"
- :titles="['可选门店', '已选门店']"
- filterable
- :filter-method="filterStore"
- filter-placeholder="请输入门店名称"
- >
- <template slot="left-footer">
- <div class="transfer-footer">可选门店数: {{ orgData.length - orgValue.length }}</div>
- </template>
- <template slot="right-footer">
- <div class="transfer-footer">已选门店数: {{ orgValue.length }}</div>
- </template>
- </el-transfer>
- </div>
- </el-tab-pane>
- </el-tabs>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" :loading="submitLoading" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 门店列表弹窗 -->
- <data-list
- ref="storeList"
- title="绑定门店列表"
- :columns="storeColumns"
- :fetch-data="fetchStoreList"
- />
- <!-- 接单记录弹窗 -->
- <el-dialog
- title="接单记录"
- :visible.sync="openDetail"
- width="900px"
- :before-close="handleDetailClose" append-to-body
- >
- <div class="record-list" >
- <el-table
- :data="recordDetailList"
- border
- stripe
- style="width: 100%"
- >
- <el-table-column label="订单信息" align="left" min-width="200">
- <template slot-scope="scope">
- <div class="order-info">
- <div class="order-no">{{ scope.row.orderNo }}</div>
- <div class="store-name text-gray">{{ scope.row.storeName }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="派送方式" align="center" width="100">
- <template slot-scope="scope">
- <el-tag :type="scope.row.sendClothWay === '0' ? 'success' : 'primary'" size="small">
- {{ scope.row.sendClothWay === '0' ? '到店' : '上门' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="派送时间" align="center" width="180">
- <template slot-scope="scope">
- {{ scope.row.sendClothWay === '0' ? scope.row.sendToStoreTime : scope.row.sendToUserTime }}
- </template>
- </el-table-column>
- <el-table-column label="取件时间" align="center" width="180" prop="pickUpTime" />
- <el-table-column label="送达时间" align="center" width="180" prop="finishTime" />
- </el-table>
- <pagination
- v-show="recordTotal > 0"
- :total="recordTotal"
- :page.sync="queryDetailParams.pageNum"
- :limit.sync="queryDetailParams.pageSize"
- @pagination="recordDetail"
- />
- </div>
- </el-dialog>
- </div>
- </template>
- <style lang="scss" scoped>
- .app-container {
- .search-card {
- margin-bottom: 16px;
- }
- .delivery-info {
- display: flex;
- align-items: center;
- padding: 8px 0;
- .avatar {
- margin-right: 12px;
- background: #f0f2f5;
- }
- .info {
- .name {
- font-size: 15px;
- font-weight: 500;
- margin-bottom: 4px;
- }
- .phone {
- font-size: 13px;
- }
- }
- }
- .level-desc {
- .description {
- margin-top: 8px;
- font-size: 13px;
- line-height: 1.5;
- }
- }
- .store-count {
- font-size: 16px;
- font-weight: 500;
- color: #409EFF;
- margin-right: 4px;
- }
- .store-text {
- color: #606266;
- font-size: 13px;
- }
- .user-info-card {
- margin: 16px 0;
- border-radius: 4px;
- .primary-text {
- font-weight: 500;
- color: #303133;
- }
- }
- .store-transfer {
- padding: 16px 0;
- .transfer-footer {
- padding: 8px 0;
- text-align: center;
- color: #909399;
- font-size: 13px;
- }
- }
- .record-list {
- .order-info {
- .order-no {
- font-weight: 500;
- margin-bottom: 4px;
- }
- .store-name {
- font-size: 13px;
- }
- }
- }
- .user-search {
- .user-result {
- margin-top: 20px;
- .user-card {
- .user-info {
- display: flex;
- align-items: flex-start;
- .info-content {
- margin-left: 16px;
- flex: 1;
- .name {
- font-size: 16px;
- font-weight: 500;
- margin-bottom: 8px;
- }
- .phone {
- color: #606266;
- margin-bottom: 8px;
- }
- .tags {
- .el-tag + .el-tag {
- margin-left: 8px;
- }
- }
- }
- }
- .select-btn {
- margin-top: 16px;
- text-align: right;
- }
- }
- }
- .no-result {
- text-align: center;
- color: #909399;
- padding: 32px 0;
- i {
- font-size: 32px;
- margin-bottom: 8px;
- }
- span {
- display: block;
- }
- }
- }
- .select-user-tip {
- padding: 32px 0;
- }
- }
- .text-gray {
- color: #909399;
- }
- </style>
- <script>
- import { listDelivery, getDelivery, delDelivery, addDelivery, updateDelivery, updateDeliveryStatus, getDeliveryOrderRecordList, getDeliveryStoreList } from '@/api/app/delivery'
- import { findUserByPhoneNumber } from '@/api/app/user'
- import { allOrg } from '@/api/system/store'
- import DataList from '@/components/DataList'
- export default {
- name: 'Delivery',
- components: {
- DataList
- },
- data() {
- return {
- // 门店列表列配置
- storeColumns: [
- { prop: 'code', label: '门店编号' },
- { prop: 'name', label: '门店名称' },
- { prop: 'address', label: '门店地址' },
- { prop: 'contactName', label: '联系人' },
- { prop: 'contactPhone', label: '联系电话' }
- ],
- // 当前选中的配送员ID
- currentDeliveryId: null,
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- phoneNumber: [],
- appUserId: null,
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- recordTotal: 0,
- // 配送员表格数据
- deliveryList: [],
- // 弹出层标题
- title: '',
- recordDetailTitle: '',
- // 是否显示弹出层
- open: false,
- openDetail: false,
- // 查询参数
- queryParams: {
- appUserName: null,
- phoneNumber: null
- },
- // 查询参数
- queryDetailParams: {
- pageNum: 1,
- pageSize: 10,
- appUserId: null
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- description: [
- { required: true, message: '请输入派送员简介', trigger: 'blur' }
- ]
- },
- appUserInfo: null,
- // 简介
- description: null,
- isUpdate: true,
- orgData: [],
- orgValue: [],
- recordDetailList: [],
- activeTab: 'basic',
- submitLoading: false,
- userSelectVisible: false, // 用户选择弹窗显示状态
- searchPhone: '', // 搜索手机号
- searchUserInfo: null, // 搜索到的用户信息
- }
- },
- created() {
- allOrg().then((res) => {
- this.orgData = []
- res.data.forEach((org) => {
- if (org.sourceType == '02') {
- this.orgData.push({
- key: org.sourceType + ',' + org.id,
- label: org.name
- })
- }
- })
- })
- this.getList()
- },
- methods: {
- /**
- * 显示门店列表
- * @param {Object} row 当前行数据
- */
- showStoreList(row) {
- this.currentDeliveryId = row.appUserId
- this.$refs.storeList.show()
- },
- // 获取部门数据
- fetchStoreList(params) {
- return getDeliveryStoreList({
- pageNum: params.pageNum,
- pageSize: params.pageSize,
- deliveryId: this.currentDeliveryId
- })
- },
- //搜索用户
- searchUser() {
- if (!this.searchPhone) {
- this.$message.warning('请输入手机号')
- return
- }
- findUserByPhoneNumber({ phoneNumber: this.searchPhone }).then(res => {
- this.searchUserInfo = res.data
- })
- },
- /** 查询配送员列表 */
- getList() {
- this.$nextTick(() => {
- this.$refs.pagination.handleSearch(true)
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm('queryForm')
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map((item) => item.id)
- this.phoneNumber = selection.map((item) => item.phoneNumber)
- this.single = selection.length !== 1
- this.multiple = !selection.length
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = '添加配送员'
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- this.open = true
- this.title = '修改配送员'
- // 先获取用户信息
- findUserByPhoneNumber({ phoneNumber: row.phoneNumber }).then((res) => {
- this.appUserInfo = res.data
- // 获取配送员信息
- getDelivery(row.id).then((response) => {
- this.form = response.data
- this.description = response.data.description
- // 设置已绑定门店
- if (this.form.relationList && this.form.relationList.length > 0) {
- this.orgValue = this.form.relationList.map(vo => vo.sourceType + ',' + vo.orgId)
- }
- })
- })
- },
- /** 提交按钮 */
- submitForm() {
- if (!this.appUserInfo) {
- this.$modal.msgError('请先选择用户')
- return
- }
- if (!this.description) {
- this.$modal.msgError('请输入派送员简介')
- return
- }
- if (this.orgValue.length <= 0) {
- this.$modal.msgError('请选择关联门店')
- return
- }
- this.submitLoading = true
- try {
- const relationList = this.orgValue.map(vo => ({
- sourceType: vo.split(',')[0],
- orgId: vo.split(',')[1]
- }))
- const params = {
- ...this.form,
- appUserId: this.appUserInfo.id,
- description: this.description,
- relationList
- }
- const request = this.form.id ? updateDelivery(params) : addDelivery(params)
- request
- .then(() => {
- this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功')
- this.open = false
- this.getList()
- })
- .finally(() => {
- this.submitLoading = false
- })
- } catch (error) {
- this.submitLoading = false
- console.error('提交失败:', error)
- }
- },
- recordDetail(row) {
- if (row.appUserId != null && row.appUserId != '') {
- this.appUserId = row.appUserId
- this.queryDetailParams.appUserId = row.appUserId
- } else {
- this.queryDetailParams.appUserId = this.appUserId
- }
- getDeliveryOrderRecordList(this.queryDetailParams).then((response) => {
- this.recordDetailList = response.rows
- this.recordTotal = response.total
- this.openDetail = true
- this.recordDetailTitle = '接单记录'
- })
- },
- checkClose(done) {
- this.$confirm('是否关闭表单,关闭后数据将丢失?')
- .then(function () {
- done()
- })
- .then(() => { })
- .catch(() => { })
- },
- checkCloseDetail(done) {
- this.$confirm('是否关闭接单记录明细?')
- .then(function () {
- done()
- })
- .then(() => {
- this.appUserId = null
- this.queryDetailParams = {
- pageNum: 1,
- pageSize: 10,
- appUserId: null
- }
- })
- .catch(() => { })
- },
- handleStatusChange(row) {
- let text = row.status === '0' ? '启用' : '停用'
- this.$confirm('确认要' + text + ' ' + row.name + ' 吗?')
- .then(function () {
- return updateDeliveryStatus(row.id, row.status)
- })
- .then(() => {
- this.$modal.msgSuccess(text + '成功')
- })
- .catch(function () {
- row.status = row.status === '0' ? '1' : '0'
- })
- },
- // 过滤门店
- filterStore(query, item) {
- return item.label.toLowerCase().includes(query.toLowerCase())
- },
- // 处理对话框关闭
- handleDialogClose(done) {
- if (this.submitLoading) {
- this.$message.warning('正在提交数据,请稍候...')
- return
- }
- this.$confirm('确认关闭?未保存的数据将会丢失')
- .then(_ => {
- done()
- this.reset()
- })
- .catch(_ => {})
- },
- // 处理详情对话框关闭
- handleDetailClose(done) {
- done()
- this.queryDetailParams = {
- pageNum: 1,
- pageSize: 10,
- appUserId: null
- }
- },
- // 确认选择用户
- confirmSelectUser() {
- this.appUserInfo = this.searchUserInfo
- this.userSelectVisible = false
- this.searchPhone = ''
- this.searchUserInfo = null
- },
- // 重置表单
- reset() {
- this.form = {}
- this.appUserInfo = null
- this.description = null
- this.searchPhone = ''
- this.searchUserInfo = null
- this.orgValue = []
- this.activeTab = 'basic'
- }
- }
- }
- </script>
|