8/31 dev 权限,sse,账单,bug

This commit is contained in:
Zy
2026-08-31 08:09:28 +08:00
parent bfdfa05cd7
commit e4417f35b1
82 changed files with 2327 additions and 1644 deletions

View File

@@ -2,19 +2,24 @@
<div class="p-2 h-full flex flex-col">
<PageHeader></PageHeader>
<el-card class="mt-20px" style="min-height: 80px">
<div class="tabs">
<div class="tab-item" :class="{ 'active': activeTab == 'preview' }" @click="handleTabClick('preview')">
<div class="tab-content">问卷预览</div>
<div class="flex justify-between">
<div class="tabs">
<div :class="{ 'active': activeTab == 'preview' }" class="tab-item" @click="handleTabClick('preview')">
<div class="tab-content">问卷预览</div>
</div>
<div :class="{ 'active': activeTab == 'detail' }" class="tab-item" @click="handleTabClick('detail')">
<div class="tab-content">调查详情</div>
</div>
</div>
<div class="tab-item" :class="{ 'active': activeTab == 'detail' }" @click="handleTabClick('detail')">
<div class="tab-content">调查详情</div>
<div class="tabs">
<el-button @click="handleBack">返回</el-button>
</div>
</div>
</el-card>
<div class="flex-1 mt-20px">
<el-card v-if="activeTab == 'preview'">
<div class="container_box flex-1">
<div class="contentBox h-full" v-loading="viewLoading">
<div v-loading="viewLoading" class="contentBox h-full">
<div class="detail-header">
<h2>{{ viewData.title }}</h2>
<p style="color: #666">{{ viewData.description }}</p>
@@ -24,7 +29,7 @@
<div v-for="(q, index) in viewData.content" :key="q.cid" class="question-item">
<div class="title">
<span style="font-weight: bold">{{ index + 1 }}. {{ q.title }}</span>
<span style="color: #f56c6c; margin-left: 5px" v-if="q.required">*</span>
<span v-if="q.required" style="color: #f56c6c; margin-left: 5px">*</span>
</div>
<div class="type-tag">
<el-tag size="small">{{ getComponentLabel(q.type) }}</el-tag>
@@ -42,7 +47,7 @@
<el-input disabled placeholder="用户输入区域" />
</div>
<div v-else-if="q.type === 'textarea'" class="input-placeholder">
<el-input disabled type="textarea" placeholder="用户输入区域" />
<el-input disabled placeholder="用户输入区域" type="textarea" />
</div>
</div>
</div>
@@ -56,25 +61,25 @@
<el-card v-else-if="activeTab == 'detail'">
<div>
<el-table :data="list" style="width: 100%">
<el-table-column prop="answerName" label="答题人" />
<el-table-column prop="type" label="提交时间" />
<el-table-column prop="options" label="操作">
<el-table-column label="答题人" prop="answerName" />
<el-table-column label="提交时间" prop="type" />
<el-table-column label="操作" prop="options">
<template #default="scope">
<el-button type="primary" link @click="handleGetMain(scope.row.id)">查看详情</el-button>
<el-button link type="primary" @click="handleGetMain(scope.row.id)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum"
:total="total"
@pagination="getList"
/>
</div>
</el-card>
</div>
<el-dialog :title="dialog.title" v-model="dialog.visible" width="680px" append-to-body>
<el-dialog v-model="dialog.visible" :title="dialog.title" append-to-body width="680px">
<el-form ref="houseRentalFormRef" :model="form.content" label-width="120px">
<div class="detail-header">
<h2>{{ viewData.title }}</h2>
@@ -85,7 +90,7 @@
<div v-for="(q, index) in form.content" :key="q.cid" class="question-item">
<div class="title">
<span style="font-weight: bold">{{ index + 1 }}. {{ q.title }}</span>
<span style="color: #f56c6c; margin-left: 5px" v-if="q.required">*</span>
<span v-if="q.required" style="color: #f56c6c; margin-left: 5px">*</span>
</div>
<div class="type-tag">
<el-tag size="small">{{ getComponentLabel(q.type) }}</el-tag>
@@ -96,7 +101,7 @@
<el-radio-group v-model="q.value as string">
<div>
<div v-for="(opt, idx) in q.options" :key="idx">
<el-radio disabled :value="opt.label">{{ opt.label }}</el-radio>
<el-radio :value="opt.label" disabled>{{ opt.label }}</el-radio>
</div>
</div>
</el-radio-group>
@@ -104,16 +109,16 @@
<div v-if="q.type === 'checkbox'" class="options">
<el-checkbox-group v-model="q.value as string[]">
<div v-for="(opt, idx) in q.options" :key="idx">
<el-checkbox disabled :label="opt.label" :value="opt.label" />
<el-checkbox :label="opt.label" :value="opt.label" disabled />
</div>
</el-checkbox-group>
</div>
<!-- 填空题/多行文本展示 -->
<div v-else-if="q.type === 'input'" class="input-placeholder">
<el-input disabled placeholder="" v-model="q.value as string" />
<el-input v-model="q.value as string" disabled placeholder="" />
</div>
<div v-else-if="q.type === 'textarea'" class="input-placeholder">
<el-input disabled type="textarea" placeholder="" v-model="q.value as string" />
<el-input v-model="q.value as string" disabled placeholder="" type="textarea" />
</div>
</div>
</div>
@@ -126,7 +131,7 @@
</div>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import { getQuestionnaire, getQuestionnaireAnswer, getQuestionnaireAnswerMain } from '@/api/system/Questionnaire';
import { QuestionComponentItem } from '@/api/system/Questionnaire/type';
import { ref } from 'vue';
@@ -198,6 +203,10 @@ function init() {
});
}
init();
const router = useRouter();
function handleBack() {
router.back();
}
const dialog = reactive<DialogOption>({
visible: false,
@@ -242,7 +251,7 @@ function handleGetMain(id: string) {
}
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
.tabs {
display: flex;
flex-direction: row;

View File

@@ -2,7 +2,7 @@
<div class="AddBuildingBox">
<PageHeader :title="userid ? '编辑问卷' : '添加问卷'"></PageHeader>
<div class="AddBuildingBody">
<el-form class="formBody" label-position="right" label-width="130px">
<el-form :rules="rules" class="formBody" label-position="right" label-width="130px">
<el-card>
<template #header>
<span>基本信息</span>
@@ -12,31 +12,32 @@
<el-form-item label="参与范围" prop="cardName">
<div class="flex flex-items-center">
<el-radio-group v-model="form.scope">
<el-radio v-for="item in com_questionnaire_scope" :value="item.value" :label="item.label" :key="item.value"></el-radio>
<el-radio v-for="item in com_questionnaire_scope" :key="item.value" :label="item.label" :value="item.value"></el-radio>
</el-radio-group>
<Holder v-if="form.scope === '1'" returnvalue="id" ref="HolderRef" :isMultiple="true" :userid="checkoutUses" @change="handleSelect">
<Holder v-if="form.scope === '1'" ref="HolderRef" :isMultiple="true" :userid="checkoutUses" returnvalue="id" @change="handleSelect">
<template #default>
<el-button type="primary" link @click="OpenUseTablesFun">选择业主</el-button>
<el-button link type="primary" @click="OpenUseTablesFun">选择业主</el-button>
</template>
</Holder>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="时间范围" prop="timeData">
<el-form-item label="时间范围" prop="startTime">
<el-date-picker
v-model="timeData"
style="min-width: 380px"
value-format="YYYY-MM-DD HH:mm:ss"
:disabled-date="handleDate"
end-placeholder="结束日期时间"
format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
placeholder="请选择问卷时间范围"
range-separator="到"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
placeholder="请选择问卷时间范围"
style="min-width: 380px"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
@update:model-value="handleModelDate"
/>
</el-form-item>
</el-col>
@@ -44,7 +45,7 @@
<el-row>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input :rows="5" maxlength="200" show-word-limit type="textarea" placeholder="请输入" v-model="form.remark"></el-input>
<el-input v-model="form.remark" :rows="5" maxlength="200" placeholder="请输入" show-word-limit type="textarea"></el-input>
</el-form-item>
</el-col>
</el-row>
@@ -53,14 +54,14 @@
<template #header>
<span>问卷题目</span>
</template>
<QuestionnaireEdit ref="questionnaireEditRef" :initial-data="editData" @cancel="handleCancel" @save="handleSave" @publish="handlePublish" />
<QuestionnaireEdit ref="questionnaireEditRef" :initial-data="editData" @cancel="handleCancel" @publish="handlePublish" @save="handleSave" />
</el-card>
</el-form>
</div>
</div>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import Holder from '@/components/Holder/index.vue';
import QuestionnaireEdit from './components/QuestionnaireEdit.vue';
@@ -77,9 +78,22 @@ const route = useRoute();
const form = ref({
scope: '0',
residents: '',
remark: ''
remark: '',
startTime: '',
endTime: ''
});
const rules = ref({
startTime: [{ required: true, message: '请选择日期范围', trigger: 'blur' }]
});
const timeData = ref([]);
function handleDate(data: string) {
const date = new Date();
return date.getTime() > new Date(data).getTime();
}
function handleModelDate(date: string) {
form.value.startTime = date[0];
form.value.endTime = date[1];
}
// ! 路由参数 --------------------------------------------------------------------------------
// 打开
const HolderRef = ref<InstanceType<typeof Holder>>();
@@ -126,7 +140,9 @@ function handleEdit(id: string | number) {
form.value = {
scope: res.data.scope,
residents: res.data.residents,
remark: res.data.remark
remark: res.data.remark,
startTime: '',
endTime: ''
};
checkoutUses.value = res.data.residents
.split(',')
@@ -138,6 +154,9 @@ function handleEdit(id: string | number) {
// 保存草稿
async function handleSave(data: QuestionComponentnaireForm) {
if (timeData.value.length <= 0) {
return ElMessage.warning('请选择问卷时间范围');
}
try {
// 父组件自己调用接口提交
if (userid.value !== null) {
@@ -169,6 +188,9 @@ async function handleSave(data: QuestionComponentnaireForm) {
// 发布问卷
async function handlePublish(data: QuestionComponentnaireForm) {
if (timeData.value.length <= 0) {
return ElMessage.warning('请选择问卷时间范围');
}
try {
if (userid.value !== null) {
await updateQuestionnaire({
@@ -202,7 +224,7 @@ function handleCancel() {
}
</script>
<style scoped lang="scss">
<style lang="scss" scoped>
.AddBuildingBox {
padding: 15px;
height: 100%;

View File

@@ -4,9 +4,9 @@
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" @submit.prevent="handleQuery" :inline="true">
<el-form ref="queryFormRef" :inline="true" :model="queryParams" @submit.prevent="handleQuery">
<el-form-item label="问卷标题" prop="title">
<el-input maxlength="20" v-model="queryParams.title" placeholder="请输入问卷标题" clearable @keyup.enter="handleQuery" />
<el-input v-model="queryParams.title" clearable maxlength="20" placeholder="请输入问卷标题" @keyup.enter="handleQuery" />
</el-form-item>
<!-- <el-form-item label="参与范围" prop="scope">
<el-input v-model="queryParams.scope" placeholder="请输入参与范围 0全体业主 1部分业主" clearable @keyup.enter="handleQuery" />
@@ -26,8 +26,8 @@
:disable-delete="multiple"
:disable-edit="single"
:show-add="checkPermi(['questionnaire:questionnaire:add'])"
:show-edit="checkPermi(['questionnaire:questionnaire:edit'])"
:show-delete="checkPermi(['questionnaire:questionnaire:remove'])"
:show-edit="checkPermi(['questionnaire:questionnaire:edit'])"
@update:add="handleAdd"
@update:edit="handleUpdate()"
@update:delete="handleDelete()"
@@ -35,36 +35,50 @@
</el-row>
</template>
<el-table v-loading="loading" border :data="questionnaireList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="问卷标题" align="center" prop="title" />
<el-table-column label="问卷描述" align="center" prop="description" />
<el-table-column label="状态" align="center" prop="status">
<el-table v-loading="loading" :data="questionnaireList" border @selection-change="handleSelectionChange">
<el-table-column align="center" type="selection" width="55" />
<el-table-column align="center" label="小区" prop="villageName" />
<el-table-column align="center" label="问卷标题" prop="title" />
<el-table-column align="center" label="问卷描述" prop="description" />
<el-table-column align="center" label="状态" prop="status">
<template #default="scope">
<dict-tag :options="com_questionnaire_status" :value="scope.row.status"></dict-tag>
</template>
</el-table-column>
<el-table-column label="参与范围" align="center" prop="scope">
<el-table-column align="center" label="参与范围" prop="scope">
<template #default="scope">
<dict-tag :options="com_questionnaire_scope" :value="scope.row.scope"></dict-tag>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" fixed="right" width="200">
<el-table-column align="center" label="问题数量" prop="questionCount" />
<el-table-column align="center" label="发布时间" prop="updateTime" />
<el-table-column align="center" label="结束时间" prop="endTime" />
<el-table-column align="center" label="已答数量" prop="answeredCount" />
<el-table-column align="center" label="未答数量" prop="unansweredCount" />
<el-table-column align="center" label="备注" prop="remark" />
<el-table-column align="center" fixed="right" label="操作" width="200">
<template #default="scope">
<el-button link type="primary" @click="handleView(scope.row)" v-has-permi="['questionnaire:questionnaire:query']">查看</el-button>
<el-button link type="primary" @click="handleUpdate(scope.row)" v-has-permi="['questionnaire:questionnaire:edit']">编辑</el-button>
<el-button link type="primary" @click="handleDelete(scope.row)" v-has-permi="['questionnaire:questionnaire:remove']">删除</el-button>
<el-button v-has-permi="['questionnaire:questionnaire:query']" link type="primary" @click="handleView(scope.row)">查看</el-button>
<el-button
v-if="scope.row.status === '0'"
v-has-permi="['questionnaire:questionnaire:edit']"
link
type="primary"
@click="handleUpdate(scope.row)"
>编辑</el-button
>
<el-button v-has-permi="['questionnaire:questionnaire:remove']" link type="primary" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<Pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<Pagination v-show="total > 0" v-model:limit="queryParams.pageSize" v-model:page="queryParams.pageNum" :total="total" @pagination="getList" />
</el-card>
</div>
</template>
<script setup name="Questionnaire" lang="ts">
<script lang="ts" name="Questionnaire" setup>
import Pagination from '@/components/Pagination/index.vue';
import pageHeader from '@/components/Pageheader/index.vue';
import RightToolbar from '@/components/RightToolbar/index.vue';
@@ -72,13 +86,17 @@ import DictTag from '@/components/DictTag/index.vue';
import { listQuestionnaire, delQuestionnaire, addQuestionnaire, updateQuestionnaire } from '@/api/system/Questionnaire';
import { QuestionnaireVO, QuestionnaireQuery, QuestionnaireForm } from '@/api/system/Questionnaire/type';
import { checkPermi } from '@/utils/permission';
import type { communitylist_rows_type } from '@/api/system/community/type';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_questionnaire_scope } = toRefs<any>(proxy?.useDict('com_questionnaire_scope'));
const { com_questionnaire_status } = toRefs<any>(proxy?.useDict('com_questionnaire_status'));
const questionnaireList = ref<QuestionnaireVO[]>([]);
type QuestionVoList = QuestionnaireVO & {
contentLength?: number;
villageName?: string;
};
const questionnaireList = ref<QuestionVoList[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
@@ -125,9 +143,15 @@ const { queryParams, form, rules } = toRefs(data);
/** 查询问卷调查列表 */
const getList = async () => {
loading.value = true;
const villageInfo = localStorage.getItem('villageInfo') as string;
listQuestionnaire(queryParams.value)
.then((res) => {
questionnaireList.value = res.rows;
questionnaireList.value.forEach((item) => {
item.contentLength = JSON.parse(item.content as string).length ?? 0;
item.villageName = JSON.parse(villageInfo).villageName;
return item;
});
total.value = res.total;
})
.finally(() => {
@@ -217,18 +241,25 @@ const handleDelete = async (row?: QuestionnaireVO) => {
await proxy?.$modal
.confirm('是否确认删除问卷调查?')
.then(() => {
delQuestionnaire(_ids, true).catch(async (res) => {
const content = res.msg.replace(/\n/g, '<br/>');
await proxy?.$modal
.confirm(content)
.then(() => {
delQuestionnaire(_ids, false).then(() => {
proxy?.$modal.msgSuccess('删除成功');
getList();
});
})
.finally(() => (loading.value = false));
});
delQuestionnaire(_ids, true)
.catch(async (res) => {
const content = res.msg.replace(/\n/g, '<br/>');
await proxy?.$modal
.confirm(content)
.then(() => {
delQuestionnaire(_ids, false).then(() => {
proxy?.$modal.msgSuccess('删除成功');
getList();
});
})
.finally(() => (loading.value = false));
})
.then((res) => {
if (res.msg === '操作成功') {
proxy?.$modal.msgSuccess('删除成功');
getList();
}
});
})
.finally(() => (loading.value = false));
};