yyb
5 小时以前 769fb543015f1a90d42882a0a9f0592efa45a10e
src/components/ProjectManagement/DiscussProgressDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,141 @@
<template>
  <el-dialog v-model="visible" title="洽谈进度" width="700px" top="10vh" append-to-body destroy-on-close @close="handleClose">
    <el-form ref="formRef" :model="form" :rules="rules" label-position="top" label-width="120px">
      <el-form-item label="项目阶段" prop="planNodeId">
        <el-select v-model="form.planNodeId" placeholder="请选择" clearable style="width: 100%">
          <el-option v-for="opt in stageOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
        </el-select>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请输入" />
      </el-form-item>
      <el-form-item label="附件" prop="attachmentIds">
        <el-upload
          v-model:file-list="fileList"
          :action="upload.url"
          :headers="upload.headers"
          multiple
          name="files"
          :on-success="handleUploadSuccess"
          :on-error="handleUploadError"
          :on-remove="handleRemove"
        >
          <el-button type="primary">上传文件</el-button>
        </el-upload>
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="visible = false">取消</el-button>
        <el-button type="danger" @click="submit">提交</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup name="DiscussProgressDialog">
import { computed, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/auth'
const props = defineProps({
  modelValue: { type: Boolean, default: false },
  projectId: { type: [Number, String], default: undefined },
  planNodes: { type: Array, default: () => [] },
  defaultPlanNodeId: { type: [Number, String], default: undefined }
})
const emit = defineEmits(['update:modelValue', 'submitted'])
const visible = computed({
  get: () => props.modelValue,
  set: v => emit('update:modelValue', v)
})
const upload = reactive({
  url: import.meta.env.VITE_APP_BASE_API + '/basic/customer-follow/upload',
  headers: { Authorization: 'Bearer ' + getToken() }
})
const formRef = ref()
const fileList = ref([])
const form = ref({
  planNodeId: undefined,
  remark: '',
  attachmentIds: []
})
const rules = {
  planNodeId: [{ required: true, message: '请选择', trigger: 'change' }],
  remark: [{ required: true, message: '请输入', trigger: 'blur' }]
}
const stageOptions = computed(() => {
  const list = Array.isArray(props.planNodes) ? props.planNodes : []
  const sorted = [...list].sort((a, b) => Number(a.sort ?? 0) - Number(b.sort ?? 0))
  return sorted
    .map(n => ({
      label: n.name || n.workContent || n.title || String(n.id ?? ''),
      value: n.id
    }))
    .filter(i => i.value !== undefined && i.value !== null && i.value !== '')
})
watch(
  () => props.modelValue,
  v => {
    if (v) {
      form.value = { planNodeId: props.defaultPlanNodeId ?? stageOptions.value[0]?.value, remark: '', attachmentIds: [] }
      fileList.value = []
    }
  }
)
function handleClose() {
  formRef.value?.resetFields?.()
}
function handleUploadError() {
  ElMessage.error('上传文件失败')
}
function handleUploadSuccess(res, file) {
  if (res?.code !== 200) {
    ElMessage.error(res?.msg || '上传失败')
    return
  }
  const attachmentId = res?.data?.id ?? res?.data?.tempId ?? ''
  if (!attachmentId) return
  form.value.attachmentIds.push(attachmentId)
  try {
    file.attachmentId = attachmentId
  } catch (e) {}
  ElMessage.success('上传成功')
}
function handleRemove(file) {
  const attachmentId = file?.attachmentId
  if (!attachmentId) return
  form.value.attachmentIds = (form.value.attachmentIds || []).filter(id => id !== attachmentId)
}
async function submit() {
  await formRef.value?.validate?.()
  emit('submitted', {
    projectId: props.projectId,
    ...form.value
  })
  visible.value = false
}
</script>
<style scoped lang="scss">
.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
</style>