zhangwencui
2026-11-02 dab35bff798cfce2ddf7e8a67e4e1cdb144f5b4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">
  import { computed, reactive, ref } from "vue";
  import { onLoad } from "@dcloudio/uni-app";
  import { createUserGroup, getBpmSimpleUserList, getUserGroup, updateUserGroup, type BpmUser, type BpmUserGroup } from "../../../api/bpm";
  import { useAuth } from "../../../stores/auth";
  import { toast } from "../admin-shared";
  const { hasPermission, state }=useAuth(); const id=ref<number>(); const mode=ref("edit"); const saving=ref(false); const showUsers=ref(false); const users=ref<BpmUser[]>([]);
  const readonly=computed(()=>mode.value==="detail"); const canSave=computed(()=>!readonly.value && (id.value ? hasPermission("bpm:user-group:update") : hasPermission("bpm:user-group:create"))); const form=reactive<BpmUserGroup>({name:"",description:"",userIds:[],status:0,remark:""});
  const userNames=computed(()=>{ const map=new Map(users.value.map(u=>[u.id,u.nickname])); return (form.userIds||[]).map(id=>map.get(id)||id).join("、") || "请选择成员"; });
  async function loadUsers(){ if(state.accessToken&&!users.value.length) users.value=await getBpmSimpleUserList(state.accessToken); }
  onLoad(async q=>{ await loadUsers(); if(q?.id){ id.value=Number(q.id); mode.value=String(q.mode||"edit"); if(state.accessToken) Object.assign(form,await getUserGroup(state.accessToken,id.value)); }});
  function changeUsers(e:{detail:{value:string[]}}){ form.userIds=e.detail.value.map(Number); }
  async function save(){ if(!canSave.value)return; if(!state.accessToken)return; if(!form.name){toast("请填写分组名称");return;} saving.value=true; try{ if(id.value) await updateUserGroup(state.accessToken,form); else await createUserGroup(state.accessToken,form); uni.showToast({title:"已保存",icon:"success"}); setTimeout(()=>uni.navigateBack(),500);}finally{saving.value=false}}
</script>
<template><view class="page"><view class="card"><view class="field"><text>分组名称 <text class="required">*</text></text><input v-model="form.name" :disabled="!canSave" placeholder="请输入分组名称"/></view><view class="field"><text>状态</text><switch :checked="form.status!==1" :disabled="!canSave" @change="form.status=$event.detail.value?0:1"/></view><view class="field" @click="canSave && (showUsers=true)"><text>成员</text><view class="value">{{ userNames }}<text>›</text></view></view><view class="field column"><text>描述</text><textarea v-model="form.description" :disabled="!canSave" placeholder="请输入描述"/></view><view class="field column"><text>备注</text><textarea v-model="form.remark" :disabled="!canSave" placeholder="请输入备注"/></view></view><button v-if="canSave" class="save" :loading="saving" @click="save">保存</button><view v-if="showUsers" class="mask" @click.self="showUsers=false"><view class="sheet"><view class="sheet-head"><text>选择成员</text><text @click="showUsers=false">完成</text></view><checkbox-group @change="changeUsers"><label v-for="user in users" :key="user.id" class="user"><text>{{ user.nickname || user.id }}</text><checkbox :value="String(user.id)" :checked="form.userIds?.includes(user.id || 0)"/></label></checkbox-group></view></view></view></template>
<style lang="scss" scoped>.page{min-height:100vh;padding:24rpx 30rpx 70rpx;background:#f6f7f9}.card{overflow:hidden;background:#fff;border-radius:16rpx}.field{display:flex;align-items:center;min-height:96rpx;gap:20rpx;padding:0 24rpx;border-bottom:1rpx solid #eef1f5}.field>text:first-child{width:190rpx;flex:none;color:#33455d;font-size:27rpx}.field input{min-width:0;flex:1;color:#1e3049;font-size:27rpx;text-align:right}.value{display:flex;min-width:0;flex:1;align-items:center;justify-content:flex-end;gap:12rpx;color:#1e3049;font-size:27rpx;text-align:right}.value text{flex:none;color:#8092a7;font-size:36rpx}.required{color:#e23b3b}.column{align-items:flex-start;flex-direction:column;padding:20rpx 24rpx}.column>text:first-child{width:auto}.column textarea{width:100%;height:150rpx;box-sizing:border-box;font-size:27rpx}.save{margin-top:32rpx;color:#fff;font-size:30rpx;background:var(--color-primary, #1769d8);border-radius:12rpx}.save::after{border:0}.mask{position:fixed;inset:0;z-index:30;display:flex;align-items:flex-end;background:rgba(18,29,43,.42)}.sheet{width:100%;max-height:78vh;overflow:auto;background:#fff;border-radius:24rpx 24rpx 0 0}.sheet-head{display:flex;align-items:center;justify-content:space-between;height:92rpx;padding:0 30rpx;border-bottom:1rpx solid #edf1f6}.sheet-head text:first-child{color:#20334c;font-size:30rpx;font-weight:700}.sheet-head text:last-child{color:var(--color-primary, #1769d8);font-size:25rpx}.user{display:flex;align-items:center;justify-content:space-between;min-height:86rpx;padding:0 30rpx;border-bottom:1rpx solid #edf1f6}.user text{color:#20334c;font-size:26rpx}</style>