feat(gvg): 征战中原排行榜奖励

This commit is contained in:
luying
2023-02-04 12:08:29 +08:00
parent fc2a86ad81
commit eb772484c2
21 changed files with 678 additions and 100 deletions

View File

@@ -257,6 +257,8 @@ export enum REDIS_KEY {
GA_HISTORY_CITY = 'gaHisCity', // 诸侯混战打开过的城池页面
GVG_VESTIGE_MEMBER = 'vestigeUsr', // 玩家一个遗迹的积分
GVG_VESTIGE_MEMBER_ALL = 'vestigeUsrAll', // 玩家所有遗迹积分
GVG_VESTIGE_LEAGUE = 'vestigeLeague', // 联军所有遗迹积分
LEAGUE_INFO ="leagueInfo", // 联军信息
}
// 各排行榜对应hash的key
@@ -311,6 +313,8 @@ export function getInfoKeyByRedisKey(redisKey: REDIS_KEY) {
return { infoKey: REDIS_KEY.USER_INFO, extraKey: [] };
case REDIS_KEY.GVG_VESTIGE_MEMBER_ALL: // 全遗迹玩家排行榜
return { infoKey: REDIS_KEY.USER_INFO, extraKey: [] };
case REDIS_KEY.GVG_VESTIGE_LEAGUE: // 遗迹联军排行榜
return { infoKey: REDIS_KEY.LEAGUE_INFO, extraKey: [] }
default:
return { infoKey: REDIS_KEY.USER_INFO, extraKey: [] };
}
@@ -371,7 +375,8 @@ export const RANK_TYPE_TO_KEY = new Map();
export enum COMPOSE_FIELD_TYPE {
ROLE = 1,
GUILD = 2,
ROLE_HERO = 3
ROLE_HERO = 3,
LEAGUE = 4
}
// 各个key的field如何处理
@@ -406,6 +411,9 @@ export const KEY_TO_COMPOSE_FIELD = new Map([
[REDIS_KEY.TOP_LINE_SNAPSHOT, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.LADDER, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.GVG_VESTIGE_MEMBER, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.GVG_VESTIGE_MEMBER_ALL, COMPOSE_FIELD_TYPE.ROLE],
[REDIS_KEY.GVG_VESTIGE_LEAGUE, COMPOSE_FIELD_TYPE.LEAGUE],
[REDIS_KEY.LEAGUE_INFO, COMPOSE_FIELD_TYPE.LEAGUE],
]);
@@ -1102,7 +1110,8 @@ export enum ITEM_CHANGE_REASON {
GVG_RECEIVE_LV = 168, // 领取等级奖励
GVG_RECEIVE_TASK = 169, // 领取任务奖励
GVG_VESTIGE_START = 170, // gvg征战中原挑战
GVG_VESTIGE_END = 171, // gvg征战中原挑战
GVG_VESTIGE_END = 171, // gvg征战中原挑战
GVG_VESTIGE_RECEIVE_RANK = 172, // gvg征战中原领取排行榜奖励
}
export enum TA_EVENT {

View File

@@ -348,6 +348,7 @@ export const STATUS = {
GVG_VESTIGE_BATTLE_END_STATUS_ERR: { code: 21365, simStr: '挑战时间超时' },
GVG_VESTIGE_RANK_NOT_INIT: { code: 21366, simStr: '玩家数据未初始' },
GVG_VESTIGE_REFESH_CNT_MAX: { code: 21367, simStr: '遗迹刷新次数不足' },
GVG_RECEIVE_NO_RANK_REWARD: { code: 21368, simStr: '没有可领取的奖励' },
// 通用 30000 - 30099
DIC_DATA_NOT_FOUND: { code: 30000, simStr: '数据表未找到' },

View File

@@ -109,7 +109,7 @@ export default class GVGLeague extends BaseModel {
public static async findByCodes(leagueCodes: string[]) {
const leagues: GVGLeagueType[] = await GVGLeagueModel.find({ leagueCode: { $in: leagueCodes }, status: 1 })
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role')
.populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, guildName: 1, _id: 0 }, 'Role')
.lean();
return leagues
}

View File

@@ -139,7 +139,7 @@ export default class GVGLeagueFarm extends BaseModel {
public static async lockMineOrForestry(configId: number, leagueCode: string, farmId: number, type: number, roleId: string, fieldId: number, itemId: number) {
// 先创建
await GVGLeagueFarmModel.findOneAndUpdate({ configId, leagueCode, farmId, fieldId }, { $setOnInsert: { unlockTime: 0, itemId: 0, type } }, { upsert: true });
let unlockTime = nowSeconds() + type == GVG_RESOURCE_TYPE.MINERAL? GVG.GVG_MINE_LOCK_TIME: GVG.GVG_FORESTRY_LOCK_TIME;
let unlockTime = nowSeconds() + (type == GVG_RESOURCE_TYPE.MINERAL? GVG.GVG_MINE_LOCK_TIME: GVG.GVG_FORESTRY_LOCK_TIME);
const result: GVGLeagueFarmType = await GVGLeagueFarmModel.findOneAndUpdate(
{ configId, leagueCode, farmId, fieldId, $or:[{ unlockTime: { $lt: nowSeconds() } }, {lockRoleId: roleId}] },
{ $set: { unlockTime, lockRoleId: roleId, itemId } },

View File

@@ -0,0 +1,80 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { DAY_TO_SECOND, getZeroPoint } from '../pubUtils/timeUtil';
@index({ day: 1, groupId: 1, serverType: 1, score: 1 })
@index({ leagueCode: 1 })
export default class GVGVestigeLeagueRank extends BaseModel {
@prop({ required: true })
configId: number; // 赛期
@prop({ required: true })
day: number; // 每天5点
@prop({ required: true })
leagueCode: string; // 玩家id
@prop({ required: true })
groupId: number; // 战区id
@prop({ required: true })
serverType: number; // 1-单服 2-跨服
@prop({ required: true })
score: number; // 得分
@prop({ required: true })
rank: number; // 最后的排名每天22点定格
@prop({ required: true })
isReceived: boolean; // 是否领取过
public static async incScore(configId: number, leagueCode: string, groupId: number, serverType: number, inc: number) {
let today = getZeroPoint();
let result: GVGVestigeLeagueRankType = await GVGVestigeLeagueRankModel.findOneAndUpdate({
day: today, groupId, serverType, leagueCode
}, { $inc: { score: inc }, $set: { configId }, $setOnInsert: { rank: 0, isReceived: false } }, { new: true, upsert: true }).lean();
return result;
}
// 排行榜
public static async findRank(): Promise<{ _id: { groupId: number, serverType: number }, arr: { leagueCode: string, score: number, updatedAt: Date }[], leagueCodes: string[] }[]> {
let today = getZeroPoint();
let ranks = await GVGVestigeLeagueRankModel.aggregate([
{ $match: { day: today } },
{ $group: {
_id: { groupId: "$groupId", serverType: "$serverType" },
arr: { $push: { leagueCode: "$leagueCode", score: "$score", updatedAt: "$updatedAt" } }, leagueCodes: { $addToSet: "$leagueCode" }
}},
]);
return ranks;
}
public static async saveRank(groupId: number, serverType: number, ranks: { rank: number, field: string }[]) {
let today = getZeroPoint();
await GVGVestigeLeagueRankModel.bulkWrite(ranks.map(({ field, rank }) => {
return { updateOne: { filter: { day: today, groupId, serverType, leagueCode: field }, update: { $set: { rank } }} }
}));
}
public static async getYesterdayRank(leagueCode: string) {
let yesterday = getZeroPoint() - DAY_TO_SECOND;
let result: GVGVestigeLeagueRankType = await GVGVestigeLeagueRankModel.findOne({ day: yesterday, leagueCode }).lean();
return result;
}
public static async getCanReceiveRanks(configId: number, leagueCode: string) {
let result: GVGVestigeLeagueRankType[] = await GVGVestigeLeagueRankModel.find({ configId, leagueCode, rank: { $gt: 0 }, isReceived: false }).lean();
return result;
}
public static async receiveRanks(_ids: string[]) {
await GVGVestigeLeagueRankModel.updateMany({ _id: { $in: _ids } }, { $set: { isReceived: true } });
}
}
export const GVGVestigeLeagueRankModel = getModelForClass(GVGVestigeLeagueRank);
export interface GVGVestigeLeagueRankType extends Pick<DocumentType<GVGVestigeLeagueRank>, keyof GVGVestigeLeagueRank> {};
export type GVGVestigeLeagueRankUpdate = Partial<GVGVestigeLeagueRankType>; // 将所有字段变成可选项

View File

@@ -1,6 +1,6 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose';
import Role, { RoleType } from './Role';
import { index, getModelForClass, prop, DocumentType, mongoose } from '@typegoose/typegoose';
import { RoleType } from './Role';
import { getZeroPoint } from '../pubUtils/timeUtil';
export class Lineup {
@@ -36,6 +36,9 @@ export default class GVGVestigeRank extends BaseModel {
@prop({ required: true })
roleId: string; // 玩家
@prop({ required: true })
leagueCode: string; // 联军
@prop({ required: true, default: 0 })
rank: number; // 排名
@@ -75,10 +78,10 @@ export default class GVGVestigeRank extends BaseModel {
return result;
}
public static async initRank(configId: number, vestigeId: number, groupId: number, serverType: number, role: RoleType, oppRanks: number[]) {
public static async initRank(configId: number, vestigeId: number, groupId: number, serverType: number, role: RoleType, leagueCode: string, oppRanks: number[]) {
let today = getZeroPoint();
let doc = new GVGVestigeRankModel();
let update = Object.assign(doc.toJSON(), { role: role._id, configId, groupId, serverType, oppRanks });
let update = Object.assign(doc.toJSON(), { role: role._id, configId, groupId, serverType, oppRanks, leagueCode });
let result: GVGVestigeRankType = await GVGVestigeRankModel.findOneAndUpdate({ day: today, vestigeId, roleId: role.roleId }, { $setOnInsert: update }, { new: true, upsert: true }).lean();
return result;
}
@@ -153,10 +156,9 @@ export default class GVGVestigeRank extends BaseModel {
return ranks;
}
public static async findRankByVestige(groupId: number, serverType: number, vestigeId: number) {
let today = getZeroPoint();
let result: GVGVestigeRankType[] = await GVGVestigeRankModel.find({ day: today, vestigeId, groupId, serverType }).sort({ rank: 1 }).select('roleId rank lineup').lean();
let result: GVGVestigeRankType[] = await GVGVestigeRankModel.find({ day: today, vestigeId, groupId, serverType, rank: { $gt: 0 } }).sort({ rank: 1 }).select('roleId rank lineup').lean();
return result;
}
}

View File

@@ -32,6 +32,9 @@ export default class GVGVestigeRec extends BaseModel {
@prop({ required: true })
defenseRoleId: string; // 守方玩家id
@prop({ required: true })
configId: number; // 赛期
@prop({ required: true })
groupId: number; // 战区id
@@ -65,7 +68,7 @@ export default class GVGVestigeRec extends BaseModel {
@prop({ required: true, default: false })
hasRpl: boolean; // 是否存在对应录像
public static async createRec(configId: number, vestigeId: number, groupId: number, serverType: number, warId: number, attackInfo: OppPlayerInfo, defenseInfo: OppPlayerInfo, leagueGoods: LeagueGood[]) {
public static async createRec(configId: number, vestigeId: number, groupId: number, serverType: number, warId: number, attackInfo: OppPlayerInfo, defenseInfo: OppPlayerInfo, leagueGoods: LeagueGood[]) {
const battleCode = genCode(10);
const result: GVGVestigeRecType = await GVGVestigeRecModel.findOneAndUpdate({ battleCode }, {
$set: { configId, vestigeId, groupId, serverType, attackRoleId: attackInfo.roleId, defenseRoleId: defenseInfo.roleId, warId, checkTime: Date.now(), attackInfo, defenseInfo, leagueGoods }

View File

@@ -0,0 +1,49 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { getZeroPoint } from '../pubUtils/timeUtil';
@index({ day: 1, groupId: 1, serverType: 1, score: 1 })
@index({ roleId: 1 })
export default class GVGVestigeSumRank extends BaseModel {
@prop({ required: true })
day: number; // 每天5点
@prop({ required: true })
roleId: string; // 玩家id
@prop({ required: true })
groupId: number; // 战区id
@prop({ required: true })
serverType: number; // 1-单服 2-跨服
@prop({ required: true })
score: number; // 得分
public static async incScore(roleId: string, groupId: number, serverType: number, inc: number) {
let today = getZeroPoint();
let result: GVGVestigeSumRankType = await GVGVestigeSumRankModel.findOneAndUpdate({
day: today, groupId, serverType, roleId
}, { $inc: { score: inc } }, { new: true, upsert: true }).lean();
return result;
}
// 排行榜
public static async findRank(): Promise<{ _id: { groupId: number, serverType: number }, arr: { roleId: string, score: number, updatedAt: Date }[], roleIds: string[] }[]> {
let today = getZeroPoint();
let ranks = await GVGVestigeSumRankModel.aggregate([
{ $match: { day: today } },
{ $group: {
_id: { groupId: "$groupId", serverType: "$serverType" },
arr: { $push: { roleId: "$roleId", score: "$score", updatedAt: "$updatedAt" } }, roleIds: { $addToSet: "$roleId" }
}},
]);
return ranks;
}
}
export const GVGVestigeSumRankModel = getModelForClass(GVGVestigeSumRank);
export interface GVGVestigeSumRankType extends Pick<DocumentType<GVGVestigeSumRank>, keyof GVGVestigeSumRank> {};
export type GVGVestigeSumRankUpdate = Partial<GVGVestigeSumRankType>; // 将所有字段变成可选项

View File

@@ -73,7 +73,9 @@ export class OppPlayerInfo {
@prop({ required: true })
roleId: string = ''; // 角色 id
@prop({ required: true })
roleName: string = GVG.GVG_ROBOT_NAME; // 角色 名
roleName: string = GVG.GVG_ROBOT_NAME; // 角色 名
@prop({ required: true })
leagueCode: string = ''; // 联军id
@prop({ required: true, default: 0 })
lv: number = 1; // 等级
@prop({ required: true, default: EXTERIOR.EXTERIOR_FACE })
@@ -93,7 +95,7 @@ export class OppPlayerInfo {
@prop({ required: true })
isRobot: boolean = false; // 原排名
initByPlayer(rank: number, role: RoleType, isSuccess: boolean ) {
initByPlayer(rank: number, role: RoleType, leagueCode: string, isSuccess: boolean ) {
this.oldRank = rank;
this.newRank = rank;
this.roleId = role.roleId;
@@ -105,6 +107,7 @@ export class OppPlayerInfo {
this.lv = role.lv;
this.isSuccess = isSuccess;
this.isRobot = false;
this.leagueCode = leagueCode;
}
setPlayerHeroes(heroes: HeroType[], lineup: {actorId: number, dataId: number, order: number}[]) {

View File

@@ -6,6 +6,7 @@ import { getSeconds } from "../pubUtils/timeUtil";
import { prop } from "@typegoose/typegoose";
import { pick } from "underscore";
import { RANK_TYPE, REDIS_KEY } from "../consts";
import { GVGLeagueType } from "../db/GVGLeague";
// 排行榜返回玩家值
export class RankParam {
@@ -194,6 +195,7 @@ export class GuildRankParam {
}
}
export class GuildRankInfo extends GuildRankParam {
rank: number;
code: string;
@@ -223,6 +225,65 @@ export class GuildRankInfo extends GuildRankParam {
}
export class LeagueLeader {
@prop({ required: true })
roleId: string;
@prop({ required: true })
roleName: string;
@prop({ required: true })
guildName: string;
@prop({ required: true })
serverId: number;
constructor(leader: { roleId: string, roleName: string, guildName: string, serverId: number}) {
this.roleId = leader.roleId;
this.roleName = leader.roleName;
this.guildName = leader.guildName;
this.serverId = leader.serverId;
}
}
// 联军信息
export class LeagueRankParam {
@prop({ required: true })
icon: number;
@prop({ required: true })
name: string;
@prop({ required: true, _id: false })
leader: LeagueLeader;
constructor(league: GVGLeagueType) {
this.icon = league.icon;
this.name = league.name;
let leader = <RoleType>league.leader;
let _leader = new LeagueLeader(leader);
this.leader = _leader;
}
}
// LeagueRankParam显示到排行榜界面上的信息
export class LeagueRankInfo extends LeagueRankParam {
rank: number;
code: string;
num: number;
time: number;
setInfo(rank: number, myId: myIdInter, num: number, time: number) {
this.rank = rank;
this.code = myId.leagueCode;
this.num = num;
this.time = time;
}
isMyInfo(myId: myIdInter) {
return this.code == myId.leagueCode;
}
}
export class RoleAndGuildRankInfo {
rank: number;
@@ -304,6 +365,7 @@ export class KeyName {
vestigeId?: number;
groupId?: number;
serverType?: number;
day?: string;
constructor(key: string, param: KeyNameParam) {
this.key = key;
@@ -317,6 +379,7 @@ export class KeyName {
if(param.vestigeId) this.vestigeId = param.vestigeId;
if(param.groupId) this.groupId = param.groupId;
if(param.serverType) this.serverType = param.serverType;
if(param.day) this.day = param.day;
}
public getName() {
@@ -350,9 +413,11 @@ export class KeyName {
case REDIS_KEY.TOP_LINE_SNAPSHOT:
return `${this.key}:${this.serverId}:${this.activityId}`;
case REDIS_KEY.GVG_VESTIGE_MEMBER:
return `${this.key}:${this.groupId}:${this.serverType}:${this.vestigeId}`;
return `${this.key}:${this.day}:${this.groupId}:${this.serverType}:${this.vestigeId}`;
case REDIS_KEY.GVG_VESTIGE_MEMBER_ALL:
return `${this.key}:${this.groupId}`;
return `${this.key}:${this.day}:${this.groupId}:${this.serverType}`;
case REDIS_KEY.GVG_VESTIGE_LEAGUE:
return `${this.key}:${this.day}:${this.groupId}:${this.serverType}`;
default:
return this.key;
}
@@ -402,6 +467,7 @@ export interface myIdInter {
roleId?: string;
guildCode?: string;
hid?: number;
leagueCode?: string;
}
// 排行榜总览左边的数据
@@ -412,7 +478,7 @@ export class GeneralRankParam {
num: number = 0;
received: number[];
constructor(type: number, rankInfo: RoleRankInfo|GuildRankInfo, general: number, received?: number[]) {
constructor(type: number, rankInfo: RoleRankInfo|GuildRankInfo|LeagueRankInfo, general: number, received?: number[]) {
this.type = type;
if(general == 1) {
let rank = rankInfo? (type == RANK_TYPE.LADDER? rankInfo.num: rankInfo.rank): 0;

View File

@@ -130,6 +130,7 @@ import { dicGVGTask, dicGVGTaskByType, loadGVGTask } from './dictionary/DicGVGTa
import { dicGVGVestigeByType, loadGVGVestigeType } from './dictionary/DicGVGVestigeType';
import { dicGVGVestige, loadGVGVestige } from './dictionary/DicGVGVestige';
import { DicGVGVestigeRange, dicGVGVestigeRange, loadGVGVestigeRange } from './dictionary/DicGVGVestigeRange';
import { DicGVGVestigeLeagueRank, dicGVGVestigeLeagueRank, loadGVGVestigeLeagueRank } from "./dictionary/DicGVGVestigeLeagueRank";
export const gameData = {
daily: dicDaily,
@@ -327,6 +328,7 @@ export const gameData = {
gvgVestigeCntByServerType: new Map<number, number>(), // 单服or跨服 => 遗迹数量
gvgVestige: dicGVGVestige,
gvgVestigeRange: dicGVGVestigeRange,
gvgVestigeLeagueRank: dicGVGVestigeLeagueRank,
};
// 在此提供一些原先在gamedata中提供的方法以便更方便获取gameData数据
@@ -1183,6 +1185,18 @@ export function getGVGVestigeRange(myRank: number) {
return lastRank
}
export function getGVGVestigeLeagueRank(myLeagueRank: number) {
let lastRank: DicGVGVestigeLeagueRank;
for(let dic of gameData.gvgVestigeLeagueRank) {
lastRank = dic;
let { rankMin, rankMax } = dic;
if(rankMin < myLeagueRank && (rankMax >= myLeagueRank || rankMax == 0)) {
return dic;
}
}
return lastRank
}
// 初始加载
function initDatas() {
parseDicParam();
@@ -1394,6 +1408,7 @@ function loadDatas() {
loadGVGVestigeType();
loadGVGVestige();
loadGVGVestigeRange();
loadGVGVestigeLeagueRank();
}
// 重载dicParam

View File

@@ -6,6 +6,7 @@
"taskInfo": "农庄种植/矿山采集/木堆砍柴完成1次",
"taskParam": "1&",
"condition": 1,
"tips": "(3选1完成即可)",
"reward": "31002&500",
"leagueReward": "13&1"
},
@@ -16,6 +17,7 @@
"taskInfo": "中原遗迹挑战1次",
"taskParam": "1&",
"condition": 1,
"tips": "&",
"reward": "31002&500",
"leagueReward": "13&1"
},
@@ -26,6 +28,7 @@
"taskInfo": "千机阁捐献1次",
"taskParam": "1&",
"condition": 1,
"tips": "&",
"reward": "31002&500",
"leagueReward": "13&1"
}

View File

@@ -6,8 +6,9 @@
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "2&1000",
"additionValue": "2&",
"content": "枪兵",
"seid": 2401311,
"position": "&"
},
{
@@ -17,8 +18,117 @@
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "6&1000",
"additionValue": "6&",
"content": "策士",
"seid": 501411,
"position": "&"
},
{
"id": 3,
"vestigeId": 3,
"name": "燕都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "5&",
"content": "游侠",
"seid": 301411,
"position": "&"
},
{
"id": 4,
"vestigeId": 4,
"name": "韩都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "4&",
"content": "弓兵",
"seid": 3001411,
"position": "&"
},
{
"id": 5,
"vestigeId": 5,
"name": "赵都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "3&",
"content": "骑兵",
"seid": 301411,
"position": "&"
},
{
"id": 6,
"vestigeId": 6,
"name": "魏都遗址",
"mapType": "1&2",
"imageName": "&",
"additionType": 1,
"additionValue": "1&",
"content": "步兵",
"seid": 301411,
"position": "&"
},
{
"id": 7,
"vestigeId": 7,
"name": "山巅帝陵",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "1&",
"content": "魏国",
"seid": 1201611,
"position": "&"
},
{
"id": 8,
"vestigeId": 8,
"name": "崖底河泽",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "2&",
"content": "吴国",
"seid": 5001311,
"position": "&"
},
{
"id": 9,
"vestigeId": 9,
"name": "深山迷林",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "3&",
"content": "蜀国",
"seid": 5001311,
"position": "&"
},
{
"id": 10,
"vestigeId": 10,
"name": "桃源古村",
"mapType": "1&2",
"imageName": "&",
"additionType": 2,
"additionValue": "4&",
"content": "群雄",
"seid": 5001311,
"position": "&"
},
{
"id": 11,
"vestigeId": 11,
"name": "鹿鸣幽谷",
"mapType": "1&2",
"imageName": "&",
"additionType": 3,
"additionValue": "2&",
"content": "女性",
"seid": 5001311,
"position": "&"
}
]