views.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. from django.shortcuts import render
  2. from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
  3. from datetime import datetime, timedelta, date
  4. from django.forms.models import model_to_dict
  5. import json
  6. from .data import ADMIN_PSW
  7. from .setting import APPLICATION_NAME, get_media_url_prefix
  8. from .functions import is_volunteer_login, upload_file, get_ext, msg_and_direct, service_log
  9. from .models import Volunteer, ServiceTimeSlot, ServiceBooking, Bonus, BonusRecord, CreditRecord
  10. # from Niko.settings import DEBUG, ENVIRONMENT
  11. from django.db import transaction
  12. from backend.wechat import WeChatOA2, WeChatMsg
  13. from Niko.settings import DEBUG
  14. import csv
  15. # Create your views here.
  16. def index(request):
  17. if request.method == 'GET':
  18. # 尝试微信登录
  19. if 'micromessenger' in request.META['HTTP_USER_AGENT'].lower():
  20. wechat_id = request.session.get('wechat_openid')
  21. if DEBUG:
  22. service_log('打印session中的微信wechat_openid')
  23. service_log(wechat_id)
  24. if wechat_id is None:
  25. return HttpResponseRedirect('/cq/volunteer/wechat_entry/')
  26. else:
  27. wechat_id = None
  28. # wechat_id = 'o3MJZ02eAuLBNSMson2NeI19135Y'
  29. if wechat_id:
  30. volunteer = Volunteer.get_by_wechat_id(wechat_id)
  31. if volunteer:
  32. if volunteer.status == 'active':
  33. request.session['volunteer_id'] = volunteer.ID
  34. redirect_uri = request.session.get('redirect_uri') # 检索是否需要重定向
  35. if redirect_uri is None:
  36. redirect_uri = '/cq/volunteer/home/'
  37. else:
  38. request.session.pop('redirect_uri')
  39. return HttpResponseRedirect(redirect_uri)
  40. else:
  41. request.session.flush()
  42. return render(request, 'volunteer_arrangement/directPage.html',
  43. {'alertMsg': '账户未激活', 'dirLink': '/cq/volunteer/'})
  44. return render(request, 'volunteer_arrangement/index.html', {'buttom_bg_color': 'rgb(88, 167, 255)'})
  45. if request.method == 'POST':
  46. volunteer = Volunteer.get_by_mobile_social_id(request.POST['mobile'], request.POST['social_id'].upper().strip())
  47. if volunteer:
  48. if volunteer.status == 'active':
  49. request.session['volunteer_id'] = volunteer.ID
  50. if volunteer.wechat_id is None: # 如果用户没有wechat_id,就写入wechat_id
  51. volunteer.wechat_id = request.session.get('wechat_openid')
  52. volunteer.save()
  53. redirect_uri = request.session.get('redirect_uri') # 检索是否需要重定向
  54. if redirect_uri is None:
  55. redirect_uri = '/cq/volunteer/home/'
  56. else:
  57. request.session.pop('redirect_uri')
  58. return HttpResponseRedirect(redirect_uri)
  59. else:
  60. return render(request, 'volunteer_arrangement/directPage.html',
  61. {'alertMsg': '账户未激活', 'dirLink': '/cq/volunteer/'})
  62. else:
  63. return render(request, 'volunteer_arrangement/directPage.html',
  64. {'alertMsg': '手机号码和身份证错误', 'dirLink': '/cq/volunteer/'})
  65. # 微信入口跳转
  66. def wechat_entry(request):
  67. # 微信登录
  68. wechat_oa2 = WeChatOA2()
  69. # 这里的Volunteer和Base是两个参数,表示volunteer应用调用微信登录,用户获取Base信息
  70. return HttpResponseRedirect(wechat_oa2.snsapi_base('VolunteerBase'))
  71. def volunteer_reg(request):
  72. if request.method == 'GET':
  73. return render(request, 'volunteer_arrangement/volunteer_reg.html', {'title': '志愿者注册'})
  74. if request.method == 'POST':
  75. if Volunteer.get_by_mobile(request.POST['mobile']) is None:
  76. volunteer = Volunteer()
  77. volunteer.status = 'pending'
  78. volunteer.name = request.POST['name'].strip()
  79. volunteer.mobile = request.POST['mobile'].strip()
  80. if len(volunteer.mobile) != 11:
  81. return msg_and_direct(request, 'http://127.0.0.1:8000/cq/volunteer/volunteer_reg/', '手机号码需要为11位')
  82. volunteer.gender = request.POST['gender']
  83. volunteer.social_id = request.POST['social_id'].upper().strip()
  84. if len(volunteer.social_id) != 18:
  85. return msg_and_direct(request, 'http://127.0.0.1:8000/cq/volunteer/volunteer_reg/', '身份证号码需要为18位')
  86. volunteer.political_outlook = request.POST['political_outlook']
  87. volunteer.organization = request.POST['organization'].strip()
  88. volunteer.district_street = request.POST['district_street'].strip()
  89. volunteer.save()
  90. return render(request, 'volunteer_arrangement/directPage.html',
  91. {'alertMsg': '提交成功,请等待审批', 'dirLink': '/cq/volunteer'})
  92. else:
  93. return render(request, 'volunteer_arrangement/directPage.html',
  94. {'alertMsg': '手机号码已经注册过了', 'dirLink': '/cq/volunteer'})
  95. # 志愿者编辑个人信息
  96. def volunteer_update_info(request):
  97. if request.method == 'GET':
  98. # 验证登陆状态
  99. if not request.session.get('volunteer_id'):
  100. return render(request, 'volunteer_arrangement/directPage.html',
  101. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  102. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  103. return render(request, 'volunteer_arrangement/volunteer_update_info.html', {'volunteer': volunteer})
  104. if request.method == 'POST':
  105. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  106. if volunteer.mobile != int(request.POST['mobile']): # POST上来一个新的手机号码
  107. if Volunteer.get_by_mobile(request.POST['mobile']) is not None: # 这个新的号码已经存在了
  108. return render(request, 'volunteer_arrangement/directPage.html',
  109. {'alertMsg': '手机号码已经注册过了', 'dirLink': '/cq/volunteer/update_info/'})
  110. else:
  111. volunteer.status = 'pending'
  112. volunteer.name = request.POST['name'].strip()
  113. volunteer.mobile = request.POST['mobile']
  114. volunteer.gender = request.POST['gender']
  115. volunteer.social_id = request.POST['social_id'].upper()
  116. volunteer.political_outlook = request.POST['political_outlook']
  117. volunteer.organization = request.POST['organization'].strip()
  118. volunteer.district_street = request.POST['district_street'].strip()
  119. volunteer.save()
  120. request.session.flush()
  121. return render(request, 'volunteer_arrangement/directPage.html',
  122. {'alertMsg': '更新成功,请等待审批', 'dirLink': '/cq/volunteer'})
  123. def volunteer_home(request):
  124. if request.method == 'GET':
  125. if not is_volunteer_login(request):
  126. return render(request, 'volunteer_arrangement/directPage.html',
  127. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  128. available_address = ServiceTimeSlot.available_address()
  129. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  130. return render(request, 'volunteer_arrangement/volunteer_home.html',
  131. {'address': available_address, 'volunteer': volunteer})
  132. def admin(request):
  133. if request.method == 'GET':
  134. return render(request, 'volunteer_arrangement/admin_login.html')
  135. if request.method == 'POST':
  136. if request.POST['password'] == ADMIN_PSW:
  137. request.session['admin_login'] = True
  138. return HttpResponseRedirect('/cq/volunteer/admin_management/home/')
  139. else:
  140. return render(request, 'volunteer_arrangement/directPage.html',
  141. {'alertMsg': '密码错误', 'dirLink': '/cq/volunteer/admin/'})
  142. def admin_management(request, action):
  143. # 验证管理员登录状态
  144. if not request.session.get('admin_login'):
  145. return render(request, 'volunteer_arrangement/directPage.html',
  146. {'alertMsg': '请重新登录管理员', 'dirLink': '/cq/volunteer/admin/'})
  147. if action == 'home':
  148. return render(request, 'volunteer_arrangement/admin_home.html')
  149. if action == 'pending_list':
  150. pending_list = Volunteer.pending_list()
  151. return render(request, 'volunteer_arrangement/admin_pending_list.html', {'pending_list': pending_list})
  152. if action == 'approve_volunteer':
  153. v_id = request.GET.get('v_id')
  154. Volunteer.approve_volunteer(v_id)
  155. # 微信推送批准消息
  156. volunteer = Volunteer.get_by_id(v_id)
  157. if volunteer.wechat_id != None:
  158. wechat_msg = WeChatMsg(volunteer.wechat_id, '-WK6XrgmvW7cR7pZFwpHQwLVABd1dmzc3MXkXsQ6dGc', APPLICATION_NAME)
  159. wechat_msg.set_first('你已通过了审核')
  160. wechat_msg.add_keyboard(volunteer.name)
  161. wechat_msg.add_keyboard(volunteer.mobile)
  162. wechat_msg.add_keyboard(str(datetime.today().date()))
  163. wechat_msg.add_keyboard('通过')
  164. wechat_msg.set_remark('现在可以报名志愿者服务了。')
  165. wechat_msg.submit()
  166. return HttpResponseRedirect('/cq/volunteer/admin_management/home/')
  167. if action == 'reject_volunteer':
  168. v_id = request.GET.get('v_id')
  169. Volunteer.reject(v_id)
  170. return HttpResponseRedirect('/cq/volunteer/admin_management/home/')
  171. if action == 'create_service':
  172. if request.method == 'GET':
  173. return render(request, 'volunteer_arrangement/admin_create_service.html')
  174. if request.method == 'POST':
  175. if request.POST.get('day') == 'full_month':
  176. new_service_list = []
  177. year = int(request.POST.get('year'))
  178. month = int(request.POST.get('month')) + 1
  179. if month > 12:
  180. month -= 12
  181. year += 1
  182. service_year_month = datetime(year=year, month=month, day=1)
  183. service_year_month = service_year_month - timedelta(days=1)
  184. for x in range(service_year_month.day):
  185. service_timeslot = ServiceTimeSlot()
  186. service_timeslot.date = date(year=service_year_month.year, month=service_year_month.month,
  187. day=x + 1)
  188. service_timeslot.start_time = request.POST.get('start_time')
  189. service_timeslot.end_time = request.POST.get('end_time')
  190. service_timeslot.address = request.POST.get('address')
  191. service_timeslot.service_address = request.POST.get('service_address')
  192. service_timeslot.service_content = request.POST.get('service_content')
  193. service_timeslot.people_count = request.POST.get('people_count')
  194. new_service_list.append(service_timeslot)
  195. ServiceTimeSlot.objects.bulk_create(new_service_list)
  196. return msg_and_direct(request, '/cq/volunteer/admin_management/home/',
  197. message='成功添加{}条记录'.format(service_year_month.day))
  198. elif request.POST.get('day') == 'not_full_month':
  199. service_timeslot = ServiceTimeSlot()
  200. service_timeslot.date = date(int(request.POST.get('year')), int(request.POST.get('month')),
  201. int(request.POST.get('date')))
  202. service_timeslot.start_time = request.POST.get('start_time')
  203. service_timeslot.end_time = request.POST.get('end_time')
  204. service_timeslot.address = request.POST.get('address')
  205. service_timeslot.service_address = request.POST.get('service_address')
  206. service_timeslot.service_content = request.POST.get('service_content')
  207. service_timeslot.people_count = request.POST.get('people_count')
  208. service_timeslot.save()
  209. return msg_and_direct(request, '/cq/volunteer/admin_management/home/', '成功添加1条记录')
  210. if action == 'delete_service':
  211. if request.method == 'GET':
  212. booking_list = None
  213. # booking_overall_status = []
  214. # 如果有日期就获取当天的报名状况
  215. if request.GET.get('date'):
  216. service_date = request.GET['date']
  217. service_address = request.GET.get('address')
  218. if request.GET.get('timeslot_id'): # 如果指定service timeslot id 就根据ID查找
  219. service_list = ServiceTimeSlot.get_by_id(request.GET.get('timeslot_id'))
  220. else:
  221. service_list = ServiceTimeSlot.search_by_date_and_address(service_date, service_address)
  222. # service_list = ServiceTimeSlot.search_by_date(service_date)
  223. booking_list = ServiceBooking.search_by_service_timeslot_list(service_list)
  224. return render(request, 'volunteer_arrangement/admin_delete_service.html',
  225. {'booking_status': booking_list, 'date': str(request.GET.get('date'))})
  226. if action == 'get_month_service':
  227. if request.method == 'GET':
  228. # 获取日期值
  229. if request.GET.get('date'):
  230. service_date = request.GET.get('date')
  231. monthly_report = ServiceBooking.get_monthly_report(service_date)
  232. for item in monthly_report: # 添加一个tab,用来避免excel打开身份证号码最后几位显示为0的问题
  233. item['volunteer_id__social_id'] = '\t' + item['volunteer_id__social_id']
  234. # 获取数据,生成response
  235. response = HttpResponse(content_type='text/csv;charset=ANSI')
  236. response['Content-Disposition'] = 'attachment; filename="MonthlyReport.csv"'
  237. writer = csv.writer(response)
  238. # keys = monthly_report[0].keys()
  239. keys = ['日期', '开始时间', '结束时间', '服务地点', '姓名', '性别', '手机号码', '身份证号码', '政治面貌', '学校/单位', '居住区域(区或街道)']
  240. writer.writerow(keys)
  241. for x in monthly_report:
  242. writer.writerow(x.values())
  243. return response
  244. # 列出所有未来的志愿者服务
  245. if action == 'future_timeslot':
  246. if request.method == 'GET':
  247. timeslots = ServiceTimeSlot.search_future_timeslots(datetime.today().date())
  248. return render(request, 'volunteer_arrangement/admin_future_timeslots.html', {'timeslots': timeslots})
  249. # 删除service time slot会cascade删除所有报名的记录
  250. if action == 'delete_timeslot':
  251. if request.method == 'POST':
  252. timeslot_id = request.POST.get('timeslot_id')
  253. timeslot = ServiceTimeSlot.get_by_id(timeslot_id)
  254. # 微信通知删除者
  255. notify_bookings = ServiceBooking.search_by_service_timeslot(timeslot)
  256. for booking in notify_bookings:
  257. if booking.volunteer_id.wechat_id is not None:
  258. wechat_msg = WeChatMsg(booking.volunteer_id.wechat_id,
  259. 'QKMJ1XFQoXWnxdc1ZDSXKraZpumcZbg_Ow8DdaP3Cuo', APPLICATION_NAME)
  260. wechat_msg.set_first('志愿者活动已取消')
  261. wechat_msg.add_keyboard('志愿者服务')
  262. wechat_msg.add_keyboard(str(booking.timeslot_id.date) + " " + str(booking.timeslot_id.start_time)
  263. + '-' + str(booking.timeslot_id.end_time))
  264. wechat_msg.add_keyboard(booking.timeslot_id.address)
  265. wechat_msg.set_remark('你的志愿者服务,已被管理员取消。')
  266. wechat_msg.submit()
  267. pass
  268. timeslot.delete()
  269. return msg_and_direct(request, '/cq/volunteer/admin_management/home/', '活动删除成功,并解除所有报名')
  270. # 修改服务人数
  271. if action == 'modify_people_count':
  272. if request.method == 'POST':
  273. timeslot_id = request.POST.get('timeslot_id')
  274. timeslot = ServiceTimeSlot.get_by_id(timeslot_id)
  275. new_people_count = int(request.POST.get('new_count'))
  276. if new_people_count < timeslot.booked_count: # 防止修改完成后的人数少于已经报名的人数
  277. return_value = {'result': 'fail', 'code': 10}
  278. return JsonResponse(return_value)
  279. # return msg_and_direct(request, '/cq/volunteer/admin_management/future_timeslot/', '总人数少于已报名人数')
  280. else:
  281. timeslot.people_count = new_people_count
  282. timeslot.save()
  283. return_value = {'result': 'success'}
  284. return JsonResponse(return_value)
  285. # return msg_and_direct(request, '/cq/volunteer/admin_management/future_timeslot/', '修改成功')
  286. # 调整积分
  287. if action == 'adjust_credit':
  288. if request.method == 'GET':
  289. return render(request, 'volunteer_arrangement/admin/adjust_credit.html')
  290. if request.method == 'POST':
  291. mobile = request.POST.get('mobile').strip()
  292. social_id = request.POST.get('social_id').strip()
  293. adjust_credit = request.POST.get('credit').strip()
  294. try:
  295. adjust_credit = int(adjust_credit)
  296. except Exception as e:
  297. print(e)
  298. return msg_and_direct(request, '/cq/volunteer/admin_management/adjust_credit/', '积分请输入数字')
  299. volunteer = Volunteer.get_by_mobile_social_id(mobile, social_id)
  300. if volunteer:
  301. volunteer.total_credit = volunteer.total_credit + adjust_credit
  302. volunteer.current_credit = volunteer.current_credit + adjust_credit
  303. volunteer.save()
  304. credit_record = CreditRecord()
  305. credit_record.volunteer = volunteer
  306. credit_record.reason = '管理员调整{}积分/{}'.format(volunteer.name, adjust_credit)
  307. credit_record.admin = None
  308. credit_record.change = adjust_credit
  309. credit_record.save()
  310. return msg_and_direct(request, '/cq/volunteer/admin_management/home/', '调整成功')
  311. else:
  312. return msg_and_direct(request, '/cq/volunteer/admin_management/adjust_credit/', '手机、身份证未匹配')
  313. # 导出现有的志愿者
  314. if action == 'export_volunteers':
  315. if request.method == 'GET':
  316. volunteer_list = Volunteer.volunteer_list()
  317. for v in volunteer_list: # 添加一个tab,用来避免excel打开身份证号码最后几位显示为0的问题
  318. v.social_id = '\t' + v.social_id
  319. # 获取数据,生成response
  320. response = HttpResponse(content_type='text/csv;charset=ANSI')
  321. response['Content-Disposition'] = 'attachment; filename="Volunteer_List.csv"'
  322. writer = csv.writer(response)
  323. # keys = monthly_report[0].keys()
  324. keys = ['ID', '姓名', '性别', '手机号码', '身份证号码', '政治面貌', '单位/学校', '居住区域(区或街道)', '是否激活', '微信ID', '目前积分', '总积分']
  325. writer.writerow(keys)
  326. for x in volunteer_list:
  327. x = model_to_dict(x)
  328. writer.writerow(x.values())
  329. return response
  330. def logout(request):
  331. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  332. if volunteer:
  333. if volunteer.wechat_id:
  334. volunteer.wechat_id = None
  335. volunteer.save()
  336. request.session.flush()
  337. return render(request, 'volunteer_arrangement/directPage.html',
  338. {'alertMsg': '已经退出', 'dirLink': '/cq/volunteer/'})
  339. def booking_service(request):
  340. # 志愿者注册服务时间页面
  341. if request.method == 'GET':
  342. booking_overall_status = []
  343. monthly_booking_status = []
  344. # count_month = []
  345. # current_year = datetime.now().year
  346. # current_month = datetime.now().month
  347. # 验证登陆状态
  348. if not request.session.get('volunteer_id'):
  349. request.session['redirect_uri'] = request.get_full_path()
  350. return render(request, 'volunteer_arrangement/directPage.html',
  351. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  352. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  353. # 如果有指定地址
  354. if request.GET.get('address'):
  355. address = request.GET.get('address')
  356. else:
  357. address = 'false'
  358. # 如果有日期就获取当天的报名状况
  359. if request.GET.get('date'):
  360. service_date = request.GET['date']
  361. if datetime.strptime(service_date, '%Y-%m-%d').date() < datetime.now().date():
  362. return render(request, 'volunteer_arrangement/directPage.html',
  363. {'alertMsg': '日期不能早于今天',
  364. 'dirLink': '/cq/volunteer/booking_service/?date={};address={}'.format
  365. (str(datetime.now().date()), address)})
  366. else:
  367. service_date = str(datetime.now().date())
  368. service_list = ServiceTimeSlot.search_by_date_and_address(service_date, address)
  369. # service_list_IDs = []
  370. # for service in service_list:
  371. # service_list_IDs.append(service.ID)
  372. booking_list = ServiceBooking.search_by_service_timeslot_list(service_list)
  373. # service_list_json = serializers.serialize('json', service_list)
  374. for service in service_list:
  375. service_dict = model_to_dict(service)
  376. service_exist_booking_count = len(booking_list.filter(timeslot_id=service))
  377. service_dict['current_booking'] = service_exist_booking_count
  378. # service_dict['date'] = service_dict['date'].strftime("%Y-%m-%d")
  379. service_dict['date'] = str(service_dict['date'])
  380. service_dict['start_time'] = service_dict['start_time'].strftime("%H:%M:%S")
  381. service_dict['end_time'] = service_dict['end_time'].strftime("%H:%M:%S")
  382. booking_overall_status.append(service_dict)
  383. selected_date = datetime.strptime(service_date, '%Y-%m-%d').date()
  384. current_year = selected_date.year
  385. current_month = selected_date.month
  386. monthly_service_list = ServiceTimeSlot.search_by_year_month_address(current_year, current_month, address)
  387. monthly_booking_list = ServiceBooking.search_by_service_timeslot_list(monthly_service_list)
  388. count_date = 0
  389. count_people = 0
  390. count_volunteer = 0
  391. count_month = []
  392. for service in monthly_service_list:
  393. # 只显示今天以及以后的日期
  394. if service.date >= datetime.today().date():
  395. service_dict = model_to_dict(service)
  396. service_exist_booking_count = len(monthly_booking_list.filter(timeslot_id=service))
  397. service_dict['current_booking'] = service_exist_booking_count
  398. service_dict['start_time'] = service_dict['start_time'].strftime("%H:%M:%S")
  399. service_dict['end_time'] = service_dict['end_time'].strftime("%H:%M:%S")
  400. monthly_booking_status.append(service_dict)
  401. # 根据日期,统计每天在指定的地点可以提供的志愿者服务总人数和当前人数
  402. if count_date == 0 and service_dict['date'].day != count_date:
  403. count_date = service_dict['date'].day
  404. count_people += service_dict['people_count']
  405. count_volunteer += service_dict['current_booking']
  406. elif service_dict['date'].day == count_date:
  407. count_people += service_dict['people_count']
  408. count_volunteer += service_dict['current_booking']
  409. else:
  410. count_month.append({'day': count_date, 'total': count_people, 'current': count_volunteer})
  411. count_date = service_dict['date'].day
  412. count_people = 0
  413. count_volunteer = 0
  414. count_people += service_dict['people_count']
  415. count_volunteer += service_dict['current_booking']
  416. # 防止循环最后一次漏掉
  417. if count_date != 0:
  418. count_month.append({'day': count_date, 'total': count_people, 'current': count_volunteer})
  419. return render(request, 'volunteer_arrangement/booking_service.html',
  420. {'booking_status': booking_overall_status, 'monthly_status': count_month,
  421. 'date': service_date, 'volunteer': volunteer})
  422. def my_service(request):
  423. # 验证登陆状态
  424. if not request.session.get('volunteer_id'):
  425. return render(request, 'volunteer_arrangement/directPage.html',
  426. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  427. my_booking_list = ServiceBooking.search_by_volunteer(request.session.get('volunteer_id'))
  428. return render(request, 'volunteer_arrangement/my_service.html', {'my_service': my_booking_list})
  429. def booking_info_api(request):
  430. # 获取指定日期注册查询信息
  431. service_date = request.GET['date']
  432. service_list = ServiceTimeSlot.search_by_date(service_date)
  433. booking_list = ServiceBooking.search_by_service_timeslot_list(service_list)
  434. booking_overall_status = []
  435. for service in service_list:
  436. service_dict = model_to_dict(service)
  437. service_exist_booking_count = len(booking_list.filter(timeslot_id=service))
  438. service_dict['current_booking'] = service_exist_booking_count
  439. service_dict['date'] = str(service_dict['date'])
  440. service_dict['start_time'] = service_dict['start_time'].strftime("%H:%M:%S")
  441. service_dict['end_time'] = service_dict['end_time'].strftime("%H:%M:%S")
  442. booking_overall_status.append(service_dict)
  443. booking_overall_status_json = json.dumps(booking_overall_status, ensure_ascii=False)
  444. return JsonResponse(json.loads(booking_overall_status_json), safe=False)
  445. # 用户注册服务和管理员删除服务功能
  446. def register(request, action):
  447. if action == 'add':
  448. # 验证登陆状态
  449. if not request.session.get('volunteer_id'):
  450. return render(request, 'volunteer_arrangement/directPage.html',
  451. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  452. # 验证是否传入timeslot_id
  453. if not request.GET.get('timeslot_id'):
  454. return render(request, 'volunteer_arrangement/directPage.html',
  455. {'alertMsg': '参数错误', 'dirLink': '/cq/volunteer'})
  456. # 如果有指定地址
  457. if request.GET.get('address'):
  458. address = request.GET.get('address')
  459. else:
  460. address = 'false'
  461. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  462. booking_timeslot = ServiceTimeSlot.get_by_id(request.GET.get('timeslot_id'))
  463. has_conflict = ServiceBooking.has_conflict_booking(volunteer, booking_timeslot)
  464. if has_conflict:
  465. # 一下N行是研发代码,测试完成后删除
  466. # from django.forms.models import model_to_dict
  467. # volunteer_json = volunteer.__dict__
  468. # volunteer_json = model_to_dict(volunteer)
  469. # return JsonResponse(volunteer_json, safe=False)
  470. # 研发代码结束
  471. return render(request, 'volunteer_arrangement/directPage.html',
  472. {'alertMsg': '这个报名和你已经报名的服务时间上有冲突',
  473. 'dirLink': '/cq/volunteer/booking_service/?date={};address={}'.format(
  474. str(booking_timeslot.date), address)})
  475. else:
  476. current_booking_count = len(ServiceBooking.search_by_service_timeslot(booking_timeslot))
  477. if current_booking_count < booking_timeslot.people_count:
  478. service_booking = ServiceBooking()
  479. service_booking.volunteer_id = volunteer
  480. service_booking.timeslot_id = booking_timeslot
  481. if ServiceBooking.add(service_booking) is True:
  482. booking_timeslot.booked_count += 1
  483. booking_timeslot.save()
  484. wechat_msg = WeChatMsg(volunteer.wechat_id,
  485. 'bsDiCVb3G2WERHvX4DJO83A-FonYYGRwTQD_Zp3fq7s', APPLICATION_NAME)
  486. wechat_msg.set_first('志愿者活动报名成功')
  487. wechat_msg.add_keyboard(volunteer.name)
  488. wechat_msg.add_keyboard('志愿者服务')
  489. wechat_msg.add_keyboard(str(booking_timeslot.date) + " " + str(booking_timeslot.start_time))
  490. wechat_msg.add_keyboard(str(booking_timeslot.date) + " " + str(booking_timeslot.end_time))
  491. wechat_msg.add_keyboard(booking_timeslot.address)
  492. wechat_msg.set_remark('志愿者服务报名成功,请准时参加。')
  493. wechat_msg.submit()
  494. return render(request, 'volunteer_arrangement/directPage.html',
  495. {'alertMsg': '报名成功',
  496. 'dirLink': '/cq/volunteer/home/'})
  497. else:
  498. return render(request, 'volunteer_arrangement/directPage.html',
  499. {'alertMsg': '你已经报名了',
  500. 'dirLink': '/cq/volunteer/home/'})
  501. return HttpResponse("test for conflict")
  502. if action == 'volunteer_self_delete':
  503. # 验证登陆状态
  504. if not request.session.get('volunteer_id'):
  505. return render(request, 'volunteer_arrangement/directPage.html',
  506. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  507. else:
  508. volunteer_id = request.session.get('volunteer_id')
  509. volunteer = Volunteer.get_by_id(volunteer_id)
  510. service_booking_id = request.GET.get('service_booking_id')
  511. service_booking = ServiceBooking.get_by_ID(service_booking_id)
  512. if volunteer.ID == service_booking.volunteer_id.ID: # 判断是否是本人删除
  513. if datetime.today().date() + timedelta(days=1) >= service_booking.timeslot_id.date:
  514. return msg_and_direct(request, '/cq/volunteer/my_service/', '距离活动开始时间过短,如果需要取消请联系管理员。')
  515. else:
  516. service_timeslot_id = service_booking.timeslot_id.ID
  517. service_timeslot = ServiceTimeSlot.get_by_id(service_timeslot_id)
  518. wechat_msg = WeChatMsg(volunteer.wechat_id,
  519. 'QKMJ1XFQoXWnxdc1ZDSXKraZpumcZbg_Ow8DdaP3Cuo', APPLICATION_NAME)
  520. wechat_msg.set_first('志愿者活动已取消')
  521. wechat_msg.add_keyboard('志愿者服务')
  522. wechat_msg.add_keyboard(str(service_timeslot.date) + " " + str(service_timeslot.start_time) + '-'
  523. + str(service_timeslot.end_time))
  524. wechat_msg.add_keyboard(service_timeslot.address)
  525. wechat_msg.set_remark('你的志愿者服务,已取消。')
  526. wechat_msg.submit()
  527. ServiceBooking.delete(service_timeslot_id, volunteer_id)
  528. service_timeslot.booked_count -= 1
  529. service_timeslot.save()
  530. return msg_and_direct(request, '/cq/volunteer/my_service/', '活动取消成功。')
  531. else:
  532. return HttpResponse('请使用本人账号删除')
  533. if action == 'delete':
  534. # 验证管理员登录状态
  535. if not request.session.get('admin_login'):
  536. return render(request, 'volunteer_arrangement/directPage.html',
  537. {'alertMsg': '请重新登录管理员', 'dirLink': '/cq/admin/'})
  538. # 验证是否传入timeslot_id and volunteer_id
  539. if not request.GET.get('timeslot_id') and request.GET.get('volunteer_id'):
  540. return render(request, 'volunteer_arrangement/directPage.html',
  541. {'alertMsg': '参数错误', 'dirLink': '/cq/volunteer'})
  542. volunteer_id = request.GET.get('volunteer_id')
  543. volunteer = Volunteer.get_by_id(volunteer_id)
  544. service_timeslot_id = request.GET.get('timeslot_id')
  545. service_timeslot = ServiceTimeSlot.get_by_id(service_timeslot_id)
  546. wechat_msg = WeChatMsg(volunteer.wechat_id,
  547. 'QKMJ1XFQoXWnxdc1ZDSXKraZpumcZbg_Ow8DdaP3Cuo', APPLICATION_NAME)
  548. wechat_msg.set_first('志愿者活动已取消')
  549. # wechat_msg.add_keyboard(volunteer.name)
  550. wechat_msg.add_keyboard('志愿者服务')
  551. wechat_msg.add_keyboard(str(service_timeslot.date) + " " + str(service_timeslot.start_time) + '-'
  552. + str(service_timeslot.end_time))
  553. # wechat_msg.add_keyboard(str(service_timeslot.date) + " " + str(service_timeslot.end_time))
  554. wechat_msg.add_keyboard(service_timeslot.address)
  555. wechat_msg.set_remark('你的志愿者服务,已被管理员取消。')
  556. wechat_msg.submit()
  557. ServiceBooking.delete(service_timeslot_id, volunteer_id)
  558. service_timeslot.booked_count -= 1
  559. service_timeslot.save()
  560. return render(request, 'volunteer_arrangement/directPage.html',
  561. {'alertMsg': '删除成功',
  562. 'dirLink': '/cq/volunteer/admin_management/delete_service/?date='
  563. + str(service_timeslot.date)})
  564. # 志愿者查看和兑换礼物
  565. @transaction.atomic
  566. def volunteer_bonus(request, action):
  567. # 验证登陆状态
  568. if not request.session.get('volunteer_id'):
  569. request.session['redirect_uri'] = '/cq/volunteer/bonus/list/'
  570. return render(request, 'volunteer_arrangement/directPage.html',
  571. {'alertMsg': '请登录', 'dirLink': '/cq/volunteer'})
  572. volunteer = Volunteer.get_by_id(request.session.get('volunteer_id'))
  573. if action == 'list':
  574. bonus_list = Bonus.all_available_bonus()
  575. url_prefix = get_media_url_prefix()
  576. return render(request, 'volunteer_arrangement/volunteer_bonus_list.html',
  577. {'bonus_list': bonus_list, 'volunteer': volunteer, 'url_prefix': url_prefix})
  578. if action == 'enroll':
  579. bonus = request.GET.get('bonus_id')
  580. bonus = Bonus.get_by_id(bonus)
  581. if bonus is None:
  582. return msg_and_direct(request, '/cq/volunteer/home/', '参数错误')
  583. if BonusRecord.is_exist(volunteer, bonus): # 检查是否已经兑换过
  584. return msg_and_direct(request, '/cq/volunteer/bonus/list/', '你已经兑换过了')
  585. if volunteer.current_credit < bonus.cost:
  586. return msg_and_direct(request, '/cq/volunteer/bonus/list/', '积分不足,请继续努力')
  587. if bonus.used_qty < bonus.total_qty:
  588. bonus.used_qty += 1
  589. bonus.save()
  590. bonus_record = BonusRecord()
  591. bonus_record.volunteer = volunteer
  592. bonus_record.bonus = bonus
  593. bonus_record.save()
  594. volunteer.current_credit -= bonus.cost
  595. volunteer.save()
  596. credit_record = CreditRecord()
  597. credit_record.volunteer = volunteer
  598. credit_record.reason = '{}兑换{}/{}奖励'.format(volunteer.name, bonus.id, bonus.name)
  599. credit_record.admin = None
  600. credit_record.change = bonus.cost * -1
  601. credit_record.save()
  602. wechat_msg = WeChatMsg(volunteer.wechat_id,
  603. 'wkjPXVLn_OT57IKINx3uInDlA9S1-XndV7bO4d_sbcQ', APPLICATION_NAME)
  604. wechat_msg.set_first(bonus.name + '兑换成功')
  605. wechat_msg.add_keyboard(str(datetime.today().date()))
  606. wechat_msg.add_keyboard('通过')
  607. wechat_msg.add_keyboard('请保留这条消息。我们的工作人员会尽快和你联系。')
  608. wechat_msg.set_remark('消耗{}积分,还剩{}积分'.format(bonus.cost, volunteer.current_credit))
  609. wechat_msg.submit()
  610. return msg_and_direct(request, '/cq/volunteer/home/', '兑换成功')
  611. if action == 'my_enrollment':
  612. bonus_record_list = BonusRecord.search_by_volunteer(volunteer)
  613. url_prefix = get_media_url_prefix()
  614. return render(request, 'volunteer_arrangement/volunteer_bonus_my_enrollment.html',
  615. {'bonus_record_list': bonus_record_list, 'volunteer': volunteer, 'url_prefix': url_prefix})
  616. # 管理员后台管理礼物
  617. def admin_bonus(request, action):
  618. # 验证管理员登录状态
  619. if not request.session.get('admin_login'):
  620. return render(request, 'volunteer_arrangement/directPage.html',
  621. {'alertMsg': '请重新登录管理员', 'dirLink': '/cq/volunteer/admin/'})
  622. if action == 'list':
  623. bonus_list = Bonus.get_bonus_list()
  624. url_prefix = get_media_url_prefix()
  625. return render(request, 'volunteer_arrangement/bonus/admin_list.html',
  626. {'bonus_list': bonus_list, 'url_prefix': url_prefix})
  627. if action == 'download_bonus_enrollment':
  628. bonus_id = request.GET.get('bonus_id')
  629. bonus = Bonus.get_by_id(bonus_id)
  630. bonus_list = BonusRecord.search_bonus_with_volunteer(bonus)
  631. for bonus in bonus_list: # 添加一个tab,用来避免excel打开身份证号码最后几位显示为0的问题
  632. bonus['volunteer__social_id'] = '\t' + bonus['volunteer__social_id']
  633. # 获取数据,生成response
  634. response = HttpResponse(content_type='text/csv;charset=ANSI')
  635. response['Content-Disposition'] = 'attachment; filename="Enrollment.csv"'
  636. writer = csv.writer(response)
  637. # keys = monthly_report[0].keys()
  638. keys = ['姓名', '性别', '手机号码', '身份证号码', '政治面貌', '学校/单位', '居住区域(区或街道)']
  639. writer.writerow(keys)
  640. for x in bonus_list:
  641. writer.writerow(x.values())
  642. return response
  643. if action == 'create':
  644. if request.method == 'GET':
  645. return render(request, 'volunteer_arrangement/bonus/create.html')
  646. if request.method == 'POST':
  647. bonus = Bonus()
  648. bonus.name = request.POST.get('name')
  649. bonus.description = request.POST.get('description')
  650. pic_filename = request.FILES.get('picture')
  651. if pic_filename is None:
  652. filename = None
  653. else:
  654. new_pic_name = hash(str(pic_filename) + str(datetime.now()))
  655. upload_file(request, filename='picture', prefix=new_pic_name)
  656. filename = str(new_pic_name) + '.' + get_ext(pic_filename)
  657. bonus.picture = filename
  658. bonus.type = request.POST.get('type')
  659. bonus.total_qty = request.POST.get('total_qty')
  660. bonus.cut_off_date = request.POST.get('cut_off_date')
  661. bonus.cost = request.POST.get('cost')
  662. bonus.save()
  663. return render(request, 'volunteer_arrangement/directPage.html',
  664. {'alertMsg': '添加成功', 'dirLink': '/cq/volunteer/admin_management/home/'})
  665. if action == 'delete':
  666. bonus_id = request.GET.get('bonus_id')
  667. if Bonus.del_bonus(bonus_id):
  668. return msg_and_direct(request, '/cq/volunteer/admin_management/home/', '删除成功')
  669. else:
  670. return msg_and_direct(request, '/cq/volunteer/admin_management/home/', '兑换已经有人报名了,不能删除')