检查项目故事

This commit is contained in:
zhonghua.li
2026-04-06 13:54:43 +08:00
parent d7007cea59
commit 96d0f2aa7d
3 changed files with 547 additions and 8 deletions

View File

@@ -0,0 +1,76 @@
import request from '@/utils/request'
/**
* 恋爱检查项子表 love_check_item_child
* LoveCheckItemChildController@RequestMapping("/api/loveCheckItemChild")
* 本项目的 axios baseURL 为 /api故此处 url 使用 /loveCheckItemChild/...(最终请求 /api/loveCheckItemChild/...
*
* 若 Spring 已配置 server.servlet.context-path=/api且类上仍为 @RequestMapping("/api/loveCheckItemChild")
* 实际路径可能为 /api/api/loveCheckItemChild/...可设环境变量VUE_APP_LOVE_CHECK_ITEM_CHILD_SEGMENT=api/loveCheckItemChild无首尾斜杠
*/
function lcChildUrl(action) {
const seg = (process.env.VUE_APP_LOVE_CHECK_ITEM_CHILD_SEGMENT || 'loveCheckItemChild').replace(/^\/+|\/+$/g, '')
return seg.startsWith('api/') ? `${seg}/${action}` : `/${seg}/${action}`
}
/** GET /listcurrent、size、parentId、projectName、scenario、createStartTime、createEndTime、updateStartTime、updateEndTime */
export function fetchInspectionStoryList(params) {
return request({
url: lcChildUrl('list'),
method: 'get',
params: {
current: params.page || 1,
size: params.limit || 10,
parentId: params.parentId,
projectName: params.projectName,
scenario: params.scenario,
createStartTime: params.createStartTime,
createEndTime: params.createEndTime,
updateStartTime: params.updateStartTime,
updateEndTime: params.updateEndTime
}
})
}
/** GET /get/{id} */
export function getInspectionStoryById(id) {
return request({
url: lcChildUrl(`get/${id}`),
method: 'get'
})
}
/** POST /add */
export function addInspectionStory(data) {
return request({
url: lcChildUrl('add'),
method: 'post',
data
})
}
/** PUT /update */
export function updateInspectionStory(data) {
return request({
url: lcChildUrl('update'),
method: 'put',
data
})
}
/** DELETE /delete/{id} */
export function deleteInspectionStory(id) {
return request({
url: lcChildUrl(`delete/${id}`),
method: 'delete'
})
}
/** DELETE /batchDelete请求体为 id 字符串列表 */
export function batchDeleteInspectionStory(ids) {
return request({
url: lcChildUrl('batchDelete'),
method: 'delete',
data: ids
})
}

View File

