CrowdTaskEdit.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <template>
  2. <div class="crowd-task-edit">
  3. <el-card>
  4. <div slot="header" class="header">
  5. <span class="title">{{ pageTitle }}</span>
  6. </div>
  7. <el-steps :active="step" finish-status="success" align-center class="steps">
  8. <el-step title="基本信息" icon="el-icon-edit-outline" />
  9. <el-step title="规则组/奖励信息" icon="el-icon-set-up" />
  10. </el-steps>
  11. <!-- Step 1: 基本信息 -->
  12. <div v-show="step === 0" class="section">
  13. <el-form
  14. ref="baseForm"
  15. :model="form"
  16. :rules="rules"
  17. label-width="140px"
  18. style="max-width: 1000px; margin: 0 auto"
  19. >
  20. <el-row :gutter="32">
  21. <el-col :span="12">
  22. <el-form-item label="客群名称" prop="name">
  23. <el-input v-model="form.name" placeholder="请输入" maxlength="40" show-word-limit />
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="12">
  27. <el-form-item label="客群编号" prop="id">
  28. <el-input v-model="form.id" disabled placeholder="系统自动生成" suffix-icon="el-icon-circle-close" />
  29. </el-form-item>
  30. </el-col>
  31. <el-col :span="24">
  32. <el-form-item label="客群描述" prop="description">
  33. <el-input
  34. v-model="form.description"
  35. type="textarea"
  36. :rows="4"
  37. placeholder="请输入"
  38. maxlength="200"
  39. show-word-limit
  40. />
  41. </el-form-item>
  42. </el-col>
  43. </el-row>
  44. <el-row :gutter="32">
  45. <el-col :span="12">
  46. <el-form-item label="客群任务开始日期" prop="startDate">
  47. <el-date-picker
  48. v-model="form.startDate"
  49. type="date"
  50. placeholder="请选择日期"
  51. value-format="yyyy-MM-dd"
  52. style="width: 100%"
  53. />
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="12">
  57. <el-form-item label="客群任务结束日期" prop="endDate">
  58. <el-date-picker
  59. v-model="form.endDate"
  60. type="date"
  61. placeholder="请选择日期"
  62. value-format="yyyy-MM-dd"
  63. :picker-options="endDateOptions"
  64. style="width: 100%"
  65. />
  66. </el-form-item>
  67. </el-col>
  68. </el-row>
  69. </el-form>
  70. </div>
  71. <!-- Step 2: 规则组信息 -->
  72. <div v-show="step === 1" class="section">
  73. <div class="section-title">规则组配置</div>
  74. <el-form label-width="140px" style="max-width: 1000px; margin: 0 auto 16px">
  75. <el-form-item label="规则组间运算逻辑" required>
  76. <el-select v-model="form.ruleGroupLogic" placeholder="请选择" style="width: 320px">
  77. <el-option label="and/且" value="AND" />
  78. <el-option label="or/或" value="OR" />
  79. </el-select>
  80. </el-form-item>
  81. </el-form>
  82. <el-table :data="form.ruleGroups" border style="width: 100%" empty-text="暂无规则组,请点击下方加号新增">
  83. <el-table-column prop="id" label="规则组编号" width="170" align="center" />
  84. <el-table-column prop="name" label="规则组名称" min-width="160" show-overflow-tooltip />
  85. <el-table-column prop="description" label="规则组描述" min-width="200" show-overflow-tooltip />
  86. <el-table-column label="规则组内逻辑" width="120" align="center">
  87. <template slot-scope="scope">{{ scope.row.logic === 'AND' ? 'and/且' : 'or/或' }}</template>
  88. </el-table-column>
  89. <el-table-column prop="ruleCount" label="规则个数" width="90" align="center" />
  90. <el-table-column label="操作" width="90" align="center">
  91. <template slot-scope="scope">
  92. <el-button
  93. type="danger" circle size="mini" icon="el-icon-delete" title="删除"
  94. @click="removeRuleGroup(scope.$index)"
  95. />
  96. </template>
  97. </el-table-column>
  98. </el-table>
  99. <div class="add-row">
  100. <el-button type="primary" circle icon="el-icon-plus" @click="openAddDialog" />
  101. </div>
  102. </div>
  103. <div class="footer">
  104. <el-button v-if="step === 0" @click="handleCancel">取消</el-button>
  105. <el-button v-if="step === 1" @click="step = 0">上一步</el-button>
  106. <el-button v-if="step === 0" type="primary" @click="handleNext">下一步</el-button>
  107. <el-button v-if="step === 1" type="primary" @click="handleSave">完成</el-button>
  108. </div>
  109. </el-card>
  110. <add-rule-group-dialog
  111. :visible.sync="dialogVisible"
  112. :exclude-ids="selectedRuleGroupIds"
  113. @save="onRuleGroupAdded"
  114. />
  115. </div>
  116. </template>
  117. <script>
  118. import crowdTaskStore from '@/store/crowdTaskStore'
  119. import AddRuleGroupDialog from '@/components/crowdTask/AddRuleGroupDialog.vue'
  120. const emptyForm = () => ({
  121. name: '',
  122. id: '',
  123. description: '',
  124. startDate: '',
  125. endDate: '',
  126. ruleGroupLogic: '',
  127. ruleGroups: []
  128. })
  129. export default {
  130. name: 'CrowdTaskEdit',
  131. components: { AddRuleGroupDialog },
  132. data() {
  133. return {
  134. step: 0,
  135. form: emptyForm(),
  136. current: null,
  137. dialogVisible: false,
  138. rules: {
  139. name: [{ required: true, message: '请输入客群名称', trigger: 'blur' }],
  140. description: [{ required: true, message: '请输入客群描述', trigger: 'blur' }],
  141. startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
  142. endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }]
  143. }
  144. }
  145. },
  146. computed: {
  147. isEdit() {
  148. return this.$route.name === 'CrowdTaskEdit'
  149. },
  150. isCopy() {
  151. return this.$route.name === 'CrowdTaskCopy'
  152. },
  153. pageTitle() {
  154. if (this.isEdit) return '编辑客群任务'
  155. if (this.isCopy) return '复制客群任务'
  156. return '新建客群任务'
  157. },
  158. selectedRuleGroupIds() {
  159. return this.form.ruleGroups.map((r) => r.id)
  160. },
  161. endDateOptions() {
  162. const start = this.form.startDate
  163. return {
  164. disabledDate(d) {
  165. if (!start) return false
  166. return d.getTime() < new Date(start).getTime()
  167. }
  168. }
  169. }
  170. },
  171. created() {
  172. if (this.isEdit || this.isCopy) {
  173. const source = crowdTaskStore.getById(this.$route.params.id)
  174. if (!source) {
  175. this.$message.error('任务不存在')
  176. this.$router.replace('/customization/hsbc/crowd-tasks')
  177. return
  178. }
  179. this.current = source
  180. this.form = {
  181. name: this.isCopy ? source.name + '-副本' : source.name,
  182. id: this.isCopy ? '复制保存后生成' : source.id,
  183. description: source.description,
  184. startDate: source.startDate,
  185. endDate: source.endDate,
  186. ruleGroupLogic: source.ruleGroupLogic,
  187. ruleGroups: JSON.parse(JSON.stringify(source.ruleGroups || []))
  188. }
  189. } else {
  190. this.form.id = '保存后系统自动生成'
  191. }
  192. },
  193. methods: {
  194. handleNext() {
  195. this.$refs.baseForm.validate((ok) => {
  196. if (!ok) return
  197. if (this.form.startDate && this.form.endDate && this.form.endDate < this.form.startDate) {
  198. this.$message.error('结束日期不能早于开始日期')
  199. return
  200. }
  201. this.step = 1
  202. })
  203. },
  204. openAddDialog() {
  205. this.dialogVisible = true
  206. },
  207. onRuleGroupAdded(rg) {
  208. this.form.ruleGroups.push(rg)
  209. this.$message.success('已添加规则组')
  210. },
  211. removeRuleGroup(idx) {
  212. this.$confirm('确定移除该规则组吗?', '提示', {
  213. confirmButtonText: '移除', cancelButtonText: '取消', type: 'warning'
  214. }).then(() => {
  215. this.form.ruleGroups.splice(idx, 1)
  216. }).catch(() => {})
  217. },
  218. handleSave() {
  219. if (!this.form.ruleGroupLogic) {
  220. this.$message.error('请选择规则组间运算逻辑')
  221. return
  222. }
  223. if (this.form.ruleGroups.length === 0) {
  224. this.$message.error('请至少添加一条规则组')
  225. return
  226. }
  227. const payload = { ...this.form }
  228. if (this.isEdit) {
  229. // 校验状态下的编辑需回退到新建并重置运行信息
  230. const resetRun = this.current.status === 'verifying'
  231. crowdTaskStore.update(this.current.id, payload, { resetRun })
  232. this.$message.success(resetRun ? '保存成功,任务回退至新建状态,需重新运行' : '保存成功')
  233. } else {
  234. crowdTaskStore.create(payload)
  235. this.$message.success(this.isCopy ? '复制成功' : '创建成功')
  236. }
  237. this.$router.push('/customization/hsbc/crowd-tasks')
  238. },
  239. handleCancel() {
  240. this.$router.push('/customization/hsbc/crowd-tasks')
  241. }
  242. }
  243. }
  244. </script>
  245. <style scoped>
  246. .crowd-task-edit { padding: 0; }
  247. .header { display: flex; align-items: center; justify-content: center; }
  248. .title { font-size: 16px; font-weight: 600; color: #409EFF; }
  249. .steps { margin: 16px 0 32px; }
  250. .section { margin-bottom: 24px; }
  251. .section-title {
  252. font-size: 14px; font-weight: 600; color: #303133;
  253. background: #f5f7fa; padding: 10px 14px; border-radius: 4px;
  254. margin-bottom: 16px;
  255. }
  256. .add-row { display: flex; padding: 16px 0; }
  257. .footer { text-align: center; margin-top: 24px; padding-top: 16px; border-top: 1px solid #ebeef5; }
  258. .footer .el-button { min-width: 100px; }
  259. </style>