批量按部门修改代理商的寄卖状态,用户状态

This commit is contained in:
zhonghua.li
2026-09-08 01:18:54 +08:00
parent a11ade08ac
commit 365e776b37
6 changed files with 1407 additions and 396 deletions

View File

@@ -40,3 +40,13 @@ export function rushBuyLbBuyAccount(data) {
timeout: 120000 timeout: 120000
}) })
} }
/** 模拟指定租户所有用户抢单 */
export function rushBuyAllLbBuyAccount(params) {
return request({
url: '/lbBuyAccount/simulate-rush-buy_all',
method: 'post',
params,
timeout: 120000
})
}

View File

@@ -118,3 +118,25 @@ export function updateHxrAdminUserVipByUserIds(data) {
skipResponseNormalize: true skipResponseNormalize: true
}) })
} }
/** 按用户 ID 列表批量修改「是否可寄卖 / 用户状态」(逐条调用第三方管理端,可能较慢) */
export function updateHxrAdminUserResellStatusByUserIds(data) {
return request({
url: '/lbPurchaseApply/updateHxrAdminUserResellStatusByUserIds',
method: 'post',
data,
timeout: 120000,
skipResponseNormalize: true
})
}
/** 按 member_info 全部用户批量修改「是否可寄卖 / 用户状态」(不接收 id 列表,逐条调用第三方管理端,可能较慢) */
export function updateHxrAdminUserResellStatusForAllMembers(data) {
return request({
url: '/lbPurchaseApply/updateHxrAdminUserResellStatusForAllMembers',
method: 'post',
data,
timeout: 120000,
skipResponseNormalize: true
})
}

36
src/api/member-info.js Normal file
View File

@@ -0,0 +1,36 @@
import request from '@/utils/request'
/** 会员信息分页查询(member_info) */
export function getMemberInfoList(params) {
return request({
url: '/memberInfo/list',
method: 'get',
params
})
}
/** 新增会员信息 */
export function addMemberInfo(data) {
return request({
url: '/memberInfo/add',
method: 'post',
data
})
}
/** 编辑会员信息(须含 id) */
export function updateMemberInfo(data) {
return request({
url: '/memberInfo/update',
method: 'put',
data
})
}
/** 删除会员信息 */
export function deleteMemberInfo(id) {
return request({
url: `/memberInfo/delete/${id}`,
method: 'delete'
})
}

View File