@@ -1,20 +1,466 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card shadow="never"> <div class="filter-container">
<div class="page-title">喜喜检查故事</div> <el-input
</el-card> v-model="listQuery.projectName"
placeholder="项目名称(模糊)"
style="width: 170px;"
class="filter-item"
clearable
@keyup.enter.native="handleFilter"
/>
<el-input
v-model="listQuery.scenario"
placeholder="场景(模糊)"
style="width: 140px;"
class="filter-item"
clearable
@keyup.enter.native="handleFilter"
/>
<el-input
v-model="listQuery.parentId"
placeholder="父级ID精确"
style="width: 200px;"
class="filter-item"
clearable
@keyup.enter.native="handleFilter"
/>
<el-date-picker
v-model="createTimeRange"
type="datetimerange"
range-separator=""
start-placeholder="创建开始"
end-placeholder="创建结束"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
class="filter-item filter-daterange"
clearable
/>
<el-date-picker
v-model="updateTimeRange"
type="datetimerange"
range-separator=""
start-placeholder="修改开始"
end-placeholder="修改结束"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
class="filter-item filter-daterange"
clearable
/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
查询
</el-button>
<el-button class="filter-item" icon="el-icon-refresh-left" @click="resetFilter">
重置
</el-button>
<el-button class="filter-item" type="primary" icon="el-icon-plus" @click="handleCreate">
新增
</el-button>
</div>
<el-table
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
style="width: 100%;"
>
<el-table-column label="项目名称" prop="projectName" min-width="120" show-overflow-tooltip />
<el-table-column label="父级ID" prop="parentId" min-width="110" show-overflow-tooltip />
<el-table-column label="场景" prop="scenario" min-width="100" show-overflow-tooltip />
<el-table-column label="话术" prop="talkScript" min-width="140" show-overflow-tooltip />
<el-table-column label="引导故事" prop="guideStory" min-width="120" show-overflow-tooltip />
<el-table-column label="加分标准" prop="bonusStandard" min-width="100" show-overflow-tooltip />
<el-table-column label="减分标准" prop="deductionStandard" min-width="100" show-overflow-tooltip />
<el-table-column label="备注" prop="remark" min-width="90" show-overflow-tooltip />
<el-table-column label="创建时间" width="152" align="center">
<template slot-scope="{ row }">
<span>{{ formatDateTime(row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="修改时间" width="152" align="center">
<template slot-scope="{ row }">
<span>{{ formatDateTime(row.updateTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" fixed="right">
<template slot-scope="{ row }">
<el-button type="primary" size="mini" @click="handleUpdate(row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList"
/>
<el-dialog
:title="textMap[dialogStatus]"
:visible.sync="dialogFormVisible"
width="720px"
top="5vh"
@close="onDialogClose"
>
<el-form ref="dataForm" :rules="rules" :model="temp" label-width="100px" class="story-form">
<el-form-item label="父级ID" prop="parentId">
<el-input v-model="temp.parentId" placeholder="关联主检查项 UUID" clearable />
</el-form-item>
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="temp.projectName" placeholder="项目名称" maxlength="200" show-word-limit />
</el-form-item>
<el-form-item label="场景" prop="scenario">
<el-input v-model="temp.scenario" placeholder="场景" maxlength="200" />
</el-form-item>
<el-form-item label="话术" prop="talkScript">
<el-input v-model="temp.talkScript" type="textarea" :rows="3" placeholder="话术" maxlength="2000" show-word-limit />
</el-form-item>
<el-form-item label="引导故事" prop="guideStory">
<el-input v-model="temp.guideStory" type="textarea" :rows="3" placeholder="引导故事" maxlength="2000" show-word-limit />
</el-form-item>
<el-form-item label="加分标准" prop="bonusStandard">
<el-input v-model="temp.bonusStandard" type="textarea" :rows="2" placeholder="加分标准" maxlength="1000" show-word-limit />
</el-form-item>
<el-form-item label="减分标准" prop="deductionStandard">
<el-input v-model="temp.deductionStandard" type="textarea" :rows="2" placeholder="减分标准" maxlength="1000" show-word-limit />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="temp.remark" type="textarea" :rows="2" placeholder="备注" maxlength="500" show-word-limit />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false"> </el-button>
<el-button type="primary" @click="dialogStatus === 'create' ? createData() : updateData()"> </el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import {
fetchInspectionStoryList,
getInspectionStoryById,
addInspectionStory,
updateInspectionStory,
deleteInspectionStory
} from '@/api/xixi-inspection-story'
import waves from '@/directive/waves'
import Pagination from '@/components/Pagination'
const emptyForm = () => ({
id: undefined,
parentId: '',
projectName: '',
scenario: '',
talkScript: '',
guideStory: '',
bonusStandard: '',
deductionStandard: '',
remark: ''
})
export default { export default {
name: 'XixiInspectionStory' name: 'XixiInspectionStory',
components: { Pagination },
directives: { waves },
data() {
return {
list: [],
total: 0,
listLoading: false,
listQuery: {
page: 1,
limit: 10,
projectName: undefined,
scenario: undefined,
parentId: undefined
},
createTimeRange: null,
updateTimeRange: null,
temp: emptyForm(),
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: '编辑场景话术',
create: '新增场景话术'
},
rules: {
parentId: [{ required: true, message: '请输入父级ID', trigger: 'blur' }],
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }]
}
}
},
created() {
const q = this.$route.query
if (q.openCreate === '1' && q.parentId) {
this.listQuery.parentId = String(q.parentId)
}
this.getList()
},
mounted() {
this.applyOpenCreateFromQuery(this.$route, false)
},
watch: {
'$route'(to) {
if (to.name === 'XixiInspectionStory') {
this.applyOpenCreateFromQuery(to, true)
}
}
},
methods: {
applyOpenCreateFromQuery(route, fetchList) {
const q = route.query
if (q.openCreate !== '1' || !q.parentId) return
this.listQuery.parentId = String(q.parentId)
this.listQuery.page = 1
if (fetchList) {
this.getList()
}
this.resetTemp()
this.temp.parentId = String(q.parentId)
this.temp.projectName = q.projectName ? String(q.projectName) : ''
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs.dataForm && this.$refs.dataForm.clearValidate()
})
},
formatDateTime(val) {
if (!val) return '—'
const d = new Date(val)
if (Number.isNaN(d.getTime())) return String(val)
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const h = String(d.getHours()).padStart(2, '0')
const min = String(d.getMinutes()).padStart(2, '0')
return `${y}-${m}-${day} ${h}:${min}`
},
parseListResponse(response) {
const raw = response.data
const rows = Array.isArray(raw)
? raw
: (raw && (raw.records || raw.data)) || []
const total =
response.total != null
? response.total
: (raw && !Array.isArray(raw) && raw.total != null ? raw.total : rows.length)
return { rows, total: Number(total) || 0 }
},
buildListParams() {
const params = {
page: this.listQuery.page,
limit: this.listQuery.limit,
projectName: this.listQuery.projectName,
scenario: this.listQuery.scenario,
parentId: this.listQuery.parentId
}
if (this.createTimeRange && this.createTimeRange.length === 2) {
params.createStartTime = this.createTimeRange[0]
params.createEndTime = this.createTimeRange[1]
}
if (this.updateTimeRange && this.updateTimeRange.length === 2) {
params.updateStartTime = this.updateTimeRange[0]
params.updateEndTime = this.updateTimeRange[1]
}
Object.keys(params).forEach((key) => {
const v = params[key]
if (v === '' || v === null || v === undefined) {
delete params[key]
}
})
return params
},
getList() {
this.listLoading = true
const params = this.buildListParams()
fetchInspectionStoryList(params)
.then((response) => {
if (response && (response.code === 20000 || response.code === 200)) {
const { rows, total } = this.parseListResponse(response)
this.list = rows
this.total = total
} else {
this.$message.error(response?.message || '获取列表失败')
this.list = []
this.total = 0
}
this.listLoading = false
})
.catch(() => {
this.list = []
this.total = 0
this.listLoading = false
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
resetFilter() {
this.listQuery = {
page: 1,
limit: this.listQuery.limit,
projectName: undefined,
scenario: undefined,
parentId: undefined
}
this.createTimeRange = null
this.updateTimeRange = null
this.getList()
},
resetTemp() {
this.temp = emptyForm()
},
buildSubmitPayload() {
const trim = (s) => (s || '').trim()
const payload = {
parentId: trim(this.temp.parentId) || null,
projectName: trim(this.temp.projectName),
scenario: trim(this.temp.scenario) || null,
talkScript: trim(this.temp.talkScript) || null,
guideStory: trim(this.temp.guideStory) || null,
bonusStandard: trim(this.temp.bonusStandard) || null,
deductionStandard: trim(this.temp.deductionStandard) || null,
remark: trim(this.temp.remark) || null
}
if (this.dialogStatus === 'update' && this.temp.id) {
payload.id = this.temp.id
}
return payload
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs.dataForm && this.$refs.dataForm.clearValidate()
})
},
mapRowToTemp(d) {
return {
id: d.id,
parentId: d.parentId || '',
projectName: d.projectName || '',
scenario: d.scenario || '',
talkScript: d.talkScript || '',
guideStory: d.guideStory || '',
bonusStandard: d.bonusStandard || '',
deductionStandard: d.deductionStandard || '',
remark: d.remark || ''
}
},
handleUpdate(row) {
this.listLoading = true
getInspectionStoryById(row.id)
.then((response) => {
if (response && (response.code === 20000 || response.code === 200) && response.data) {
this.temp = this.mapRowToTemp(response.data)
} else {
this.temp = this.mapRowToTemp(row)
}
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs.dataForm && this.$refs.dataForm.clearValidate()
})
})
.catch(() => {
this.temp = this.mapRowToTemp(row)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs.dataForm && this.$refs.dataForm.clearValidate()
})
})
.finally(() => {
this.listLoading = false
})
},
createData() {
this.$refs.dataForm.validate((valid) => {
if (!valid) return
addInspectionStory(this.buildSubmitPayload())
.then((response) => {
if (response && (response.code === 20000 || response.code === 200)) {
this.$message.success(response.message || '新增成功')
this.dialogFormVisible = false
this.getList()
} else {
this.$message.error(response?.message || '新增失败')
}
})
.catch(() => {})
})
},
updateData() {
this.$refs.dataForm.validate((valid) => {
if (!valid) return
updateInspectionStory(this.buildSubmitPayload())
.then((response) => {
if (response && (response.code === 20000 || response.code === 200)) {
this.$message.success(response.message || '更新成功')
this.dialogFormVisible = false
this.getList()
} else {
this.$message.error(response?.message || '更新失败')
}
})
.catch(() => {})
})
},
handleDelete(row) {
this.$confirm(`确定删除「${row.projectName || row.scenario || row.id}」吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
deleteInspectionStory(row.id).then((response) => {
if (response && (response.code === 20000 || response.code === 200)) {
this.$message.success(response.message || '删除成功')
this.getList()
} else {
this.$message.error(response?.message || '删除失败')
}
})
})
.catch(() => {})
},
onDialogClose() {
this.resetTemp()
this.$nextTick(() => {
if (this.$refs.dataForm) {
this.$refs.dataForm.clearValidate()
}
})
}
}
} }
</script> </script>
<style scoped> <style scoped>
.page-title { .filter-container {
font-size: 16px; padding-bottom: 10px;
color: #303133; }
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
margin-right: 10px;
}
.filter-daterange {
width: 340px;
}
.dialog-footer {
text-align: right;
}
.story-form .el-textarea {
max-width: 100%;
} }
</style> </style>

View File

@@ -105,8 +105,11 @@
<span>{{ formatDateTime(row.updateTime) }}</span> <span>{{ formatDateTime(row.updateTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="160" fixed="right"> <el-table-column label="操作" align="center" width="250" fixed="right">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-button type="success" size="mini" @click="handleAddStory(row)">
新增故事
</el-button>
<el-button type="primary" size="mini" @click="handleUpdate(row)"> <el-button type="primary" size="mini" @click="handleUpdate(row)">
编辑 编辑
</el-button> </el-button>
@@ -345,6 +348,20 @@ export default {
this.$refs.dataForm && this.$refs.dataForm.clearValidate() this.$refs.dataForm && this.$refs.dataForm.clearValidate()
}) })
}, },
handleAddStory(row) {
if (!row || row.id == null || row.id === '') {
this.$message.warning('无法获取检查项 ID')
return
}
this.$router.push({
name: 'XixiInspectionStory',
query: {
parentId: String(row.id),
projectName: row.projectName || '',
openCreate: '1'
}
})
},
handleUpdate(row) { handleUpdate(row) {
this.listLoading = true this.listLoading = true
getXixiInspectionById(row.id) getXixiInspectionById(row.id)