feat:新增发送邮件功能

This commit is contained in:
zty 2024-04-24 17:27:32 +08:00
parent 4b7a875591
commit 6929fb7753
12 changed files with 605 additions and 101 deletions

View File

@ -1,7 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
export function getMyQi(query) { export function getAllQi(query) {
return request({ return request({
url: '/info/faq/', url: '/info/faq/',
method: 'get', method: 'get',
@ -9,9 +9,17 @@ export function getMyQi(query) {
}) })
} }
export function getMyQi(query) {
return request({
url: '/info/faqch/',
method: 'get',
params: query
})
}
export function getQi(id) { export function getQi(id) {
return request({ return request({
url: `/info/faqch/?instance_id=${id}`, url: `/info/ad/?instance_id=${id}`,
method: 'get' method: 'get'
}) })
} }
@ -19,8 +27,8 @@ export function getQi(id) {
export function updateQi(id, data) { export function updateQi(id, data) {
return request({ return request({
url: `/info/faq/${id}/`, url: `/info/faqch/${id}/`,
method: 'patch', method: 'put',
data data
}) })
} }

View File

@ -457,6 +457,12 @@ export const asyncRoutes = [
component: () => import('@/views/informatiomCollect/externalAuditor.vue'), component: () => import('@/views/informatiomCollect/externalAuditor.vue'),
meta: { title: '外审员情况', perms: ['infoCollect_EA'] } meta: { title: '外审员情况', perms: ['infoCollect_EA'] }
}, },
{
path: 'smsMessage',
name: 'smsMessage',
component: () => import('@/views/informatiomCollect/smsMessage.vue'),
meta: { title: '发送邮件', perms: ['infoCollect_SM']}
},
// { // {
// path: 'inspectionStats', // path: 'inspectionStats',
// name: 'inspectionStats', // name: 'inspectionStats',

View File

@ -0,0 +1,104 @@
<template>
<div class="app-container">
<el-card style="margin-top: 10px">
<el-table :data="tableData.results" style="width: 100%" v-loading="listLoading"
border fit stripe
highlight-current-row>
<el-table-column prop="company_name" label="公司名称" width="180"></el-table-column>
<el-table-column label="操作" width="120" >
<template slot-scope="scope">{{ curdOp[scope.row.action] }}</template>
</el-table-column>
<el-table-column prop="change_time" label="修改时间" width="180"></el-table-column>
<el-table-column prop="change_reason" label="变更原因" width="180"></el-table-column>
<el-table-column label="资质名称" width="180">
<template v-slot="scope">
{{ scope.row.val_new.name }}
</template>
</el-table-column>
<el-table-column label="变更详情">
<template slot-scope="scope">
<el-tag v-for="(diff, index) in scope.row.difference" :key="index">
{{ resultsMap[diff.name] }}: {{ diff.old }} -> {{ diff.new }}
</el-tag>
</template>
</el-table-column>
</el-table>
<pagination v-show="tableData.count > 0" :total="tableData.count" :page.sync="listQuery.page"
:limit.sync="listQuery.page_size" @pagination="getTableList" />
</el-card>
</div>
</template>
<script>
import checkPermission from "@/utils/permission";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { getDictList, getDictTypeList } from "@/api/dict";
import { getChangeInfo} from "@/api/qualificationInfo";
export default {
components: { Pagination, Treeselect },
data(){
return {
listLoading: false,
listQuery: {
page: 1,
page_size: 20,
},
tableColumns: [],
tableData: {
count: 0
},
curdOp:{"update":"更新","create":"创建","delete":"删除"},
resultsMap:{
"company_name":"公司名称",
"name":"资质名称",
"quali_type":"资质类型",
"org":"发证单位",
"org_date":"发证日期",
"expiration_date":"截至日期",
"scope":"资质范围",
"number":"参数数量",
"cie_path":"证书路径",
}
}
},
mounted() {
let that = this;
// let height1 = document.getElementsByClassName('app-main')[0].clientHeight;
// let height2 = document.getElementsByClassName('elHeader')[0].clientHeight;
// that.tableHeight = height1 - height2 - 70;
// console.log(that.tableHeight)
that.getList();
},
methods: {
//提交表单
getTableList(){
this.getList()
},
checkPermission,
getList() {
this.listLoading = true;
this.tableData.results =[];
this.tableData.count =0;
getChangeInfo(this.listQuery).then((response) => {
console.log(response);
if (response.data) {
this.tableData = response.data;
this.tableColumns = response.data.results
console.log(this.tableColumns)
}
this.listLoading = false;
});
},
},
};
</script>
<style></style>

View File

@ -1,32 +1,139 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card class="elHeader">
<el-button type="primary" icon="el-icon-plus" @click="handleAddFile">新增</el-button>
<el-button type="primary" @click="handleExport">导出</el-button>
</el-card>
<el-card style="margin-top: 10px"> <el-card style="margin-top: 10px">
<el-table :data="tableData.results" style="width: 100%" v-loading="listLoading" <el-table v-loading="listLoading"
:data="tableData.results"
border fit stripe border fit stripe
highlight-current-row> highlight-current-row>
<el-table-column prop="company_name" label="公司名称" width="180"></el-table-column> <el-table-column type="index" width="50" />
<el-table-column label="操作" width="120" > <el-table-column label="公司名称" prop="company_name"></el-table-column>
<template slot-scope="scope">{{ curdOp[scope.row.action] }}</template> <el-table-column label="资质名称" prop="name"></el-table-column>
</el-table-column> <el-table-column label="资质类型" prop="quali_type">
<el-table-column prop="change_time" label="修改时间" width="180"></el-table-column> <template slot-scope="scope">
<el-table-column prop="change_reason" label="变更原因" width="180"></el-table-column> <span>{{ac_options[scope.row.quali_type]}}</span>
<el-table-column label="资质名称" width="180"> </template>
<template v-slot="scope"> </el-table-column>
{{ scope.row.val_new.name }} <el-table-column label="发证单位" prop="org"></el-table-column>
</template> <el-table-column label="发证日期" prop="org_date"></el-table-column>
</el-table-column> <el-table-column label="截至日期" prop="expiration_date"></el-table-column>
<el-table-column label="变更详情"> <el-table-column label="资质范围" prop="scope"></el-table-column>
<template slot-scope="scope"> <el-table-column label="参数数量" prop="number"></el-table-column>
<el-tag v-for="(diff, index) in scope.row.difference" :key="index"> <el-table-column label="变更日期" prop="change_date"></el-table-column>
{{ resultsMap[diff.name] }}: {{ diff.old }} -> {{ diff.new }} <el-table-column align="center" label="操作" width="120px" fixed="right">
</el-tag> <template slot-scope="scope">
</template> <el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="primary" size="small"
</el-table-column> @click="handleEdit(scope)">编辑</el-link>
<el-divider direction="vertical"
</el-table> v-if="checkPermission(['infoCollect_QIN']) && checkPermission(['infoCollect_QIN'])"></el-divider>
<el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="danger" size="small"
@click="handleDelete(scope)">删除</el-link>
<!-- <el-link type="primary" @click="handleChange(scope)">变更记录</el-link> -->
</template>
</el-table-column>
</el-table>
<!-- <el-dialog title="变更记录" :visible.sync="dialogTableVisible">
<el-table :data="changeTableData" style="width: 100%">
<el-table-column label="公司名称" prop="company_name"></el-table-column>
<el-table-column label="变更时间" prop="change_time" ></el-table-column>
<el-table-column prop="change_reason" label="变更原因"></el-table-column>
<el-table-column label="资质名称" >
<template v-slot="scope">
<span>{{scope.row.val_new.name}}</span>
</template>
</el-table-column>
<el-table-column label="变更详情" width="500">
<template slot-scope="scope">
<el-tag v-for="(diff, index) in scope.row.difference" :key="index">
{{ resultsMap[diff.name] }}: {{ diff.old }} -> {{ diff.new }}
</el-tag>
</template>
</el-table-column>
</el-table>
</el-dialog> -->
<pagination v-show="tableData.count > 0" :total="tableData.count" :page.sync="listQuery.page" <pagination v-show="tableData.count > 0" :total="tableData.count" :page.sync="listQuery.page"
:limit.sync="listQuery.page_size" @pagination="getTableList" /> :limit.sync="listQuery.page_size" @pagination="getTableList" />
</el-card> </el-card>
<el-dialog :visible.sync="dialogVisible" :title="dialogType === 'edit' ? '编辑' : '新增'">
<el-form ref="Form" :model="Content" label-width="80px" label-position="right" :rules="rule">
<el-form-item label="公司名称" prop="company_name">
<el-input v-model="Content.company_name" placeholder="公司名称"/>
</el-form-item>
<el-form-item label="资质名称" prop="name">
<el-input v-model="Content.name" placeholder="资质名称"/>
</el-form-item>
<el-form-item label="资质类型">
<el-select
v-model="Content.quali_type"
placeholder="请选择"
>
<el-option
v-for="item in activateOptions"
:key="item.value"
:label="item.key"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="发证单位" prop="org">
<el-input v-model="Content.org" ></el-input>
</el-form-item>
<el-form-item label="发证日期" prop="org_date">
<el-date-picker
v-model="Content.org_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width:50%"
>
</el-date-picker>
</el-form-item>
<el-form-item label="截至日期" prop="expiration_date">
<el-date-picker
v-model="Content.expiration_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width:50%"
>
</el-date-picker>
</el-form-item>
<el-form-item label="资质范围" prop="scope">
<el-input v-model="Content.scope" ></el-input>
</el-form-item>
<el-form-item label="参数数量" prop="number" >
<el-input-number
v-model="Content.number"
:min="1"
controls-position="right"
:step="1"
/>
</el-form-item>
<el-form-item label="证书上传" prop="file">
<el-upload
ref="upload"
:action="upUrl"
:on-success="handleUpSuccess"
:on-remove="handleRemove"
:on-preview="handlePreview"
:headers="upHeaders"
:file-list="fileList"
:limit="1"
accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip">
<el-button size="small" type="primary">上传证书</el-button>
</el-upload>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
@ -35,22 +142,73 @@ import Pagination from "@/components/Pagination"; // secondary package based on
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { getDictList, getDictTypeList } from "@/api/dict"; import { getDictList, getDictTypeList } from "@/api/dict";
import { getChangeInfo} from "@/api/qualificationInfo"; import { getMyQi, updateQi, createQi, delQi} from "@/api/qualificationInfo";
import { upUrl, upHeaders } from "@/api/file";
import { saveAs } from 'file-saver';
import XLSX from 'xlsx';
const defaultContent = {
company_name: "",
name: "",
quali_type: "",
org: "",
org_date: "",
expiration_date: "",
scope: "",
number: "",
cie_path: "",
change_date:""
};
export default { export default {
components: { Pagination, Treeselect }, components: { Pagination, Treeselect },
data(){ data(){
return { return {
form: {
company_name: "",
name: "",
quali_type: "",
org: "",
org_date: "",
expiration_date: "",
scope: "",
number: "",
cie_path: "",
change_date:""
},
upHeaders: upHeaders(),
upUrl: upUrl(),
fileList: [],
Content: defaultContent,
typeOptions: [],
listLoading: false, listLoading: false,
dialogVisible: false,
showExportDialog: false,
dialogTableVisible:false,
exportForm: {
startDate: '', // 开始日期
endDate: '', // 结束日期
},
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
tableColumns: [],
tableData: { tableData: {
count: 0 count: 0
}, },
curdOp:{"update":"更新","create":"创建","delete":"删除"}, changeTableData:[],
dialogType: "new",
rule: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
},
filterOrgText: "",
// tableHeight: '300px',
activateOptions:[
{key:'国家级',value:'国家级'},
{key:'省级',value:'省级'}
],
ac_options:{'国家级':'国家级', '省级':'省级'},
resultsMap:{ resultsMap:{
"company_name":"公司名称", "company_name":"公司名称",
"name":"资质名称", "name":"资质名称",
@ -66,35 +224,191 @@ export default {
}, },
mounted() { mounted() {
let that = this; let that = this;
// let height1 = document.getElementsByClassName('app-main')[0].clientHeight; let height1 = document.getElementsByClassName('app-main')[0].clientHeight;
// let height2 = document.getElementsByClassName('elHeader')[0].clientHeight; let height2 = document.getElementsByClassName('elHeader')[0].clientHeight;
// that.tableHeight = height1 - height2 - 70; that.tableHeight = height1 - height2 - 70;
// console.log(that.tableHeight) console.log(that.tableHeight)
that.getList(); that.getList();
}, },
methods: { methods: {
//提交表单 //提交表单
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
if (this.dialogType == "new") {
this.addData();
} else {
this.editData();
}
} else {
console.log("error submit!!");
return false;
}
});
},
getTableList(){ getTableList(){
this.getList() this.getList()
}, },
handleExport() {
// if (!this.exportForm.startDate || !this.exportForm.endDate) {
// this.$message.error('请选择完整的起止日期!');
// return;}
console.log(this.exportForm)
getMyQi().then((response) => {
console.log(response);
if (response.data) {
let filename = '质量活动表.xlsx';
let tableData = response.data;
console.log(tableData)
const ws = XLSX.utils.json_to_sheet(tableData.results);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
try {
saveAs(new Blob([wbout], { type: 'application/octet-stream' }), filename);
} catch (e) { if(typeof console !== 'undefined') console.log(e, wbout); }
return;
}else {
this.$message.error(data.message || '导出失败');
}
})
// this.showExportDialog = false;
.catch(error => {
this.$message.error('请求失败,请稍后再试');
console.error(error);
})
.finally(() => {
this.handleDialogClose();
});
},
handleDialogClose(){
this.showExportDialog = false;
this.startDate = '';
this.endDate = '';
},
handlePreview(file) {
if ("url" in file) {
window.open(file.url);
} else {
window.open(file.response.data.path);
}
},
handleUpSuccess(res, file, filelist) {
console.log(res.data.path)
this.Content.cie_path = res.data.path;
this.Content.file = res.data.id;
},
handleRemove(file, filelist) {
this.Content.file = null;
},
checkPermission, checkPermission,
getList() { getList() {
this.listLoading = true; this.listLoading = true;
this.tableData.results =[]; this.tableData.results =[];
this.tableData.count =0; this.tableData.count =0;
getChangeInfo(this.listQuery).then((response) => { getMyQi(this.listQuery).then((response) => {
console.log(response); console.log(response);
if (response.data) { if (response.data) {
this.tableData = response.data; this.tableData = response.data;
this.tableColumns = response.data.results
console.log(this.tableColumns)
} }
this.listLoading = false; this.listLoading = false;
}
);
},
handleAddFile() {
this.Content = Object.assign({}, defaultContent);
this.dialogType = "new";
this.dialogVisible = true;
this.fileList = []
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.Content = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
if (this.Content.file) {
this.fileList = [
{
name: this.Content.file_.name,
url: this.Content.file,
},
];
}
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await delQi(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
// handleChange(scope) {
// this.listLoading = true;
// this.Content = Object.assign({}, scope.row); // copy obj
// this.changeTableData =[];
// this.dialogTableVisible=true;
// getQi(scope.row.id).then((response) => {
// if (response.data.count>0) {
// this.changeTableData = response.data.results;
// console.log(this.changeTableData);
// this.listLoading = false;
// }else{
// alert('无变更记录')
// this.dialogTableVisible=false;
// this.listLoading = false;
// return
// }
// });
// },
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
console.log(this.Content, "edited");
updateQi(this.Content.id, this.Content).then((response) => {
if (response.data) {
this.tableData = response.data;
}
this.listLoading = false;
this.dialogVisible = false;
this.getTableList();
});
} else {
createQi(this.Content).then((response) => {
if (response.data) {
console.log(response.data, "created");
this.tableData = response.data;
}
this.listLoading = false;
this.dialogVisible = false;
this.getTableList();
});
}
} else {
return false;
}
}); });
}, },
}, },

