todo-add-dialog.vue 5.16 KB
<template>
  <el-dialog
    :visible.sync="visibleProxy"
    :show-close="false"
    width="480px"
    :close-on-click-modal="false"
    custom-class="todo-add-dialog"
    append-to-body
    @open="handleOpen"
  >
    <div class="dialog-inner">
      <div class="dialog-header">
        <div class="dialog-title-wrap">
          <div class="dialog-title">添加待办</div>
          <div class="dialog-subtitle">记录个人事项,到期可在待办中查看</div>
        </div>
        <span class="dialog-close" @click="visibleProxy = false"><i class="el-icon-close"></i></span>
      </div>

      <div class="dialog-body">
        <el-form ref="form" :model="form" :rules="rules" label-width="88px" size="small">
          <el-form-item label="待办标题" prop="title">
            <el-input v-model="form.title" placeholder="请输入待办标题" maxlength="100" show-word-limit />
          </el-form-item>
          <el-form-item label="待办描述">
            <el-input
              v-model="form.desc"
              type="textarea"
              :rows="3"
              placeholder="补充说明(选填)"
              maxlength="500"
              show-word-limit
            />
          </el-form-item>
          <el-form-item label="提醒时间">
            <el-date-picker
              v-model="form.dueTime"
              type="datetime"
              value-format="timestamp"
              placeholder="选择提醒时间(选填)"
              style="width: 100%"
            />
          </el-form-item>
        </el-form>
      </div>

      <div class="dialog-footer">
        <el-button type="primary" size="small" class="pill-btn" :loading="submitting" @click="handleSubmit">保存</el-button>
        <el-button size="small" class="pill-btn pill-btn--plain" @click="visibleProxy = false">取消</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import { createTodo } from '@/api/lqTodo'

export default {
  name: 'TodoAddDialog',
  props: {
    visible: { type: Boolean, default: false },
    storeId: { type: String, default: '' }
  },
  data() {
    return {
      submitting: false,
      form: {
        title: '',
        desc: '',
        dueTime: null
      },
      rules: {
        title: [{ required: true, message: '请输入待办标题', trigger: 'blur' }]
      }
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(v) { this.$emit('update:visible', v) }
    }
  },
  methods: {
    handleOpen() {
      this.form = { title: '', desc: '', dueTime: null }
      this.$nextTick(() => {
        if (this.$refs.form) this.$refs.form.clearValidate()
      })
    },
    handleSubmit() {
      this.$refs.form.validate(async valid => {
        if (!valid) return
        this.submitting = true
        try {
          const userId = (this.$store.getters.userInfo || {}).userId || ''
          await createTodo({
            userId: userId || undefined,
            title: this.form.title.trim(),
            desc: this.form.desc ? this.form.desc.trim() : undefined,
            dueTime: this.form.dueTime || undefined,
            storeId: this.storeId || undefined,
            source: 'manual',
            tag: '自定',
            handleType: 'dialog',
            handlePath: 'manualTodo'
          })
          this.$message.success('待办已添加')
          this.$emit('success')
          this.visibleProxy = false
        } catch (e) {
          // 错误由拦截器处理
        } finally {
          this.submitting = false
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .todo-add-dialog {
  border-radius: 20px;
  padding: 0;
  background: radial-gradient(circle at 0 0, rgba(255, 255, 255, 0.96) 0, rgba(248, 250, 252, 0.98) 40%, rgba(241, 245, 249, 0.98) 100%);
  box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18), 0 0 0 1px rgba(255, 255, 255, 0.9);
  .el-dialog__header { display: none; }
  .el-dialog__body { padding: 0; }
}
.dialog-inner { display: flex; flex-direction: column; }
.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 18px 20px 0;
  padding: 10px 14px;
  border-radius: 14px;
  background: rgba(219, 234, 254, 0.96);
}
.dialog-title-wrap { display: flex; flex-direction: column; gap: 2px; }
.dialog-title { font-size: 17px; font-weight: 600; color: #0f172a; }
.dialog-subtitle { font-size: 12px; color: #64748b; }
.dialog-close {
  cursor: pointer;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: #64748b;
  &:hover { background: rgba(0, 0, 0, 0.06); color: #0f172a; }
}
.dialog-body { padding: 14px 20px 4px; }
.dialog-footer {
  display: flex;
  justify-content: flex-start;
  gap: 8px;
  padding: 12px 20px 18px;
  border-top: 1px solid rgba(229, 231, 235, 0.6);
}
::v-deep .pill-btn {
  border-radius: 999px;
  &.el-button--primary {
    background: #2563eb;
    border-color: #2563eb;
    box-shadow: 0 4px 10px rgba(37, 99, 235, 0.28);
  }
}
.pill-btn--plain { border-radius: 999px; }
::v-deep .todo-add-dialog .el-input__inner,
::v-deep .todo-add-dialog .el-textarea__inner {
  border-radius: 10px;
  border-color: #e5e7eb;
  background-color: #f9fafb;
}
</style>