@@ -168,6 +168,31 @@
> >
取消勾选 取消勾选
</el-button> </el-button>
<el-button
type="info"
icon="el-icon-s-check"
:disabled="!urgeTreeCheckedUserIds.length"
@click="handleUrgeTreeSelectChildren"
>
选中所有的子
</el-button>
<el-button
type="warning"
icon="el-icon-edit-outline"
:loading="urgeTreeStatusSubmitLoading"
:disabled="!urgeTreeCheckedUserIds.length"
@click="openUrgeTreeStatusDialog"
>
修改状态
</el-button>
<el-button
type="danger"
icon="el-icon-set-up"
:loading="urgeTreeAllStatusSubmitLoading"
@click="openUrgeTreeAllStatusDialog"
>
全部修正状态
</el-button>
<span v-if="urgeTreeCheckedUserIds.length" class="urge-tree-selected-tip"> <span v-if="urgeTreeCheckedUserIds.length" class="urge-tree-selected-tip">
已选 {{ urgeTreeCheckedUserIds.length }} 人 已选 {{ urgeTreeCheckedUserIds.length }} 人
</span> </span>
@@ -455,6 +480,94 @@
<el-button type="primary" :loading="parentBindLoading" @click="confirmParentSelection">确定</el-button> <el-button type="primary" :loading="parentBindLoading" @click="confirmParentSelection">确定</el-button>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
title="修改状态"
:visible.sync="urgeTreeStatusDialogVisible"
width="520px"
@close="resetUrgeTreeStatusDialog"
>
<el-form label-width="120px">
<el-form-item label="已选用户">
<el-input :value="`${urgeTreeStatusSelectedUserIds.length} 人`" disabled />
</el-form-item>
<el-form-item label="修改寄卖状态">
<el-switch v-model="urgeTreeStatusForm.isResellEnabled" />
<span class="urge-tree-status-tip">开启后批量修改「是否可以寄卖」</span>
</el-form-item>
<el-form-item v-if="urgeTreeStatusForm.isResellEnabled" label="是否可寄卖" required>
<el-select v-model="urgeTreeStatusForm.isResell" placeholder="请选择" style="width: 100%">
<el-option label="可以寄卖" :value="1" />
<el-option label="不可以寄卖" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="修改用户状态">
<el-switch v-model="urgeTreeStatusForm.statusEnabled" />
<span class="urge-tree-status-tip">开启后批量修改「用户状态」</span>
</el-form-item>
<el-form-item v-if="urgeTreeStatusForm.statusEnabled" label="用户状态" required>
<el-select v-model="urgeTreeStatusForm.status" placeholder="请选择" style="width: 100%">
<el-option label="正常" :value="1" />
<el-option label="停用" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="租户ID">
<el-input :value="urgeTreeStatusTenantIdDisplay" disabled placeholder="未获取到租户ID" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="urgeTreeStatusDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="urgeTreeStatusSubmitLoading" @click="handleConfirmUrgeTreeStatus">
确定
</el-button>
</div>
</el-dialog>
<el-dialog
title="全部修正状态"
:visible.sync="urgeTreeAllStatusDialogVisible"
width="520px"
@close="resetUrgeTreeAllStatusDialog"
>
<el-form label-width="120px">
<el-alert
title="该操作将按 member_info 全部用户批量修改「是否可寄卖 / 用户状态」,逐条调用第三方管理端,可能耗时较长。"
type="warning"
:closable="false"
show-icon
style="margin-bottom: 16px"
/>
<el-form-item label="修改寄卖状态">
<el-switch v-model="urgeTreeAllStatusForm.isResellEnabled" />
<span class="urge-tree-status-tip">开启后批量修改「是否可以寄卖」</span>
</el-form-item>
<el-form-item v-if="urgeTreeAllStatusForm.isResellEnabled" label="是否可寄卖" required>
<el-select v-model="urgeTreeAllStatusForm.isResell" placeholder="请选择" style="width: 100%">
<el-option label="可以寄卖" :value="1" />
<el-option label="不可以寄卖" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="修改用户状态">
<el-switch v-model="urgeTreeAllStatusForm.statusEnabled" />
<span class="urge-tree-status-tip">开启后批量修改「用户状态」</span>
</el-form-item>
<el-form-item v-if="urgeTreeAllStatusForm.statusEnabled" label="用户状态" required>
<el-select v-model="urgeTreeAllStatusForm.status" placeholder="请选择" style="width: 100%">
<el-option label="正常" :value="1" />
<el-option label="停用" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="租户ID">
<el-input :value="urgeTreeAllStatusTenantIdDisplay" disabled placeholder="未获取到租户ID" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="urgeTreeAllStatusDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="urgeTreeAllStatusSubmitLoading" @click="handleConfirmUrgeTreeAllStatus">
确定
</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
@@ -471,6 +584,7 @@ import {
syncLbDepartmentUserFromLbUser, syncLbDepartmentUserFromLbUser,
updateLbDepartmentUser updateLbDepartmentUser
} from '@/api/lb-department-user' } from '@/api/lb-department-user'
import { updateHxrAdminUserResellStatusByUserIds, updateHxrAdminUserResellStatusForAllMembers } from '@/api/lb-purchase-apply'
import { getBusinessHeaders } from '@/utils/business-headers' import { getBusinessHeaders } from '@/utils/business-headers'
function getDefaultUrgeTreeQueryParams() { function getDefaultUrgeTreeQueryParams() {
@@ -496,6 +610,25 @@ export default {
urgeTreeFilterText: '', urgeTreeFilterText: '',
urgeTreeCheckedUserIds: [], urgeTreeCheckedUserIds: [],
urgeTreeSyncingChecks: false, urgeTreeSyncingChecks: false,
urgeTreeStatusDialogVisible: false,
urgeTreeStatusSubmitLoading: false,
urgeTreeStatusSelectedUserIds: [],
urgeTreeStatusTenantIdDisplay: '',
urgeTreeStatusForm: {
isResellEnabled: false,
isResell: 1,
statusEnabled: false,
status: 1
},
urgeTreeAllStatusDialogVisible: false,
urgeTreeAllStatusSubmitLoading: false,
urgeTreeAllStatusTenantIdDisplay: '',
urgeTreeAllStatusForm: {
isResellEnabled: false,
isResell: 1,
statusEnabled: false,
status: 1
},
urgeTreeQueryParams: getDefaultUrgeTreeQueryParams(), urgeTreeQueryParams: getDefaultUrgeTreeQueryParams(),
urgeTreeProps: { urgeTreeProps: {
children: 'children', children: 'children',
@@ -842,6 +975,60 @@ export default {
this.urgeTreeSyncingChecks = false this.urgeTreeSyncingChecks = false
}) })
}, },
buildUrgeTreeNodeIndex(nodes, map = {}) {
if (!nodes || !nodes.length) return map
nodes.forEach((node) => {
if (node.userId != null && node.userId !== '') {
map[this.normalizeUrgeTreeUserId(node.userId)] = node
}
if (node.children && node.children.length) {
this.buildUrgeTreeNodeIndex(node.children, map)
}
})
return map
},
collectUrgeTreeDescendantUserIds(node, result = []) {
const children = node && node.children
if (!children || !children.length) return result
children.forEach((child) => {
if (child.userId != null && child.userId !== '') {
result.push(child.userId)
}
this.collectUrgeTreeDescendantUserIds(child, result)
})
return result
},
handleUrgeTreeSelectChildren() {
const tree = this.$refs.urgeTree
if (!tree) return
this.syncUrgeTreeCheckedFromTree()
const checkedKeys = tree.getCheckedKeys()
if (!checkedKeys.length) {
this.$message.warning('请先勾选节点')
return
}
const nodeIndex = this.buildUrgeTreeNodeIndex(this.urgeTreeData)
const descendantIds = []
checkedKeys.forEach((key) => {
const node = nodeIndex[this.normalizeUrgeTreeUserId(key)]
if (node) {
this.collectUrgeTreeDescendantUserIds(node, descendantIds)
}
})
const mergedKeys = [...new Set([...checkedKeys, ...descendantIds])]
this.urgeTreeSyncingChecks = true
tree.setCheckedKeys(mergedKeys)
this.syncUrgeTreeCheckedFromTree()
this.$nextTick(() => {
this.urgeTreeSyncingChecks = false
})
const addedCount = mergedKeys.length - checkedKeys.length
if (addedCount > 0) {
this.$message.success(`已选中全部下级,新增 ${addedCount} 人,共 ${mergedKeys.length} 人`)
} else {
this.$message.info('所选节点没有可追加的下级节点')
}
},
handleUrgeTreeExport() { handleUrgeTreeExport() {
const tenantId = this.getTenantIdFromBusinessHeaders() const tenantId = this.getTenantIdFromBusinessHeaders()
if (!tenantId) { if (!tenantId) {
@@ -877,6 +1064,165 @@ export default {
this.urgeTreeExportLoading = false this.urgeTreeExportLoading = false
}) })
}, },
getDefaultUrgeTreeStatusForm() {
return {
isResellEnabled: false,
isResell: 1,
statusEnabled: false,
status: 1
}
},
openUrgeTreeStatusDialog() {
this.syncUrgeTreeCheckedFromTree()
const userIds = [...new Set(
this.urgeTreeCheckedUserIds.filter((id) => id !== '' && id != null)
)]
if (!userIds.length) {
this.$message.warning('请先勾选要修改状态的用户')
return
}
this.urgeTreeStatusSelectedUserIds = userIds
this.urgeTreeStatusTenantIdDisplay = this.getTenantIdFromBusinessHeaders()
this.urgeTreeStatusForm = this.getDefaultUrgeTreeStatusForm()
this.urgeTreeStatusDialogVisible = true
},
resetUrgeTreeStatusDialog() {
this.urgeTreeStatusSubmitLoading = false
this.urgeTreeStatusSelectedUserIds = []
this.urgeTreeStatusTenantIdDisplay = ''
this.urgeTreeStatusForm = this.getDefaultUrgeTreeStatusForm()
},
handleConfirmUrgeTreeStatus() {
const tenantId = this.getTenantIdFromBusinessHeaders()
if (!tenantId) {
this.$message.error('未获取到租户ID,请先登录或配置业务请求头中的租户')
return
}
const userIds = (this.urgeTreeStatusSelectedUserIds || [])
.map((id) => Number(id))
.filter((id) => !Number.isNaN(id))
if (!userIds.length) {
this.$message.warning('未选择有效用户,请关闭后重新勾选')
return
}
const { isResellEnabled, isResell, statusEnabled, status } = this.urgeTreeStatusForm
if (!isResellEnabled && !statusEnabled) {
this.$message.warning('请至少开启一项要修改的状态(寄卖状态或用户状态)')
return
}
if (isResellEnabled && isResell !== 0 && isResell !== 1) {
this.$message.warning('请选择「是否可以寄卖」的值')
return
}
if (statusEnabled && status !== 0 && status !== 1) {
this.$message.warning('请选择「用户状态」的值')
return
}
const payload = {
tenantId,
userIds,
isResellEnabled: !!isResellEnabled,
statusEnabled: !!statusEnabled
}
if (isResellEnabled) {
payload.isResell = Number(isResell)
}
if (statusEnabled) {
payload.status = Number(status)
}
this.urgeTreeStatusSubmitLoading = true
updateHxrAdminUserResellStatusByUserIds(payload)
.then((res) => {
const ok = res && (res.success === true || res.code === 200 || res.code === 20000)
if (ok) {
this.$message.success((res && res.message) || '修改状态成功')
this.urgeTreeStatusDialogVisible = false
} else {
this.$message.error((res && (res.message || res.msg)) || '修改状态失败')
}
})
.catch(() => {
// 错误提示由 @/utils/request 响应拦截器统一展示
})
.finally(() => {
this.urgeTreeStatusSubmitLoading = false
})
},
openUrgeTreeAllStatusDialog() {
this.urgeTreeAllStatusTenantIdDisplay = this.getTenantIdFromBusinessHeaders()
this.urgeTreeAllStatusForm = {
isResellEnabled: false,
isResell: 1,
statusEnabled: false,
status: 1
}
this.urgeTreeAllStatusDialogVisible = true
},
resetUrgeTreeAllStatusDialog() {
this.urgeTreeAllStatusSubmitLoading = false
this.urgeTreeAllStatusTenantIdDisplay = ''
this.urgeTreeAllStatusForm = {
isResellEnabled: false,
isResell: 1,
statusEnabled: false,
status: 1
}
},
handleConfirmUrgeTreeAllStatus() {
const tenantId = this.getTenantIdFromBusinessHeaders()
if (!tenantId) {
this.$message.error('未获取到租户ID,请先登录或配置业务请求头中的租户')
return
}
const { isResellEnabled, isResell, statusEnabled, status } = this.urgeTreeAllStatusForm
if (!isResellEnabled && !statusEnabled) {
this.$message.warning('请至少开启一项要修改的状态(寄卖状态或用户状态)')
return
}
if (isResellEnabled && isResell !== 0 && isResell !== 1) {
this.$message.warning('请选择「是否可以寄卖」的值')
return
}
if (statusEnabled && status !== 0 && status !== 1) {
this.$message.warning('请选择「用户状态」的值')
return
}
const payload = {
tenantId,
isResellEnabled: !!isResellEnabled,
statusEnabled: !!statusEnabled
}
if (isResellEnabled) {
payload.isResell = Number(isResell)
}
if (statusEnabled) {
payload.status = Number(status)
}
this.$confirm(
'确认对 member_info 全部会员批量修正状态吗?该操作可能耗时较长。',
'提示',
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
)
.then(() => {
this.urgeTreeAllStatusSubmitLoading = true
return updateHxrAdminUserResellStatusForAllMembers(payload)
})
.then((res) => {
const ok = res && (res.success === true || res.code === 200 || res.code === 20000)
if (ok) {
this.$message.success((res && res.message) || '全部修正状态成功')
this.urgeTreeAllStatusDialogVisible = false
} else {
this.$message.error((res && (res.message || res.msg)) || '全部修正状态失败')
}
})
.catch(() => {
// 错误提示由 @/utils/request 响应拦截器统一展示
})
.finally(() => {
this.urgeTreeAllStatusSubmitLoading = false
})
},
buildSumTotalMoneyParams() { buildSumTotalMoneyParams() {
const tenantId = this.getTenantIdFromBusinessHeaders() const tenantId = this.getTenantIdFromBusinessHeaders()
const params = { tenantId } const params = { tenantId }
@@ -1222,6 +1568,12 @@ export default {
color: #606266; color: #606266;
font-size: 14px; font-size: 14px;
} }
.urge-tree-status-tip {
margin-left: 12px;
color: #909399;
font-size: 13px;
}
} }
.filter-container { .filter-container {

View File

@@ -52,6 +52,14 @@
</el-form-item> </el-form-item>
<el-form-item class="filter-form-query"> <el-form-item class="filter-form-query">
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
<el-button
type="success"
icon="el-icon-magic-button"
:loading="rushBuyAllLoading"
@click="handleRushBuyAll"
>
全部抢单
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@@ -145,7 +153,7 @@
/> />
</el-card> </el-card>
<el-dialog title="选择货物包开始时间" :visible.sync="rushBuyTimeDialogVisible" width="500px" top="20vh"> <el-dialog :title="rushBuyMode === 'all' ? '全部抢单 - 选择货物包开始时间' : '选择货物包开始时间'" :visible.sync="rushBuyTimeDialogVisible" width="500px" top="20vh">
<el-form label-width="120px"> <el-form label-width="120px">
<el-form-item label="货物包开始时间"> <el-form-item label="货物包开始时间">
<el-date-picker <el-date-picker
@@ -159,7 +167,7 @@
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="rushBuyTimeDialogVisible = false">取消</el-button> <el-button @click="rushBuyTimeDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="rushBuyLoading" @click="handleConfirmRushBuyTime">确认</el-button> <el-button type="primary" :loading="rushBuyMode === 'all' ? rushBuyAllLoading : rushBuyLoading" @click="handleConfirmRushBuyTime">确认</el-button>
</div> </div>
</el-dialog> </el-dialog>
@@ -314,6 +322,7 @@ import {
addLbBuyAccount, addLbBuyAccount,
deleteLbBuyAccount, deleteLbBuyAccount,
getLbBuyAccountList, getLbBuyAccountList,
rushBuyAllLbBuyAccount,
rushBuyLbBuyAccount, rushBuyLbBuyAccount,
updateLbBuyAccount updateLbBuyAccount
} from '@/api/lb-buy-account' } from '@/api/lb-buy-account'
@@ -354,6 +363,8 @@ export default {
submitLoading: false, submitLoading: false,
syncLoading: false, syncLoading: false,
rushBuyLoading: false, rushBuyLoading: false,
rushBuyAllLoading: false,
rushBuyMode: 'selected',
tenantLoading: false, tenantLoading: false,
rushBuyTimeDialogVisible: false, rushBuyTimeDialogVisible: false,
rushBuyTime: '', rushBuyTime: '',
@@ -502,6 +513,17 @@ export default {
this.$message.warning('所选账号缺少有效 ID') this.$message.warning('所选账号缺少有效 ID')
return return
} }
this.rushBuyMode = 'selected'
this.rushBuyTime = this.getYesterdayStart()
this.rushBuyTimeDialogVisible = true
},
handleRushBuyAll() {
const tenantId = (this.queryParams.tenantId || '').trim() || this.getTenantIdFromBusinessHeaders()
if (!tenantId) {
this.$message.error('未获取到租户ID,请先选择租户或配置业务请求头中的租户')
return
}
this.rushBuyMode = 'all'
this.rushBuyTime = this.getYesterdayStart() this.rushBuyTime = this.getYesterdayStart()
this.rushBuyTimeDialogVisible = true this.rushBuyTimeDialogVisible = true
}, },
@@ -510,6 +532,13 @@ export default {
this.$message.warning('请选择货物包时间') this.$message.warning('请选择货物包时间')
return return
} }
if (this.rushBuyMode === 'all') {
this.confirmRushBuyAll()
return
}
this.confirmRushBuySelected()
},
confirmRushBuySelected() {
const ids = this.multipleSelection.map((row) => row.id).filter(Boolean) const ids = this.multipleSelection.map((row) => row.id).filter(Boolean)
const accountLabels = this.multipleSelection const accountLabels = this.multipleSelection
.map((row) => row.loginAccount || row.nickname || row.id) .map((row) => row.loginAccount || row.nickname || row.id)
@@ -538,6 +567,34 @@ export default {
this.rushBuyLoading = false this.rushBuyLoading = false
}) })
}, },
confirmRushBuyAll() {
const tenantId = (this.queryParams.tenantId || '').trim() || this.getTenantIdFromBusinessHeaders()
this.$confirm(
`确定对该租户所有用户发起全部抢单吗?\n租户ID:${tenantId}\n货物包开始时间:${this.rushBuyTime}`,
'全部抢单',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
this.rushBuyAllLoading = true
const params = { tenantId }
if (this.rushBuyTime) params.goodsBeginTime = this.rushBuyTime
return rushBuyAllLbBuyAccount(params)
}).then((res) => {
const isSuccess = res && (res.success === true || res.code === 200 || res.code === 20000)
if (!isSuccess) {
this.$message.error((res && res.message) || '全部抢单失败')
return
}
this.$message.success((res && res.message) || '全部抢单完成')
this.rushBuyTimeDialogVisible = false
this.fetchList()
}).catch(() => {}).finally(() => {
this.rushBuyAllLoading = false
})
},
handleTenantChange(tenantId) { handleTenantChange(tenantId) {
const option = this.tenantOptions.find((item) => item.value === tenantId) const option = this.tenantOptions.find((item) => item.value === tenantId)
if (option && option.tenantName) { if (option && option.tenantName) {

File diff suppressed because it is too large Load Diff