View File

@ -22,7 +22,7 @@
<el-table-column label="截至日期" prop="expiration_date"></el-table-column> <el-table-column label="截至日期" prop="expiration_date"></el-table-column>
<el-table-column label="资质范围" prop="scope"></el-table-column> <el-table-column label="资质范围" prop="scope"></el-table-column>
<el-table-column label="参数数量" prop="number"></el-table-column> <el-table-column label="参数数量" prop="number"></el-table-column>
<el-table-column label="变更日期" prop="update_time"></el-table-column> <el-table-column label="变更日期" prop="change_date"></el-table-column>
<el-table-column align="center" label="操作" width="120px" fixed="right"> <el-table-column align="center" label="操作" width="120px" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="primary" size="small" <el-link :disabled="!checkPermission(['infoCollect_QIN'])" type="primary" size="small"
@ -142,7 +142,7 @@ import Pagination from "@/components/Pagination"; // secondary package based on
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { getDictList, getDictTypeList } from "@/api/dict"; import { getDictList, getDictTypeList } from "@/api/dict";
import { getMyQi, getQi, updateQi, createQi, delQi} from "@/api/qualificationInfo"; import { getAllQi, getQi, updateQi, createQi, delQi} from "@/api/qualificationInfo";
import { upUrl, upHeaders } from "@/api/file"; import { upUrl, upHeaders } from "@/api/file";
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import XLSX from 'xlsx'; import XLSX from 'xlsx';
@ -157,7 +157,8 @@ const defaultContent = {
expiration_date: "", expiration_date: "",
scope: "", scope: "",
number: "", number: "",
cie_path: "" cie_path: "",
change_date:""
}; };
export default { export default {
@ -173,7 +174,8 @@ export default {
expiration_date: "", expiration_date: "",
scope: "", scope: "",
number: "", number: "",
cie_path: "" cie_path: "",
change_date:""
}, },
upHeaders: upHeaders(), upHeaders: upHeaders(),
upUrl: upUrl(), upUrl: upUrl(),
@ -255,7 +257,7 @@ export default {
// this.$message.error('请选择完整的起止日期!'); // this.$message.error('请选择完整的起止日期!');
// return;} // return;}
console.log(this.exportForm) console.log(this.exportForm)
getMyQi().then((response) => { getAllQi().then((response) => {
console.log(response); console.log(response);
if (response.data) { if (response.data) {
let filename = '质量活动表.xlsx'; let filename = '质量活动表.xlsx';
@ -309,7 +311,7 @@ export default {
this.listLoading = true; this.listLoading = true;
this.tableData.results =[]; this.tableData.results =[];
this.tableData.count =0; this.tableData.count =0;
getMyQi(this.listQuery).then((response) => { getAllQi(this.listQuery).then((response) => {
console.log(response); console.log(response);
if (response.data) { if (response.data) {
this.tableData = response.data; this.tableData = response.data;

View File

@ -0,0 +1,46 @@
<template>
<div>
<el-button class="my-button" type="primary" @click="handleSendEmail">发送邮件</el-button>
<div style="margin-top: 20px;">
<el-checkbox-group
v-model="form.names">
<el-checkbox label="材料报送二级单位"></el-checkbox>
<el-checkbox label="材料报送三级单位"></el-checkbox>
</el-checkbox-group>
</div>
</div>
</template>
<script>
import {sendMsg} from "@/api/msg";
export default {
data() {
return {
form: {names: []}, // 用于存储复选框的选中状态
};
},
methods: {
handleSendEmail() {
// 检查是否有复选框被选中
if (this.form.names.length > 0) {
// 这里应该是发送邮件的逻辑
alert('发送邮件,选中的选项是:' + this.form.names.join(', '));
// 你可以在这里调用API发送邮件并传入选中的选项作为参数
sendMsg(this.form).then(response => {
console.log(response);
});
} else {
alert('请至少选择一个选项');
}
}
}
};
</script>
<style scoped>
.my-button {
margin: 20px; /* 设置外边距 */
/* padding: 10px; /* 如果需要设置内边距可以取消注释这行 */
}
</style>

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2024-04-24 04:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('information', '0030_alter_externalauditors_review_types'),
]
operations = [
migrations.AddField(
model_name='qualification',
name='change_date',
field=models.DateField(blank=True, null=True, verbose_name='变更日期'),
),
]

View File

@ -15,7 +15,7 @@ class Qualification(CommonBDModel):
scope = models.TextField(verbose_name='资质范围', null=True, blank=True) scope = models.TextField(verbose_name='资质范围', null=True, blank=True)
number = models.IntegerField(verbose_name='参数数量', null=True, blank=True) number = models.IntegerField(verbose_name='参数数量', null=True, blank=True)
cie_path = models.CharField(max_length=100, verbose_name='证书路径', null=True, blank=True) cie_path = models.CharField(max_length=100, verbose_name='证书路径', null=True, blank=True)
change_date = models.DateField(verbose_name='变更日期', null=True, blank=True)
class Meta: class Meta:
verbose_name = '资质情况' verbose_name = '资质情况'

View File

@ -1,6 +1,8 @@
from rest_framework import serializers from rest_framework import serializers
from apps.system.serializers import OrganizationSimpleSerializer from apps.system.serializers import OrganizationSimpleSerializer
from apps.system.models import Organization
from .models import AbilityReview, QualityCommendation, QualityActivities, Contact, ExternalAuditors, AuditLog, Qualification from .models import AbilityReview, QualityCommendation, QualityActivities, Contact, ExternalAuditors, AuditLog, Qualification
from django.utils import timezone
class BaseMeta: class BaseMeta:
fields = '__all__' fields = '__all__'
@ -36,8 +38,15 @@ class ExternalAuditorsSerializer(serializers.ModelSerializer):
class QualificationSerializer(serializers.ModelSerializer): class QualificationSerializer(serializers.ModelSerializer):
class Meta(BaseMeta): class Meta(BaseMeta):
model = Qualification model = Qualification
fields = ["id","name","company_name","quali_type","org","org_date","expiration_date","number","scope"] fields = ["id","name","company_name","quali_type","org","org_date","expiration_date","number","scope", "change_date"]
def create(self, validated_data):
validated_data["belong_dept_id"] = Organization.objects.filter(name = validated_data.get("company_name")).first().id
return super().create(validated_data)
def update(self, instance, validated_data):
validated_data["change_date"] = timezone.now().date()
return super().update(instance, validated_data)
class AbilityReviewSerializer(serializers.ModelSerializer): class AbilityReviewSerializer(serializers.ModelSerializer):
quali_name = serializers.CharField(source='quali.name', read_only=True) quali_name = serializers.CharField(source='quali.name', read_only=True)

View File

@ -1,6 +1,6 @@
from django.urls import path, include from django.urls import path, include
from rest_framework import routers from rest_framework import routers
from .views import AbilityReviewViewSet, QualityCommendationViewSet, QualityActivitiesViewSet, QualiChangeViewSet, ContactViewSet, ExternalAuditorsViewSet, QualificationViewSet from .views import AbilityReviewViewSet, AuditLogViewSet, QualityCommendationViewSet, QualityActivitiesViewSet, QualiChangeViewSet, ContactViewSet, ExternalAuditorsViewSet, QualificationViewSet
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register('ar', AbilityReviewViewSet, basename='abilityreviews') router.register('ar', AbilityReviewViewSet, basename='abilityreviews')
@ -10,6 +10,7 @@ router.register('contact', ContactViewSet, basename='contact')
router.register('ea', ExternalAuditorsViewSet, basename='externalauditors') router.register('ea', ExternalAuditorsViewSet, basename='externalauditors')
router.register('faq', QualificationViewSet, basename='faq') router.register('faq', QualificationViewSet, basename='faq')
router.register('faqch', QualiChangeViewSet, basename='faqch') router.register('faqch', QualiChangeViewSet, basename='faqch')
router.register('ad', AuditLogViewSet, basename='ad')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)) path('', include(router.urls))

View File

@ -276,6 +276,7 @@ class QualityActivitiesViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
data_list = [] data_list = []
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据 for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
if row[0] is not None: if row[0] is not None:
department_id = Organization.objects.filter(name=row[4]).first().id
activate_time = row[6].strftime("%Y-%m-%d") activate_time = row[6].strftime("%Y-%m-%d")
role_dict = {"组织方":0, "参与方":1} role_dict = {"组织方":0, "参与方":1}
serializer_data = { serializer_data = {
@ -287,7 +288,8 @@ class QualityActivitiesViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
'activate_time':activate_time, 'activate_time':activate_time,
'participations':row[7], 'participations':row[7],
'function':row[8], 'function':row[8],
'earnings':row[9] 'earnings':row[9],
'belong_dept':department_id,
} }
data_list.append(serializer_data) data_list.append(serializer_data)
return data_list return data_list
@ -300,7 +302,7 @@ class QualityActivitiesViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
return self.gen_imp_view(request, 2, QualityActivitiesSerializer) return self.gen_imp_view(request, 2, QualityActivitiesSerializer)
class ContactViewSet(RbacFilterSet, CreateUpdateCustomMixin, ModelViewSet): class ContactViewSet(CreateUpdateCustomMixin, ModelViewSet):
queryset = Contact.objects.all() queryset = Contact.objects.all()
serializer_class = ContactSerializer serializer_class = ContactSerializer
@ -377,6 +379,7 @@ class ExternalAuditorsViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
data_list = [] data_list = []
for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据 for row in sheet.iter_rows(min_row=start, values_only=True): # 假设第一行是表头,从第二行开始读取数据
if row[0] is not None: if row[0] is not None:
department_id = Organization.objects.filter(name=row[1]).first().id
activate_time = row[4].strftime("%Y-%m-%d") activate_time = row[4].strftime("%Y-%m-%d")
serializer_data = { serializer_data = {
'name_company': row[1], # 第一列是名字 'name_company': row[1], # 第一列是名字
@ -386,6 +389,7 @@ class ExternalAuditorsViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
'contact':row[5], 'contact':row[5],
'judging_areas':row[6], 'judging_areas':row[6],
'remark':row[7], 'remark':row[7],
'belong_dept':department_id,
} }
data_list.append(serializer_data) data_list.append(serializer_data)
return data_list return data_list
@ -398,43 +402,26 @@ class ExternalAuditorsViewSet(ImpMixin, RbacFilterSet, CreateUpdateCustomMixin,
return self.gen_imp_view(request, 2, ExternalAuditorsSerializer) return self.gen_imp_view(request, 2, ExternalAuditorsSerializer)
class QualificationViewSet(CreateUpdateCustomMixin, ModelViewSet): class QualificationViewSet(ModelViewSet):
queryset = Qualification.objects.all() queryset = Qualification.objects.all()
serializer_class = QualificationSerializer serializer_class = QualificationSerializer
perms_map = {'get': '*', 'post': 'qa_create',
# # 重写更新的方法 'put': 'qa_update', 'delete': 'qa_delete'}
# def partial_update(self, request, pk=None):
# #获取需要更新的实列
# instance = self.get_object()
# # 数据比较
# ignore_fields = ['create_by', 'create_date', 'update_date', 'id']
# origin_dict = QualificationSerializer(instance=instance).data
# diff = []
# for k, v in request.data.items():
# if k not in ignore_fields:
# origin_value = origin_dict.get(k)
# if origin_value != v:
# diff.append({'old':origin_value, 'new':v, 'name':k})
# serializers = self.get_serializer(instance, data=request.data, partial=True)
# serializers.is_valid(raise_exception=True)
# self.perform_update(serializers)
# if diff:
# AuditLog.objects.create(
# action='update',
# instance=instance,
# change_time = datetime.now(),
# change_user=request.user,
# val_new=serializers.data,
# difference=diff
# )
# return Response(serializers.data, status = status.HTTP_204_NO_CONTENT)
class QualiChangeViewSet(RbacFilterSet, ModelViewSet): class AuditLogViewSet(RbacFilterSet, CreateUpdateCustomMixin, ModelViewSet):
queryset = AuditLog.objects.select_related('instance').all() queryset = AuditLog.objects.select_related('instance').all()
serializer_class = AuditLogSerializer serializer_class = AuditLogSerializer
filterset_fields = ['instance_id'] filterset_fields = ['instance_id']
class QualiChangeViewSet(RbacFilterSet, CreateUpdateCustomMixin, ModelViewSet):
queryset = Qualification.objects.all()
serializer_class = QualificationSerializer
perms_map = {'get': '*', 'post': 'qchange_create',
'put': 'qchange_update', 'patch': 'qchange_update', 'delete': 'qchange_delete'}
# 重写更新的方法 # 重写更新的方法
def partial_update(self, request, pk=None): def partial_update(self, request, pk=None):
#获取需要更新的实列 #获取需要更新的实列

View File

@ -105,32 +105,41 @@ class sendMsg(APIView):
def post(self, request): def post(self, request):
code = random.randint(10000,99999) code = random.randint(10000,99999)
my_sender = 'gxpt@ctc.ac.cn' my_sender = 'gxpt@ctc.ac.cn'
my_user = request.data['mail'] # 材料报送二级单位和三级单位
names = request.data['names']
role_ids = [role.id for role in Role.objects.filter(name__in=names)]
reci_users = []
for i in role_ids:
role = Role.objects.get(id=i)
users = role.user_set.all()
username = users.values_list('username', flat=True)
reci_users.extend(username)
my_pass = 'Pintai123' my_pass = 'Pintai123'
if not User.objects.filter(username=my_user).exists(): # if not User.objects.filter(username=my_user).exists():
return Response('该账户不存在', status=status.HTTP_400_BAD_REQUEST) # return Response('该账户不存在', status=status.HTTP_400_BAD_REQUEST)
try: try:
# 邮件内容 for u in reci_users:
msg=MIMEText('您好,共享平台本次登陆验证码为' + str(code),'plain','utf-8') # 邮件内容
# 括号里的对应发件人邮箱昵称、发件人邮箱账号 msg=MIMEText('您好,共享平台本次登陆验证码为' + str(code),'plain','utf-8')
msg['From']=formataddr(["国检集团检验检测能力共享平台",my_sender]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号
# 括号里的对应收件人邮箱昵称、收件人邮箱账号 msg['From']=formataddr(["国检集团检验检测能力共享平台",my_sender])
msg['To']=formataddr(["",my_user]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号
# 邮件的主题 msg['To']=formataddr(["",u])
msg['Subject'] = Header(str(code), 'utf-8').encode() # 邮件的主题
msg['Subject'] = Header(str(code), 'utf-8').encode()
# SMTP服务器腾讯企业邮箱端口是465腾讯邮箱支持SSL(不强制) 不支持TLS # SMTP服务器腾讯企业邮箱端口是465腾讯邮箱支持SSL(不强制) 不支持TLS
# qq邮箱smtp服务器地址:smtp.qq.com,端口号456 # qq邮箱smtp服务器地址:smtp.qq.com,端口号456
# 163邮箱smtp服务器地址smtp.163.com端口号25 # 163邮箱smtp服务器地址smtp.163.com端口号25
server=smtplib.SMTP_SSL("smtp.exmail.qq.com", 465) server=smtplib.SMTP_SSL("smtp.exmail.qq.com", 465)
# 登录服务器,括号中对应的是发件人邮箱账号、邮箱密码 # 登录服务器,括号中对应的是发件人邮箱账号、邮箱密码
server.login(my_sender, my_pass) server.login(my_sender, my_pass)
# 发送邮件,括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件 # 发送邮件,括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.sendmail(my_sender,[my_user,],msg.as_string()) server.sendmail(my_sender,[u,],msg.as_string())
Message.objects.filter(mail=u).delete()
Message.objects.create(mail=u, msg=code)
# 关闭连接 # 关闭连接
server.quit() server.quit()
Message.objects.filter(mail=my_user).delete()
Message.objects.create(mail=my_user, msg=code)
except: except:
return Response('验证码发送失败', status=status.HTTP_400_BAD_REQUEST) return Response('验证码发送失败', status=status.HTTP_400_BAD_REQUEST)
return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)