user-batch-rest-group-dialog.vue 8.21 KB
<template>
  <el-dialog
    :visible.sync="visible"
    custom-class="user-batch-dialog user-batch-dialog--rest"
    width="520px"
    append-to-body
    :close-on-click-modal="false"
    @closed="onClosed"
  >
    <template slot="title">
      <div class="ubd-title">
        <div class="ubd-title__icon-wrap ubd-title__icon-wrap--rest">
          <i class="el-icon-date ubd-title__icon" />
        </div>
        <div class="ubd-title__meta">
          <div class="ubd-title__heading">批量设置应休分组</div>
          <div class="ubd-title__desc">统一绑定应休规则(月应休、半天拆分等来自所选分组)</div>
        </div>
      </div>
    </template>

    <div class="ubd-body ubd-body--rest">
      <div class="ubd-stat-bar ubd-stat-bar--rest">
        <div class="ubd-stat-bar__main">
          <span class="ubd-stat-bar__num ubd-stat-bar__num--rest">{{ userIds.length }}</span>
          <span class="ubd-stat-bar__unit ubd-stat-bar__unit--rest">人</span>
          <span class="ubd-stat-bar__dash">将绑定同一应休分组</span>
        </div>
        <p class="ubd-stat-bar__hint">
          清空下拉框并保存,可取消用户级绑定,员工将沿用各门店<strong>考勤分组默认</strong>应休规则。
        </p>
      </div>

      <div class="ubd-panel ubd-panel--rest">
        <div class="ubd-field-label">
          <span class="ubd-field-label__text">应休分组</span>
          <span class="ubd-field-label__optional">可选</span>
        </div>
        <el-select
          v-model="attendanceRestGroupId"
          placeholder="请选择分组,或清空以恢复默认"
          clearable
          filterable
          class="ubd-rest-select"
          popper-class="ubd-rest-select-dropdown"
        >
          <el-option v-for="item in options" :key="item.id" :label="item.fullName" :value="item.id" />
        </el-select>
        <p class="ubd-field-help">
          <i class="el-icon-info" />
          与「用户编辑」中单人选应休分组的逻辑一致,仅批量写入该字段。
        </p>
      </div>
    </div>

    <div slot="footer" class="ubd-footer">
      <el-button class="ubd-footer__cancel" @click="visible = false">取消</el-button>
      <el-button type="primary" class="ubd-footer__ok" :loading="submitting" @click="submit">
        应用到所选用户
      </el-button>
    </div>
  </el-dialog>
</template>

<script>
import { getAttendanceRestGroupSelector } from '@/api/extend/attendanceRestGroup'
import { batchUpdateUserPunchRest } from '@/api/permission/user'

export default {
  name: 'user-batch-rest-group-dialog',
  data() {
    return {
      visible: false,
      userIds: [],
      submitting: false,
      attendanceRestGroupId: '',
      options: []
    }
  },
  methods: {
    open(userIds) {
      this.userIds = Array.isArray(userIds) ? userIds.filter(Boolean) : []
      this.attendanceRestGroupId = ''
      this.visible = true
      this.loadOptions()
    },
    loadOptions() {
      getAttendanceRestGroupSelector().then(res => {
        if (res.data && res.data.list) {
          this.options = res.data.list
        } else if (res.data && Array.isArray(res.data)) {
          this.options = res.data
        } else {
          this.options = []
        }
      }).catch(() => {
        this.options = []
      })
    },
    onClosed() {
      this.userIds = []
      this.attendanceRestGroupId = ''
      this.submitting = false
    },
    submit() {
      if (!this.userIds.length) {
        this.$message.warning('没有可更新的用户')
        return
      }
      const payload = {
        userIds: this.userIds,
        updatePunchAllowedStores: false,
        updateAttendanceRestGroup: true,
        punchAllowedStoreIds: '',
        attendanceRestGroupId: this.attendanceRestGroupId || ''
      }
      this.submitting = true
      batchUpdateUserPunchRest(payload)
        .then(res => {
          this.$message.success(res.msg || '批量设置成功')
          this.visible = false
          this.$emit('success')
        })
        .finally(() => {
          this.submitting = false
        })
    }
  }
}
</script>

