SubstationList.vue 7.67 KB
<template>
  <div>
    <a-card title="分站管理" :bordered="false" class="list-table-card">
      <div class="list-toolbar">
        <div class="list-toolbar-left">
          <a-input-search v-model:value="keyword" placeholder="搜索账号/昵称/手机" @search="loadList" class="list-search" />
        </div>
        <div class="list-toolbar-right">
          <a-button type="primary" @click="openAdd">新增分站</a-button>
        </div>
      </div>
      <a-table :dataSource="list" :columns="columns" :loading="loading" rowKey="id" :pagination="false">
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'cityId'">
            {{ getCityName(record.cityId) }}
          </template>
          <template v-if="column.key === 'roleId'">
            {{ getRoleName(record.roleId) }}
          </template>
          <template v-if="column.key === 'status'">
            <a-tag :color="record.userStatus === 1 ? 'green' : 'red'">
              {{ record.userStatus === 1 ? '正常' : '禁用' }}
            </a-tag>
          </template>
          <template v-if="column.key === 'action'">
            <a-space>
              <a @click="openEdit(record)">编辑</a>
              <a @click="openChangePwd(record)">改密码</a>
              <a-popconfirm
                :title="record.userStatus === 1 ? '确认禁用?' : '确认启用?'"
                @confirm="toggleBan(record)">
                <a :style="record.userStatus === 1 ? 'color:red' : ''">
                  {{ record.userStatus === 1 ? '禁用' : '启用' }}
                </a>
              </a-popconfirm>
              <a-popconfirm title="确认删除?" @confirm="handleDel(record.id)">
                <a style="color:red">删除</a>
              </a-popconfirm>
            </a-space>
          </template>
        </template>
      </a-table>
    </a-card>

    <a-modal v-model:open="modalVisible" :title="editingId ? '编辑分站' : '新增分站'" @ok="handleSave" :confirmLoading="saving">
      <div class="soft-page-stack">
        <div class="soft-note-card">
          <strong>分站账号说明</strong>
          <p>分站账号绑定单一租户,用于日常站点运营。编辑时登录账号保持不变,密码留空则不修改。</p>
        </div>
        <a-form :model="form" layout="vertical">
          <a-form-item label="所属租户">
            <a-select v-model:value="form.cityId" placeholder="选择租户">
              <a-select-option v-for="c in cityList" :key="c.id" :value="c.id">{{ c.name }}</a-select-option>
            </a-select>
          </a-form-item>
          <a-form-item label="菜单角色">
            <a-select v-model:value="form.roleId" placeholder="选择角色">
              <a-select-option v-for="item in roleOptions" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
            </a-select>
          </a-form-item>
          <a-form-item label="登录账号">
            <a-input v-model:value="form.userLogin" :disabled="!!editingId" />
          </a-form-item>
          <a-form-item label="昵称">
            <a-input v-model:value="form.userNickname" />
          </a-form-item>
          <a-form-item label="手机号">
            <a-input v-model:value="form.mobile" />
          </a-form-item>
          <a-form-item :label="editingId ? '新密码(不填不修改)' : '密码'">
            <a-input-password v-model:value="form.userPass" />
          </a-form-item>
        </a-form>
      </div>
    </a-modal>

    <a-modal v-model:open="pwdVisible" title="修改密码" @ok="handleChangePwd" :confirmLoading="pwdSaving">
      <div class="soft-page-stack">
        <div class="soft-note-card">
          <strong>密码修改说明</strong>
          <p>这里修改的是当前选中分站账号的登录密码,提交时会按目标分站账号执行,不影响其他账号。</p>
        </div>
        <a-form layout="vertical">
          <a-form-item label="原密码">
            <a-input-password v-model:value="pwdForm.oldPassword" />
          </a-form-item>
          <a-form-item label="新密码">
            <a-input-password v-model:value="pwdForm.newPassword" />
          </a-form-item>
        </a-form>
      </div>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import { substationApi, systemRoleApi } from '@/api'
import { useRoleCityList } from '@/composables/useRoleCityList'

const loading = ref(false)
const saving = ref(false)
const list = ref<any[]>([])
const roleOptions = ref<any[]>([])
const keyword = ref('')
const modalVisible = ref(false)
const editingId = ref<number | null>(null)
const form = reactive({ cityId: undefined, roleId: undefined, userLogin: '', userNickname: '', mobile: '', userPass: '' })
const { cityList, loadCities, getCityName } = useRoleCityList()

const columns = [
  { title: 'ID', dataIndex: 'id', width: 80 },
  { title: '账号', dataIndex: 'userLogin' },
  { title: '昵称', dataIndex: 'userNickname' },
  { title: '手机', dataIndex: 'mobile' },
  { title: '角色', key: 'roleId' },
  { title: '租户', key: 'cityId' },
  { title: '状态', key: 'status' },
  { title: '操作', key: 'action' },
]

function getRoleName(roleId?: number) {
  const role = roleOptions.value.find(item => item.id === roleId)
  return role?.name || (roleId ? `角色#${roleId}` : '-')
}

async function loadList() {
  loading.value = true
  try {
    const res: any = await substationApi.list(keyword.value)
    list.value = res.data
  } finally { loading.value = false }
}

async function loadRoles() {
  const res: any = await systemRoleApi.list()
  roleOptions.value = Array.isArray(res?.data) ? res.data.filter((item: any) => item.roleScope === 'SUBSTATION') : []
}

function openAdd() {
  editingId.value = null
  Object.assign(form, { cityId: undefined, roleId: roleOptions.value[0]?.id, userLogin: '', userNickname: '', mobile: '', userPass: '' })
  modalVisible.value = true
}

function openEdit(record: any) {
  editingId.value = record.id
  Object.assign(form, { cityId: record.cityId, roleId: record.roleId, userLogin: record.userLogin, userNickname: record.userNickname, mobile: record.mobile, userPass: '' })
  modalVisible.value = true
}

async function handleSave() {
  if (!form.roleId) {
    message.error('请选择菜单角色')
    return
  }
  saving.value = true
  try {
    if (editingId.value) {
      await substationApi.edit({ ...form, id: editingId.value })
    } else {
      await substationApi.add(form)
    }
    message.success('保存成功')
    modalVisible.value = false
    loadList()
  } finally { saving.value = false }
}

async function toggleBan(record: any) {
  if (record.userStatus === 1) {
    await substationApi.ban(record.id)
  } else {
    await substationApi.cancelBan(record.id)
  }
  message.success('操作成功')
  loadList()
}

async function handleDel(id: number) {
  await substationApi.del(id)
  message.success('删除成功')
  loadList()
}

// 改密码
const pwdVisible = ref(false)
const pwdSaving = ref(false)
const pwdForm = reactive({ oldPassword: '', newPassword: '' })
const pwdTargetId = ref(0)

function openChangePwd(record: any) {
  pwdTargetId.value = record.id
  Object.assign(pwdForm, { oldPassword: '', newPassword: '' })
  pwdVisible.value = true
}

async function handleChangePwd() {
  if (!pwdForm.oldPassword || !pwdForm.newPassword) {
    message.error('请填写完整密码')
    return
  }
  pwdSaving.value = true
  try {
    await substationApi.changePassword({ id: pwdTargetId.value, ...pwdForm })
    message.success('密码修改成功')
    pwdVisible.value = false
  } finally { pwdSaving.value = false }
}

onMounted(() => { loadList(); loadCities(); loadRoles() })
</script>