61 changed files with 1209 additions and 121 deletions
@ -1,4 +1,7 @@
@@ -1,4 +1,7 @@
|
||||
# 程序自身数据源配置 |
||||
spring.datasource.url=jdbc:mysql://10.100.0.108:3306/idle_game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true |
||||
spring.datasource.username=root |
||||
spring.datasource.password=mBMjp2v74c7MzhC/5RGeXF1V3E+AcRFs1f5OH6PDHi3nWaM3njaaoewswq8Sl7/AY631t0sONVDG672pX4mFpZx/8xex8BJP3uX1wUu9NGpTCSHskb5cD6KZMNV4jNsfoqxFRyJq8yk86djPsCfR4ch0sPnLH+LCg9XY1DAw8szh93QnKDkiImq2JLkaIwG3R3t8dNWv1wVoMR6vVecPsEUyPJu5vsrvJhjP3uAL7jZYJVGZG6bkrpV3R6I6mja0QnTdF41NCL5Ex0TINSi7GKnrALjZ0qWcT9fe2bTUCKq50+CtVEAQnEz2ZJpYUaBZXJbHh4OrUyqjAmA5s7IelQ== |
||||
spring.datasource.password=123456 |
||||
|
||||
login.token.timeout=10080 |
||||
login.token.domain= |
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
package vip.xumy.idle.server.conf; |
||||
|
||||
import java.nio.charset.Charset; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.converter.HttpMessageConverter; |
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature; |
||||
import com.alibaba.fastjson.support.config.FastJsonConfig; |
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; |
||||
|
||||
/** Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@Configuration |
||||
public class Configer { |
||||
|
||||
@Bean |
||||
public HttpMessageConverter<?> configureMessageConverters() { |
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); |
||||
FastJsonConfig config = new FastJsonConfig(); |
||||
config.setSerializerFeatures( |
||||
SerializerFeature.WriteMapNullValue, |
||||
SerializerFeature.WriteNullStringAsEmpty, |
||||
SerializerFeature.WriteNullNumberAsZero, |
||||
SerializerFeature.WriteNullListAsEmpty, |
||||
SerializerFeature.WriteNullBooleanAsFalse, |
||||
SerializerFeature.DisableCircularReferenceDetect |
||||
); |
||||
|
||||
converter.setFastJsonConfig(config); |
||||
converter.setDefaultCharset(Charset.forName("UTF-8")); |
||||
List<MediaType> mediaTypeList = new ArrayList<>(); |
||||
mediaTypeList.add(MediaType.APPLICATION_JSON); |
||||
converter.setSupportedMediaTypes(mediaTypeList); |
||||
return converter; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
package vip.xumy.idle.server.ctrl; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
||||
import org.springframework.web.bind.annotation.RequestBody; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import vip.xumy.core.pojo.com.BaseResponse; |
||||
import vip.xumy.idle.server.pojo.Archive; |
||||
import vip.xumy.idle.server.service.ArchiveService; |
||||
import vip.xumy.idle.server.util.LoginUtil; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@RestController |
||||
@RequestMapping("archive") |
||||
public class ArchiveController { |
||||
@Autowired |
||||
private ArchiveService archiveService; |
||||
|
||||
@PostMapping |
||||
public BaseResponse saveArchive(@RequestBody Archive archive) { |
||||
String userId = LoginUtil.getUserId(); |
||||
if (userId == null) { |
||||
return new BaseResponse(true, "请先登录"); |
||||
} |
||||
archive.setUsername(userId); |
||||
archiveService.saveOrUpdate(archive); |
||||
return new BaseResponse(true, "存档保存成功"); |
||||
} |
||||
|
||||
@GetMapping |
||||
public BaseResponse getArchive(String version) { |
||||
String userId = LoginUtil.getUserId(); |
||||
Archive archive = archiveService.getByKey(userId, version); |
||||
if (archive == null) { |
||||
return new BaseResponse(false, "未查询到你的存档"); |
||||
} |
||||
return new BaseResponse(archive.getArchive()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
package vip.xumy.idle.server.mapper; |
||||
|
||||
import org.apache.ibatis.annotations.Mapper; |
||||
import org.apache.ibatis.annotations.Update; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
||||
import vip.xumy.idle.server.pojo.Archive; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@Mapper |
||||
public interface IArchiveMapper extends BaseMapper<Archive> { |
||||
|
||||
@Update(""" |
||||
UPDATE archive |
||||
SET |
||||
lv = #{lv}, |
||||
coins = #{coins}, |
||||
strengthen_lv= #{strengthenLv} , |
||||
archive = #{archive} |
||||
WHERE |
||||
username = #{username} |
||||
and version = #{version} |
||||
""") |
||||
void update(Archive archive); |
||||
|
||||
} |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
package vip.xumy.idle.server.pojo; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
||||
import lombok.Getter; |
||||
import lombok.Setter; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@Setter |
||||
@Getter |
||||
@TableName("archive") |
||||
public class Archive { |
||||
|
||||
private String username; |
||||
private String version; |
||||
private int lv; |
||||
private long coins; |
||||
private int strengthenLv; |
||||
private String archive; |
||||
|
||||
} |
@ -1,29 +1,33 @@
@@ -1,29 +1,33 @@
|
||||
package vip.xumy.idle.server.pojo; |
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField; |
||||
import com.baomidou.mybatisplus.annotation.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
|
||||
import lombok.Getter; |
||||
import lombok.Setter; |
||||
|
||||
/** Ownership belongs to the company |
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年4月18日 |
||||
* @author:mengyxu |
||||
* @date:2025年4月18日 |
||||
*/ |
||||
|
||||
@Setter |
||||
@Getter |
||||
@TableName("user") |
||||
public class User { |
||||
|
||||
private String useranme; |
||||
|
||||
@TableId |
||||
private String username; |
||||
@JSONField(serialize = false) |
||||
private String password; |
||||
private String state; |
||||
private String phone; |
||||
private String idCard; |
||||
private String name; |
||||
private String registerTime; |
||||
private String last_login; |
||||
|
||||
private String lastLogin; |
||||
|
||||
} |
||||
|
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
package vip.xumy.idle.server.service; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
|
||||
import vip.xumy.idle.server.mapper.IArchiveMapper; |
||||
import vip.xumy.idle.server.pojo.Archive; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@Service |
||||
public class ArchiveService { |
||||
@Autowired |
||||
private IArchiveMapper archiveMapper; |
||||
|
||||
public void saveOrUpdate(Archive archive) { |
||||
Archive exit = getByKey(archive.getUsername(), archive.getVersion()); |
||||
if (exit == null) { |
||||
archiveMapper.insert(archive); |
||||
} else { |
||||
archiveMapper.update(archive); |
||||
} |
||||
} |
||||
|
||||
public Archive getByKey(String username, String version) { |
||||
QueryWrapper<Archive> wrapper = new QueryWrapper<>(); |
||||
wrapper.eq("username", username); |
||||
wrapper.eq("version", version); |
||||
return archiveMapper.selectOne(wrapper); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
package vip.xumy.idle.server.service; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import vip.xumy.core.utils.DateUtil; |
||||
import vip.xumy.core.utils.StringUtil; |
||||
import vip.xumy.idle.server.mapper.IUserMapper; |
||||
import vip.xumy.idle.server.pojo.User; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2025年5月19日 |
||||
*/ |
||||
|
||||
@Service |
||||
public class UserService { |
||||
@Autowired |
||||
private IUserMapper userMapper; |
||||
|
||||
public User login(User param) { |
||||
String username = param.getUsername(); |
||||
String password = param.getPassword(); |
||||
if (StringUtil.isEmpty(username, password)) { |
||||
return null; |
||||
} |
||||
User user = getById(username); |
||||
if (user != null) { |
||||
if (password.equals(user.getPassword())) { |
||||
userMapper.login(username); |
||||
return user; |
||||
} else { |
||||
return null; |
||||
} |
||||
} else { |
||||
String time = DateUtil.format(); |
||||
param.setState("0"); |
||||
param.setRegisterTime(time); |
||||
param.setLastLogin(time); |
||||
userMapper.insert(param); |
||||
return param; |
||||
} |
||||
} |
||||
|
||||
public User getById(String username) { |
||||
return userMapper.selectById(username); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,205 @@
@@ -0,0 +1,205 @@
|
||||
package vip.xumy.idle.server.util; |
||||
|
||||
import javax.servlet.http.Cookie; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.annotation.Value; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import vip.xumy.core.golbal.GlobalBuffer; |
||||
import vip.xumy.core.pojo.com.Cache; |
||||
import vip.xumy.core.utils.StringUtil; |
||||
import vip.xumy.idle.server.pojo.User; |
||||
|
||||
/** |
||||
* Ownership belongs to the company |
||||
* |
||||
* @author:mengyxu |
||||
* @date:2024年3月5日 |
||||
*/ |
||||
|
||||
//@Log4j2
|
||||
@Component |
||||
public class LoginUtil { |
||||
public static final String TIKEN_KEY_PREFIX = "token-"; |
||||
public static final String LOGIN_COOKIE_NAME = "token"; |
||||
|
||||
@Value("${login.token.timeout}") |
||||
public void setTimeout(Integer timeout) { |
||||
LoginUtil.timeout = timeout; |
||||
} |
||||
|
||||
private static Integer timeout; |
||||
|
||||
@Value("${login.token.domain}") |
||||
public void setDomain(String domain) { |
||||
LoginUtil.domain = domain; |
||||
} |
||||
|
||||
private static String domain; |
||||
|
||||
private static HttpServletRequest request; |
||||
|
||||
@Autowired |
||||
public void setRequest(HttpServletRequest request) { |
||||
LoginUtil.request = request; |
||||
} |
||||
|
||||
private static HttpServletResponse response; |
||||
|
||||
@Autowired |
||||
public void setResponse(HttpServletResponse response) { |
||||
LoginUtil.response = response; |
||||
} |
||||
|
||||
private static String getTokenKey(String userId) { |
||||
return TIKEN_KEY_PREFIX + userId; |
||||
} |
||||
|
||||
public static boolean isLogin(String userId) { |
||||
Cache cache = GlobalBuffer.getCache(getTokenKey(userId)); |
||||
return !Cache.isEmpty(cache); |
||||
} |
||||
|
||||
public static void remveLoginInfo(String userId) { |
||||
String tokenKey = LoginUtil.getTokenKey(userId); |
||||
Cache token = GlobalBuffer.getCache(tokenKey); |
||||
if (!Cache.isEmpty(token)) { |
||||
String value = token.getValue(); |
||||
GlobalBuffer.removeCache(value.substring(0, 10)); |
||||
GlobalBuffer.removeCache(tokenKey); |
||||
} |
||||
} |
||||
|
||||
public static void saveLoginInfo(User user) { |
||||
// 删除旧的token信息
|
||||
String userId = user.getUsername(); |
||||
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId)); |
||||
if (!Cache.isEmpty(exitToken)) { |
||||
String value = exitToken.getValue(); |
||||
GlobalBuffer.removeCache(value.substring(0, 10)); |
||||
} |
||||
|
||||
// 计算新的token
|
||||
String ip = getIpAddr(); |
||||
String seq = GlobalBuffer.getSeq(); |
||||
String token = seq + StringUtil.md5(user.getUsername() + ip + System.currentTimeMillis(), false); |
||||
|
||||
// 保存用户token
|
||||
GlobalBuffer.addCache(LoginUtil.getTokenKey(userId), new Cache(token, timeout * 60)); |
||||
// 保存token的用户信息
|
||||
GlobalBuffer.addCache(seq, new Cache(user, timeout * 60)); |
||||
|
||||
LoginUtil.addToken(token, response); |
||||
|
||||
} |
||||
|
||||
private static void addToken(String token, HttpServletResponse response) { |
||||
Cookie cookie = new Cookie(LOGIN_COOKIE_NAME, token); |
||||
if (!StringUtil.isEmpty(domain)) { |
||||
cookie.setDomain(domain); |
||||
} |
||||
cookie.setPath("/"); |
||||
response.addCookie(cookie); |
||||
} |
||||
|
||||
public static User getUserInfo(String token, boolean refresh) { |
||||
if (StringUtil.isEmpty(token)) { |
||||
token = getToken(); |
||||
} |
||||
User empty = new User(); |
||||
if (StringUtil.isEmpty(token) || token.length() != 42) { |
||||
return empty; |
||||
} |
||||
Cache userCache = GlobalBuffer.getCache(token.substring(0, 10)); |
||||
if (Cache.isEmpty(userCache)) { |
||||
return empty; |
||||
} |
||||
User user = userCache.getValue(); |
||||
String userId = user.getUsername(); |
||||
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId)); |
||||
if (Cache.isEmpty(exitToken)) { |
||||
return empty; |
||||
} |
||||
if (StringUtil.equals(token, exitToken.getValue())) { |
||||
if (refresh) { |
||||
userCache.refresh(); |
||||
exitToken.refresh(); |
||||
} |
||||
return user; |
||||
} |
||||
return empty; |
||||
} |
||||
|
||||
public static String getUserId() { |
||||
return getUserInfo(null, false).getUsername(); |
||||
} |
||||
|
||||
public static String getUserIdAndRefresh() { |
||||
return getUserInfo(null, true).getUsername(); |
||||
} |
||||
|
||||
public static User getUserInfo() { |
||||
return getUserInfo(null, false); |
||||
} |
||||
|
||||
public static void loginOut() { |
||||
String token = LoginUtil.getToken(); |
||||
if (!StringUtil.isEmpty(token)) { |
||||
String seq = token.substring(0, 10); |
||||
Cache userCache = GlobalBuffer.getCache(seq); |
||||
if (!Cache.isEmpty(userCache)) { |
||||
User user = userCache.getValue(); |
||||
String userId = user.getUsername(); |
||||
GlobalBuffer.removeCache(getTokenKey(userId)); |
||||
} |
||||
GlobalBuffer.removeCache(seq); |
||||
} |
||||
} |
||||
|
||||
public static String getToken() { |
||||
Cookie[] cookies = request.getCookies(); |
||||
if (cookies == null) { |
||||
return null; |
||||
} |
||||
for (Cookie cookie : cookies) { |
||||
if (LOGIN_COOKIE_NAME.equals(cookie.getName())) { |
||||
return cookie.getValue(); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 获取访问者IP |
||||
* |
||||
* 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。 |
||||
* |
||||
* 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割), 如果还不存在则调用Request |
||||
* .getRemoteAddr()。 |
||||
* |
||||
* @param request |
||||
* @return |
||||
*/ |
||||
public static String getIpAddr() { |
||||
String ip = request.getHeader("X-Real-IP"); |
||||
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) { |
||||
return ip; |
||||
} |
||||
ip = request.getHeader("X-Forwarded-For"); |
||||
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) { |
||||
// 多次反向代理后会有多个IP值,第一个为真实IP。
|
||||
int index = ip.indexOf(','); |
||||
if (index != -1) { |
||||
return ip.substring(0, index); |
||||
} else { |
||||
return ip; |
||||
} |
||||
} else { |
||||
return request.getRemoteAddr(); |
||||
} |
||||
} |
||||
|
||||
} |
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
let commit; |
||||
|
||||
export const setCommit = (data) => { |
||||
commit = data; |
||||
}; |
||||
export const post = (url, data) => { |
||||
const t = new Date().getTime(); |
||||
data.t = t; |
||||
const options: any = { |
||||
method: 'POST', |
||||
credentials: 'same-origin', // 设置为 同源 以发送 Cookie
|
||||
body: JSON.stringify(data), |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
}, |
||||
}; |
||||
return new Promise((reslove, reject) => { |
||||
fetch(url, options) |
||||
.then(responseToJson) |
||||
.then((data) => reslove(getResult(data))) |
||||
.catch((error) => reslove(false)); |
||||
}); |
||||
}; |
||||
export const get = (url, data?) => { |
||||
const t = new Date().getTime(); |
||||
if (data) { |
||||
data.t = t; |
||||
const params = new URLSearchParams(data); |
||||
url += '?' + params; |
||||
} else { |
||||
url += '?t=' + t; |
||||
} |
||||
const options: any = { |
||||
method: 'GET', |
||||
credentials: 'same-origin', // 设置为 同源 以发送 Cookie
|
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
}, |
||||
}; |
||||
return new Promise((reslove, reject) => { |
||||
fetch(url.toString(), options) |
||||
.then(responseToJson) |
||||
.then((data) => reslove(getResult(data))) |
||||
.catch((error) => reslove(false)); |
||||
}); |
||||
}; |
||||
|
||||
const responseToJson = (response) => { |
||||
if (response.ok) { |
||||
return response.json(); |
||||
} else { |
||||
commit('set_sys_info', { msg: '网络错误', type: 'warning' }); |
||||
} |
||||
}; |
||||
|
||||
const getResult = (data) => { |
||||
if (data.message) { |
||||
commit('set_sys_info', { msg: data.message, type: data.success ? 'win' : 'warning' }); |
||||
} |
||||
return data.data; |
||||
}; |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
import { post, get, setCommit } from './base'; |
||||
|
||||
export { setCommit }; |
||||
|
||||
export const api_root = '/api'; |
||||
const urls = { |
||||
login: api_root + '/public/login', |
||||
archive: api_root + '/archive', |
||||
}; |
||||
export const loginOrRegister = (param) => { |
||||
return post(urls.login, param); |
||||
}; |
||||
export const getUser = () => { |
||||
return get(urls.login); |
||||
}; |
||||
export const uploadArchive = (archive) => { |
||||
return post(urls.archive, archive); |
||||
}; |
||||
export const downArchive = (param) => { |
||||
return get(urls.archive, param); |
||||
}; |
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
export const title = '系统设置(ESC)'; |
||||
export const action = ['保存设置', '取消']; |
||||
export const music = ['背景音乐', '完全关闭', '最小音量', '正常音量']; |
||||
export const battle = ['战斗日志', '显示', '隐藏']; |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
<template> |
||||
<Dialog :title="t('login.0')" v-model="state.showLogin" :top="state.mobile ? '5rem' : '10rem'" |
||||
:left="state.mobile ? '2rem' : '10rem'" padding="0" :z="50" :obscured="true"> |
||||
<div class="login"> |
||||
<div class="item"> |
||||
<div class="label">{{ t('login.1') }}: </div> |
||||
<input type="text" v-model="user.username"><br> |
||||
</div> |
||||
<div class="item"> |
||||
<div class="label">{{ t('login.2') }}: </div> |
||||
<input type="password" v-model="user.password"><br> |
||||
</div> |
||||
<button class="button" @click="login">{{ t('login.3') }}</button> |
||||
</div> |
||||
</Dialog> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { reactive, onMounted, ref, computed } from "vue"; |
||||
import { useI18n } from "vue3-i18n"; |
||||
import { Dialog } from "@/components"; |
||||
import { deepCopy, MD5 } from "@/tool"; |
||||
import { loginOrRegister } from "@/api"; |
||||
|
||||
const { t } = useI18n(); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const user = reactive({ |
||||
username: '', |
||||
password: '', |
||||
}) |
||||
|
||||
const login = () => { |
||||
const username = user.username; |
||||
const password = user.password; |
||||
if (!username) { |
||||
commit('set_sys_info', { msg: t('login.4'), type: 'warning' }) |
||||
return; |
||||
} |
||||
if (!password) { |
||||
commit('set_sys_info', { msg: t('login.5'), type: 'warning' }) |
||||
return; |
||||
} |
||||
const param = { username: username, password: MD5(password) }; |
||||
loginOrRegister(param).then(rsp => { |
||||
rsp && (state.showLogin = false); |
||||
}) |
||||
} |
||||
|
||||
onMounted(() => { }); |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.login { |
||||
padding: 1rem; |
||||
|
||||
.item { |
||||
padding: 0.5rem 0; |
||||
|
||||
.label { |
||||
text-align: left; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
<template> |
||||
<Tooltip :infos="[t('title')]" width="10rem"> |
||||
<img class="menu-img" :src="menu_icons.settings" @click="showMenu"> |
||||
</Tooltip> |
||||
|
||||
<Dialog :title="t('title')" v-model="show" top="4rem" :left="state.mobile ? '4%' : '8%'" padding="0.7rem" :z="49" |
||||
@close="state.curMenu = null"> |
||||
<div class="setting"> |
||||
<div class="item"> |
||||
<div class="label">{{ t('music.0') }}:</div> |
||||
<div class="options"> |
||||
<input type="radio" id="none" :value="0" v-model="settings.music"> {{ t('music.1') }} |
||||
<input type="radio" id="min" :value="0.01" v-model="settings.music"> {{ t('music.2') }} |
||||
<input type="radio" id="normal" :value="0.2" v-model="settings.music"> {{ t('music.3') }} |
||||
</div> |
||||
</div> |
||||
<div class="item"> |
||||
<div class="label">{{ t('battle.0') }}:</div> |
||||
<div class="options"> |
||||
<input type="radio" :value="1" v-model="settings.battle"> {{ t('battle.1') }} |
||||
<input type="radio" :value="0" v-model="settings.battle"> {{ t('battle.2') }} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="footer"> |
||||
<button class="button" @click="saveSettings">{{ t('action.0') }}</button> |
||||
<button class="button" @click="showMenu">{{ t('action.1') }}</button> |
||||
</div> |
||||
</Dialog> |
||||
|
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { useStore } from "vuex"; |
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from "vue"; |
||||
import { Tooltip, Dialog } from "@/components" |
||||
import { menu_icons } from "@/config"; |
||||
import { createt } from "@/config/i18n"; |
||||
import { store_name_config, key_name_config, getFromStore, insertToStore } from "@/tool"; |
||||
|
||||
const t = createt('setting.'); |
||||
const { state, commit, dispatch } = useStore(); |
||||
const show = computed(() => { |
||||
return state.curMenu == 'setting'; |
||||
}); |
||||
const settings = ref({ |
||||
type: 'setting', |
||||
music: 0.01, |
||||
battle: 1 |
||||
}) |
||||
|
||||
const saveSettings = () => { |
||||
insertToStore(store_name_config, settings.value); |
||||
set(); |
||||
showMenu(); |
||||
} |
||||
|
||||
const set = () => { |
||||
dispatch('set_music_volume', settings.value.music); |
||||
state.battleLog = settings.value.battle; |
||||
} |
||||
|
||||
const readSetting = () => { |
||||
getFromStore(store_name_config, settings.value.type).then((rsp: any) => { |
||||
if (rsp) { |
||||
settings.value = rsp |
||||
set(); |
||||
}; |
||||
}); |
||||
} |
||||
|
||||
const showMenu = () => { |
||||
state.curMenu = show.value ? null : 'setting'; |
||||
} |
||||
|
||||
const keydown = (e) => { |
||||
if (state.curMenu != null) { |
||||
return; |
||||
} |
||||
if (e.keyCode == 27 && !e.ctrlKey) { |
||||
setTimeout(() => { |
||||
showMenu(); |
||||
}, 50); |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
document.addEventListener('keydown', keydown, true) |
||||
readSetting(); |
||||
}); |
||||
onBeforeUnmount(() => { |
||||
document.removeEventListener('keydown', keydown) |
||||
}) |
||||
|
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.setting { |
||||
width: 32rem; |
||||
font-size: 1rem; |
||||
padding-top: 1rem; |
||||
|
||||
.label { |
||||
float: left; |
||||
width: 25%; |
||||
text-align: right; |
||||
} |
||||
|
||||
.options { |
||||
float: right; |
||||
width: 73%; |
||||
text-align: left; |
||||
} |
||||
|
||||
.item { |
||||
height: 2rem; |
||||
} |
||||
|
||||
.footer { |
||||
padding-top: 1rem; |
||||
} |
||||
} |
||||
|
||||
@media only screen and (max-width: 768px) { |
||||
.setting { |
||||
width: 23.5rem; |
||||
margin-top: 0.5rem; |
||||
font-size: 0.8rem; |
||||
|
||||
.footer { |
||||
margin-top: 0.5rem; |
||||
} |
||||
|
||||
} |
||||
} |
||||
</style> |
Loading…
Reference in new issue