init: 你学法我惠农·法润三湘促振兴抽奖项目
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
*.local
|
||||
.DS_Store
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>你学法我惠农·法润三湘促振兴</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+1162
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "nfcj",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.7.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue2": "^2.3.3",
|
||||
"vite": "^5.4.19"
|
||||
}
|
||||
}
|
||||
+509
@@ -0,0 +1,509 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="lottery-buttons">
|
||||
<div class="button-row">
|
||||
<img
|
||||
v-for="btn in buttons"
|
||||
:key="btn.name"
|
||||
:src="btn.src"
|
||||
:alt="btn.name"
|
||||
@click="startLottery(btn.name)"
|
||||
/>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<img
|
||||
v-for="btn in subButtons"
|
||||
:key="btn.name"
|
||||
:src="btn.src"
|
||||
:alt="btn.name"
|
||||
@click="startLottery(btn.name)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showPasswordDialog" class="dialog-mask" @click.self="closeDialog">
|
||||
<div class="dialog">
|
||||
<h3>请输入密码</h3>
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
@keyup.enter="confirmPassword"
|
||||
/>
|
||||
<p v-if="errorMsg" class="dialog-error">{{ errorMsg }}</p>
|
||||
<div class="dialog-actions">
|
||||
<button @click="closeDialog">取消</button>
|
||||
<button @click="confirmPassword">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="exporting" class="export-loading">导出中...</div>
|
||||
<div v-if="showDrawingDialog" class="dialog-mask" @click.self="closeDrawingDialog">
|
||||
<div class="drawing-dialog">
|
||||
<div class="drawing-text">{{ drawingText }}</div>
|
||||
<p v-if="apiError && !drawing" class="dialog-error">{{ apiError }}</p>
|
||||
<div v-else :class="['name-grid', gridClass]">
|
||||
<span v-for="(n, i) in displayNames" :key="i">{{ n }}</span>
|
||||
</div>
|
||||
<div class="drawing-actions">
|
||||
<button v-if="drawing" @click="stopDrawing">停止</button>
|
||||
<button v-if="!drawing && pendingBtn === 'ydj'" @click="exportWinners">
|
||||
导出中奖名单
|
||||
</button>
|
||||
<button v-if="!drawing" @click="closeDrawingDialog">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NAMES } from './names.js'
|
||||
|
||||
const API_BASE = 'https://api.hntgov.com/lylaw/api/lylaw'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
data() {
|
||||
return {
|
||||
buttons: [
|
||||
{ name: 'ydj', src: 'https://aliyunoss.hn12301.net/learnlaw/nf_ydj.png' },
|
||||
{ name: 'edj', src: 'https://aliyunoss.hn12301.net/learnlaw/nf_edj.png' },
|
||||
{ name: 'sdj', src: 'https://aliyunoss.hn12301.net/learnlaw/nf_sdj.png' }
|
||||
],
|
||||
subButtons: [
|
||||
{ name: 'cymd', src: 'https://aliyunoss.hn12301.net/learnlaw/nf_cymd.png' },
|
||||
{ name: 'zjmd', src: 'https://aliyunoss.hn12301.net/learnlaw/nf_zjmd.png' }
|
||||
],
|
||||
prizeNames: {
|
||||
ydj: '一等奖',
|
||||
edj: '二等奖',
|
||||
sdj: '三等奖'
|
||||
},
|
||||
prizeLevels: {
|
||||
ydj: 1,
|
||||
edj: 2,
|
||||
sdj: 3
|
||||
},
|
||||
prizeCounts: {
|
||||
ydj: 50,
|
||||
edj: 200,
|
||||
sdj: 375
|
||||
},
|
||||
showPasswordDialog: false,
|
||||
password: '',
|
||||
errorMsg: '',
|
||||
pendingBtn: '',
|
||||
showDrawingDialog: false,
|
||||
exporting: false,
|
||||
drawingText: '',
|
||||
drawing: false,
|
||||
rollingNames: [],
|
||||
winnerNames: [],
|
||||
apiWinners: null,
|
||||
apiError: '',
|
||||
apiPromise: null,
|
||||
rollTimer: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayNames() {
|
||||
return this.drawing ? this.rollingNames : this.winnerNames
|
||||
},
|
||||
gridClass() {
|
||||
const len = this.displayNames.length
|
||||
if (len <= 50) return 'cols-5'
|
||||
if (len <= 200) return 'cols-10'
|
||||
return 'cols-15'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startLottery(name) {
|
||||
if (name === 'cymd') {
|
||||
this.exportAttendUsers()
|
||||
return
|
||||
}
|
||||
if (name === 'zjmd') {
|
||||
this.exportWinners()
|
||||
return
|
||||
}
|
||||
this.pendingBtn = name
|
||||
this.password = ''
|
||||
this.errorMsg = ''
|
||||
this.showPasswordDialog = true
|
||||
},
|
||||
confirmPassword() {
|
||||
if (this.password === '123456') {
|
||||
this.showPasswordDialog = false
|
||||
const prize = this.prizeNames[this.pendingBtn]
|
||||
if (prize) this.beginDrawing(prize)
|
||||
} else {
|
||||
this.errorMsg = '密码错误'
|
||||
}
|
||||
},
|
||||
closeDialog() {
|
||||
this.showPasswordDialog = false
|
||||
},
|
||||
beginDrawing(prize) {
|
||||
this.drawingText = prize + '抽取中...'
|
||||
this.drawing = true
|
||||
this.rollingNames = []
|
||||
this.winnerNames = []
|
||||
this.apiWinners = null
|
||||
this.apiError = ''
|
||||
this.showDrawingDialog = true
|
||||
this.rollNames()
|
||||
this.rollTimer = setInterval(this.rollNames, 200)
|
||||
const level = this.prizeLevels[this.pendingBtn]
|
||||
this.apiPromise = fetch(API_BASE + '/chouJiangWeek?wenjuan_id=1002&level=' + level, {
|
||||
method: 'POST'
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((res) => {
|
||||
if (res.code === 0 && res.Data && Array.isArray(res.Data.wenjuanWinDetails)) {
|
||||
this.apiWinners = res.Data.wenjuanWinDetails.map((d) => d.user_name)
|
||||
} else {
|
||||
this.apiError = res.msg || '接口请求失败'
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.apiError = '接口请求失败'
|
||||
})
|
||||
},
|
||||
rollNames() {
|
||||
const count = this.prizeCounts[this.pendingBtn] || 50
|
||||
const pool = NAMES.slice()
|
||||
const picked = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
picked.push(pool.splice(Math.floor(Math.random() * pool.length), 1)[0])
|
||||
}
|
||||
this.rollingNames = picked
|
||||
},
|
||||
stopDrawing() {
|
||||
if (this.rollTimer) {
|
||||
clearInterval(this.rollTimer)
|
||||
this.rollTimer = null
|
||||
}
|
||||
this.drawing = false
|
||||
this.drawingText = this.prizeNames[this.pendingBtn] + '中奖名单'
|
||||
const show = () => {
|
||||
if (this.apiWinners) this.winnerNames = this.apiWinners
|
||||
}
|
||||
if (this.apiWinners || this.apiError) {
|
||||
show()
|
||||
} else {
|
||||
this.apiPromise.then(show)
|
||||
}
|
||||
},
|
||||
closeDrawingDialog() {
|
||||
if (this.rollTimer) {
|
||||
clearInterval(this.rollTimer)
|
||||
this.rollTimer = null
|
||||
}
|
||||
this.showDrawingDialog = false
|
||||
},
|
||||
requestExport(url) {
|
||||
this.exporting = true
|
||||
const call = (method) => fetch(url, { method })
|
||||
call('POST')
|
||||
.then((r) => {
|
||||
if (r.status === 405) return call('GET')
|
||||
return r
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((res) => {
|
||||
if (res.code === 0 && res.Data) {
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.style.display = 'none'
|
||||
iframe.src = res.Data.indexOf('http') === 0 ? res.Data : 'https://api.hntgov.com' + res.Data
|
||||
document.body.appendChild(iframe)
|
||||
setTimeout(() => iframe.remove(), 60000)
|
||||
} else {
|
||||
alert(res.msg || '导出失败')
|
||||
}
|
||||
})
|
||||
.catch(() => alert('导出失败'))
|
||||
.finally(() => {
|
||||
this.exporting = false
|
||||
})
|
||||
},
|
||||
exportWinners() {
|
||||
this.requestExport(API_BASE + '/exportThisTimeWinUserReport?wenjuan_id=1002')
|
||||
},
|
||||
exportAttendUsers() {
|
||||
const d = new Date()
|
||||
const periodTime =
|
||||
d.getFullYear() +
|
||||
'-' +
|
||||
String(d.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(d.getDate()).padStart(2, '0')
|
||||
this.requestExport(
|
||||
API_BASE + '/exportAttendUserReport?wenjuan_id=1002&period_time=' + periodTime
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'ALiMaMa';
|
||||
src: url('./components/ALiMaMa.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
input {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
#app {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
text-align: center;
|
||||
background: url('https://aliyunoss.hn12301.net/learnlaw/nf_cjbj.jpg') no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.lottery-buttons {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 16vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2vh;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 4vw;
|
||||
}
|
||||
|
||||
.button-row:last-child {
|
||||
gap: 10vw;
|
||||
}
|
||||
|
||||
.lottery-buttons img {
|
||||
zoom: 0.5;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
width: 320px;
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dialog h3 {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
|
||||
.dialog input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
caret-color: transparent;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
margin: 8px 0 0;
|
||||
color: #e53935;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.dialog-actions button {
|
||||
padding: 6px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialog-actions button:first-child {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.dialog-actions button:last-child {
|
||||
background: #e53935;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.drawing-dialog {
|
||||
width: 85vw;
|
||||
padding: 24px 32px;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drawing-text {
|
||||
display: inline-block;
|
||||
padding: 12px 56px 16px;
|
||||
background: linear-gradient(180deg, #55985e 0%, #4a8952 50%, #3f7546 100%);
|
||||
border: 2px solid rgba(254, 215, 40, 0.85);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
font-family: 'ALiMaMa', Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 8px;
|
||||
color: #fed728;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.name-grid {
|
||||
margin-top: 16px;
|
||||
display: grid;
|
||||
padding: 16px;
|
||||
background: linear-gradient(180deg, #55985e 0%, #4a8952 50%, #3f7546 100%);
|
||||
border: 2px solid rgba(255, 255, 255, 0.35);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.name-grid.cols-5 {
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.name-grid.cols-10 {
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.name-grid.cols-15 {
|
||||
grid-template-columns: repeat(15, 1fr);
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.name-grid span {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
|
||||
padding: 6px 8px;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.name-grid.cols-10 span {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.name-grid.cols-15 span {
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.drawing-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.drawing-actions button {
|
||||
padding: 12px 44px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.6);
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(180deg, #ff7043 0%, #e53935 60%, #c62828 100%);
|
||||
color: #fff;
|
||||
font-family: 'ALiMaMa', Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 20px;
|
||||
letter-spacing: 4px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
||||
transition: transform 0.15s, box-shadow 0.15s, filter 0.15s;
|
||||
}
|
||||
|
||||
.drawing-actions button:hover {
|
||||
filter: brightness(1.08);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
.drawing-actions button:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.export-loading {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 16px 40px;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
letter-spacing: 2px;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
@media (max-height: 900px) {
|
||||
.drawing-text {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.name-grid.cols-10 {
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.name-grid.cols-10 span {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.name-grid.cols-15 {
|
||||
gap: 3px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.name-grid.cols-15 span {
|
||||
padding: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
new Vue({
|
||||
render: (h) => h(App)
|
||||
}).$mount('#app')
|
||||
+1002
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue2'
|
||||
|
||||
export default defineConfig({
|
||||
base: '/nfcj/',
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
open: true
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user