<style lang="scss">
.user-batch-dialog--rest.el-dialog {
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 24px 48px rgba(15, 23, 42, 0.12), 0 8px 16px rgba(15, 23, 42, 0.06);

  .el-dialog__header {
    padding: 20px 24px 16px;
    border-bottom: 1px solid #eef0f4;
    background: linear-gradient(180deg, #fafbfd 0%, #fff 100%);
  }

  .el-dialog__title {
    width: 100%;
    line-height: 1.3;
  }

  .el-dialog__body {
    padding: 20px 24px 8px;
    background: #f5f7fb;
  }

  .el-dialog__footer {
    padding: 16px 24px 20px;
    border-top: 1px solid #eef0f4;
    background: #fff;
  }

  .el-dialog__headerbtn {
    top: 18px;
    right: 18px;
  }

  .el-dialog__headerbtn .el-dialog__close {
    font-size: 18px;
    color: #909399;
  }

  .el-dialog__headerbtn .el-dialog__close:hover {
    color: #409eff;
  }
}
</style>

<style lang="scss" scoped>
.ubd-title {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding-right: 36px;
}

.ubd-title__icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.ubd-title__icon-wrap--rest {
  background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
  box-shadow: 0 8px 20px rgba(103, 194, 58, 0.35);
}

.ubd-title__icon {
  font-size: 22px;
  color: #fff;
}

.ubd-title__heading {
  font-size: 18px;
  font-weight: 600;
  color: #1f2937;
  letter-spacing: 0.02em;
}

.ubd-title__desc {
  margin-top: 4px;
  font-size: 13px;
  color: #6b7280;
  line-height: 1.45;
}

.ubd-body--rest {
  margin: 0 -4px;
}

.ubd-stat-bar--rest {
  background: linear-gradient(110deg, #ecf9f0 0%, #f4fbf7 50%, #f0fdf4 100%);
  border: 1px solid rgba(103, 194, 58, 0.22);
}

.ubd-stat-bar__num--rest {
  color: #52a832 !important;
}

.ubd-stat-bar__unit--rest {
  color: #52a832 !important;
}

.ubd-stat-bar {
  margin-bottom: 16px;
  padding: 14px 18px;
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
}

.ubd-stat-bar__main {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
}

.ubd-stat-bar__num {
  font-size: 28px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
}

.ubd-stat-bar__unit {
  font-size: 14px;
  font-weight: 600;
}

.ubd-stat-bar__dash {
  font-size: 14px;
  color: #374151;
  font-weight: 500;
}

.ubd-stat-bar__hint {
  margin: 10px 0 0;
  font-size: 12px;
  color: #6b7280;
  line-height: 1.55;
}

.ubd-stat-bar__hint strong {
  color: #52a832;
  font-weight: 600;
}

.ubd-panel--rest {
  background: #fff;
  border-radius: 12px;
  border: 1px solid #e8ebf0;
  padding: 18px 18px 16px;
  box-shadow: 0 4px 20px rgba(15, 23, 42, 0.04);
}

.ubd-field-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.ubd-field-label__text {
  font-size: 14px;
  font-weight: 600;
  color: #374151;
}

.ubd-field-label__optional {
  font-size: 11px;
  font-weight: 500;
  color: #9ca3af;
  padding: 2px 8px;
  background: #f3f4f6;
  border-radius: 999px;
}

.ubd-rest-select {
  width: 100%;
}

.ubd-rest-select ::v-deep .el-input__inner {
  border-radius: 10px;
  height: 42px;
  line-height: 42px;
  border-color: #e4e7ed;
  font-size: 14px;
}

.ubd-rest-select ::v-deep .el-input__inner:focus {
  border-color: #67c23a;
}

.ubd-rest-select ::v-deep .el-input.is-focus .el-input__inner {
  border-color: #67c23a;
}

.ubd-field-help {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 14px 0 0;
  padding: 10px 12px;
  background: #f8fafc;
  border-radius: 10px;
  border: 1px solid #eef1f6;
  font-size: 12px;
  color: #6b7280;
  line-height: 1.55;
}

.ubd-field-help i {
  margin-top: 2px;
  color: #409eff;
  flex-shrink: 0;
}

.ubd-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
}

.ubd-footer__cancel {
  min-width: 88px;
  border-radius: 10px;
}

.ubd-footer__ok {
  min-width: 140px;
  border-radius: 10px;
  font-weight: 500;
  background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
  border: none;
  box-shadow: 0 4px 14px rgba(103, 194, 58, 0.38);
}

.ubd-footer__ok:hover,
.ubd-footer__ok:focus {
  background: linear-gradient(135deg, #5daf34 0%, #7bc755 100%);
  border: none;
}
</style>