提交 7e5374ac 编写于 作者: 孙喜旺

客户群同步优化,对回调租户拦截优化

上级 a42ce3a5
......@@ -61,14 +61,10 @@ public class WeGroupController extends BaseController {
// @PreAuthorize("@ss.hasPermi('customerManage:group:sync')")
@GetMapping({"/synchWeGroup"})
public AjaxResult synchWeGroup(){
try {
SecurityContext context = SecurityContextHolder.getContext();
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
SecurityContextHolder.setContext(context);
weGroupService.synchWeGroup();
} catch (Exception e) {
e.printStackTrace();
}
SecurityContext context = SecurityContextHolder.getContext();
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
SecurityContextHolder.setContext(context);
weGroupService.synchWeGroup();
return AjaxResult.success(WeConstans.SYNCH_TIP);
}
......
......@@ -13,6 +13,7 @@ import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "wecome")
@Data
public class WeComeConfig {
public static ThreadLocal<String> localCorpId = new ThreadLocal<>();
/** 企业微信后台地址 */
private String serverUrl;
......
......@@ -9,6 +9,7 @@ import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.common.core.domain.entity.WeCorpAccount;
import com.linkwechat.common.core.domain.model.LoginUser;
import com.linkwechat.common.utils.SecurityUtils;
import com.linkwechat.common.utils.StringUtils;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.apache.ibatis.plugin.Interceptor;
......@@ -32,8 +33,6 @@ public class MyBatisPlusConfig {
@Autowired
RuoYiConfig ruoYiConfig;
@Bean
public Interceptor[] plugins() {
......@@ -44,6 +43,9 @@ public class MyBatisPlusConfig {
// 获取租户 ID 值表达式,只支持单个 ID 值
@Override
public Expression getTenantId() {
if(StringUtils.isNotEmpty(WeComeConfig.localCorpId.get())){
return new StringValue(WeComeConfig.localCorpId.get());
}
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if(null != loginUser){
......
......@@ -49,6 +49,11 @@ public class WeGroup extends BaseEntity{
@TableField(value = "group_name")
private String groupName;
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
@ApiModelProperty(value = "群的创建时间")
@TableField(value = "add_time")
private Date addTime;
@TableField(exist = false)
private Long memberNum;
......
package com.linkwechat.wecom.factory.impl;
import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.wecom.domain.vo.WxCpXmlMessageVO;
import com.linkwechat.wecom.factory.WeCallBackEventFactory;
import lombok.extern.slf4j.Slf4j;
......@@ -16,6 +17,7 @@ public class WeEventBatchJobResultImpl implements WeCallBackEventFactory {
@Override
public void eventHandle(WxCpXmlMessageVO message) {
WeComeConfig.localCorpId.set(message.getToUserName());
String jobType = message.getBatchJob().getJobType();
switch (jobType){
case "sync_user"://增量更新成员)
......
package com.linkwechat.wecom.factory.impl;
import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.wecom.domain.vo.WxCpXmlMessageVO;
import com.linkwechat.wecom.factory.WeCallBackEventFactory;
import com.linkwechat.wecom.factory.WeStrategyBeanFactory;
......@@ -20,6 +21,7 @@ public class WeEventChangeContactImpl implements WeCallBackEventFactory {
@Override
public void eventHandle(WxCpXmlMessageVO message) {
WeComeConfig.localCorpId.set(message.getToUserName());
//新增: create_user 更新: update_user 删除:delete_user
String changeType = message.getChangeType();
weStrategyBeanFactory.getResource(changeType, message);
......
package com.linkwechat.wecom.factory.impl;
import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.wecom.domain.vo.WxCpXmlMessageVO;
import com.linkwechat.wecom.factory.WeCallBackEventFactory;
import com.linkwechat.wecom.factory.WeStrategyBeanFactory;
......@@ -21,6 +22,7 @@ public class WeEventChangeExternalChatImpl implements WeCallBackEventFactory {
@Override
public void eventHandle(WxCpXmlMessageVO message) {
WeComeConfig.localCorpId.set(message.getToUserName());
String changeType = message.getChangeType();
weStrategyBeanFactory.getResource(changeType,message);
}
......
package com.linkwechat.wecom.factory.impl;
import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.wecom.domain.vo.WxCpXmlMessageVO;
import com.linkwechat.wecom.factory.WeCallBackEventFactory;
import com.linkwechat.wecom.factory.WeStrategyBeanFactory;
......@@ -20,6 +21,7 @@ public class WeEventChangeExternalContactImpl implements WeCallBackEventFactory
@Override
public void eventHandle(WxCpXmlMessageVO message) {
WeComeConfig.localCorpId.set(message.getToUserName());
String changeType = message.getChangeType();
weStrategyBeanFactory.getResource(changeType,message);
}
......
package com.linkwechat.wecom.factory.impl;
import com.linkwechat.common.config.WeComeConfig;
import com.linkwechat.wecom.domain.vo.WxCpXmlMessageVO;
import com.linkwechat.wecom.factory.WeCallBackEventFactory;
import com.linkwechat.wecom.factory.WeStrategyBeanFactory;
......@@ -20,6 +21,7 @@ public class WeEventChangeExternalTagImpl implements WeCallBackEventFactory {
@Override
public void eventHandle(WxCpXmlMessageVO message) {
WeComeConfig.localCorpId.set(message.getToUserName());
String changeType = message.getChangeType()+"CustomerTag";
weStrategyBeanFactory.getResource(changeType,message);
}
......
......@@ -13,21 +13,9 @@ import java.util.List;
* @Date: create in 2020/9/21 0021 23:58
*/
public interface WeGroupMapper extends BaseMapper<WeGroup> {
// WeGroup selectWeGroupById(Long paramLong);
//
List<WeGroup> selectWeGroupList(WeGroup paramWeGroup);
//
// int insertWeGroup(WeGroup paramWeGroup);
//
// int updateWeGroup(WeGroup paramWeGroup);
//
// int deleteWeGroupById(Long paramLong);
//
// int deleteWeGroupByIds(Long[] paramArrayOfLong);
//
// int batchLogicDeleteByIds(@Param("ids") List<Long> ids);
//
// int batchInsetWeGroup(@Param("weGroups") List<WeGroup> weGroups);
List<WeCustomerAddGroup> findWeGroupByCustomer(@Param("userId") String userId,@Param("externalUserid") String externalUserid);
void insertBatch(@Param("weGroups") List<WeGroup> weGroups);
}
......@@ -3,6 +3,7 @@ package com.linkwechat.wecom.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.linkwechat.wecom.domain.WeGroupMember;
import com.linkwechat.wecom.domain.dto.WeGroupMemberDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
......@@ -18,6 +19,8 @@ public interface WeGroupMemberMapper extends BaseMapper<WeGroupMember> {
List<WeGroupMemberDto> selectWeGroupMemberListByChatId(String chatId);
void insertBatch(@Param("weGroupMembers") List<WeGroupMember> weGroupMembers);
// int insertWeGroupMember(WeGroupMember paramWeGroupMember);
//
// int updateWeGroupMember(WeGroupMember paramWeGroupMember);
......
......@@ -18,14 +18,6 @@ import java.util.List;
*/
public interface WeUserMapper extends BaseMapper<WeUser>
{
/**
* 查询通讯录相关客户
*
* @param userId 通讯录相关客户ID
* @return 通讯录相关客户
*/
public WeUser selectWeUserById(String userId);
/**
* 查询通讯录相关客户列表
*
......@@ -39,7 +31,7 @@ public interface WeUserMapper extends BaseMapper<WeUser>
* @param weUserList 成员数据
* @return
*/
public int saveOrUpdateBatch(@Param("weUserList") List<WeUser> weUserList);
public void insertBatch(@Param("weUserList") List<WeUser> weUserList);
/**
* 离职未分配员工
* @param weLeaveUserVo
......
......@@ -3,6 +3,7 @@ package com.linkwechat.wecom.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.linkwechat.wecom.domain.WeGroupMember;
import com.linkwechat.wecom.domain.dto.WeGroupMemberDto;
import org.apache.ibatis.annotations.Param;
import java.util.List;
......@@ -18,4 +19,6 @@ public interface IWeGroupMemberService extends IService<WeGroupMember> {
List<WeGroupMemberDto> selectWeGroupMemberListByChatId(String chatId);
WeGroupMember selectWeGroupMemberByUnionId(String chatId, String unionId);
void insertBatch(List<WeGroupMember> weGroupMembers);
}
......@@ -37,5 +37,10 @@ public class WeGroupMemberServiceImpl extends ServiceImpl<WeGroupMemberMapper,We
.eq(WeGroupMember::getUnionId,unionId));
}
@Override
public void insertBatch(List<WeGroupMember> weGroupMembers) {
this.baseMapper.insertBatch(weGroupMembers);
}
}
package com.linkwechat.wecom.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.linkwechat.common.constant.Constants;
import com.linkwechat.common.constant.WeConstans;
import com.linkwechat.common.utils.SecurityUtils;
import com.linkwechat.wecom.client.WeCustomerClient;
import com.linkwechat.wecom.client.WeCustomerGroupClient;
import com.linkwechat.wecom.client.WeUserClient;
import com.linkwechat.wecom.domain.WeAllocateGroup;
import com.linkwechat.wecom.domain.WeCustomerAddGroup;
import com.linkwechat.wecom.domain.WeGroup;
import com.linkwechat.wecom.domain.WeGroupMember;
import com.linkwechat.wecom.domain.*;
import com.linkwechat.wecom.domain.dto.AllocateWeGroupDto;
import com.linkwechat.wecom.domain.dto.customer.CustomerGroupDetail;
import com.linkwechat.wecom.domain.dto.customer.CustomerGroupList;
......@@ -122,7 +121,6 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
@Async
@Transactional(rollbackFor = Exception.class)
public void synchWeGroup() {
CustomerGroupList customerGroupList =
weCustomerGroupClient.groupChatLists(new CustomerGroupList().new Params());
if (customerGroupList.getErrcode().equals(WeConstans.WE_SUCCESS_CODE)
......@@ -130,9 +128,7 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
List<WeGroup> weGroups = new ArrayList<>();
List<WeGroupMember> weGroupMembers = new ArrayList<>();
customerGroupList.getGroup_chat_list().stream().forEach(k -> {
customerGroupList.getGroup_chat_list().forEach(k -> {
CustomerGroupDetail customerGroupDetail = weCustomerGroupClient.groupChatDetail(
new CustomerGroupDetail().new Params(k.getChat_id())
);
......@@ -140,43 +136,20 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
if (customerGroupDetail.getErrcode().equals(WeConstans.WE_SUCCESS_CODE)
&& CollectionUtil.isNotEmpty(customerGroupDetail.getGroup_chat())) {
customerGroupDetail.getGroup_chat().stream().forEach(kk -> {
customerGroupDetail.getGroup_chat().forEach(kk -> {
weGroups.add(
WeGroup.builder()
.chatId(kk.getChat_id())
.groupName(kk.getName())
.notice(kk.getNotice())
.owner(kk.getOwner())
.createTime(new Date(kk.getCreate_time() * 1000L))
.addTime(new Date(kk.getCreate_time() * 1000L))
.status(k.getStatus())
.build()
);
List<CustomerGroupMember> memberLists = kk.getMember_list();
if (CollectionUtil.isNotEmpty(memberLists)) {
memberLists.stream().forEach(member -> {
//unionid不为空,获取非好友客户相关消息
// if(StrUtil.isNotBlank(member.getUnionid())){
// ExternalUserDetail.ExternalContact externalContact1 = new ExternalUserDetail.ExternalContact();
// externalContact1.setUnionid(member.getUnionid());
//
// ExternalUserDetail externalContact
// = weCustomerClient.unionidToExternalUserid(externalContact1);
//
// if(externalContact.getErrcode().equals(WeConstans.WE_SUCCESS_CODE)
// && StrUtil.isNotBlank(externalContact.getExternal_userid())){
//
//
//
// ExternalUserDetail externalUserDetail = weCustomerClient.get(member.getUnionid());
// System.out.println("===========START====================");
// System.out.println(JSONUtil.toJsonStr(externalUserDetail));
// System.out.println("===========END====================");
//
// }
//
// }
memberLists.forEach(member -> {
weGroupMembers.add(
WeGroupMember.builder()
.chatId(kk.getChat_id())
......@@ -189,10 +162,7 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
);
});
}
});
}
});
......@@ -205,15 +175,7 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
//weUserService.synchWeUser();
//同步客户
//weCustomerService.synchWeCustomer();
this.saveOrUpdateBatch(weGroups);
List<WeGroupMember> weGroupMemberList = iWeGroupMemberService.list(new LambdaQueryWrapper<WeGroupMember>().in(WeGroupMember::getChatId,
weGroups.stream().map(WeGroup::getChatId).collect(Collectors.toList())));
if (CollectionUtil.isNotEmpty(weGroupMemberList)) {
iWeGroupMemberService.removeByIds(weGroupMemberList.stream().map(WeGroupMember::getId).collect(Collectors.toList()));
}
iWeGroupMemberService.saveBatch(weGroupMembers);
insertBatchGroupAndMember(weGroups, weGroupMembers);
}
......@@ -254,9 +216,7 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
});
}
});
this.saveOrUpdateBatch(weGroups);
iWeGroupMemberService.saveBatch(weGroupMembers);
insertBatchGroupAndMember(weGroups, weGroupMembers);
}
}
......@@ -295,10 +255,9 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
});
}
});
this.saveOrUpdateBatch(weGroups);
insertBatchGroupAndMember(weGroups, weGroupMembers);
//获取表中成员信息
List<WeGroupMember> weGroupMemberList = iWeGroupMemberService.list(new LambdaQueryWrapper<WeGroupMember>()
/*List<WeGroupMember> weGroupMemberList = iWeGroupMemberService.list(new LambdaQueryWrapper<WeGroupMember>()
.eq(WeGroupMember::getChatId, chatId));
if (weGroupMembers.size() > weGroupMemberList.size()) {
//成员信息取差集
......@@ -315,6 +274,27 @@ public class WeGroupServiceImpl extends ServiceImpl<WeGroupMapper, WeGroup> impl
.eq(WeGroupMember::getChatId, chatId)
.in(WeGroupMember::getUserId, list.stream().map(WeGroupMember::getUserId)
.collect(Collectors.toList())));
}*/
}
}
/**
* 批量添加
* @param weGroups 客户群
* @param weGroupMembers 群成员
*/
private void insertBatchGroupAndMember(List<WeGroup> weGroups, List<WeGroupMember> weGroupMembers) {
if (CollectionUtil.isNotEmpty(weGroups)) {
List<List<WeGroup>> lists = Lists.partition(weGroups, 500);
for (List<WeGroup> groupList : lists) {
this.baseMapper.insertBatch(groupList);
}
}
if (CollectionUtil.isNotEmpty(weGroupMembers)) {
List<List<WeGroupMember>> lists = Lists.partition(weGroupMembers, 500);
for (List<WeGroupMember> groupMemberList : lists) {
iWeGroupMemberService.insertBatch(groupMemberList);
}
}
}
......
......@@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.linkwechat.common.constant.Constants;
import com.linkwechat.common.constant.WeConstans;
import com.linkwechat.common.utils.SecurityUtils;
......@@ -227,7 +228,11 @@ public class WeTagGroupServiceImpl extends ServiceImpl<WeTagGroupMapper, WeTagGr
this.removeByIds(noExist.stream().map(WeTagGroup::getId).collect(Collectors.toList()));
}
}
this.baseMapper.insertWeTagGroupBatch(weTagGroups);
List<List<WeTagGroup>> tagGroupLists = Lists.partition(weTagGroups, 500);
for (List<WeTagGroup> item : tagGroupLists) {
this.baseMapper.insertWeTagGroupBatch(item);
}
List<WeTag> weTags =
weTagGroups.stream().map(WeTagGroup::getWeTags).collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
if (CollectionUtil.isNotEmpty(weTags)) {
......@@ -238,7 +243,11 @@ public class WeTagGroupServiceImpl extends ServiceImpl<WeTagGroupMapper, WeTagGr
iWeTagService.removeByIds(noExistWeTags.stream().map(WeTag::getId).collect(Collectors.toList()));
}
}
iWeTagService.insertWeTagBatch(weTags);
List<List<WeTag>> lists = Lists.partition(weTags, 500);
for (List<WeTag> item : lists) {
iWeTagService.insertWeTagBatch(item);
}
}
} else {//不存在删除所有标签组,以标签
if (isSync) {
......
......@@ -7,10 +7,12 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.linkwechat.common.utils.DateUtils;
import com.linkwechat.common.utils.SecurityUtils;
import com.linkwechat.common.utils.StringUtils;
import com.linkwechat.wecom.client.WeCropTagClient;
import com.linkwechat.wecom.domain.WeGroup;
import com.linkwechat.wecom.domain.WeTagGroup;
import com.linkwechat.wecom.domain.dto.WeTagDto;
import com.linkwechat.wecom.domain.dto.tag.WeCropGroupTagDto;
......@@ -141,7 +143,12 @@ public class WeTagServiceImpl extends ServiceImpl<WeTagMapper,WeTag> implements
.groupId(tagGroup.getGroup_id())
.name(tag.getName())
.build());
this.baseMapper.insertWeTagBatch(weTags);
if(CollectionUtil.isNotEmpty(weTags)){
List<List<WeTag>> lists = Lists.partition(weTags, 500);
for (List<WeTag> item : lists) {
this.baseMapper.insertWeTagBatch(item);
}
}
}
});
}
......@@ -170,7 +177,13 @@ public class WeTagServiceImpl extends ServiceImpl<WeTagMapper,WeTag> implements
.groupId(tagGroup.getGroup_id())
.name(tag.getName())
.build());
this.baseMapper.insertWeTagBatch(weTags);
if(CollectionUtil.isNotEmpty(weTags)){
List<List<WeTag>> lists = Lists.partition(weTags, 500);
for (List<WeTag> item : lists) {
this.baseMapper.insertWeTagBatch(item);
}
}
}
});
}
......
......@@ -107,7 +107,8 @@ public class WeUserServiceImpl extends ServiceImpl<WeUserMapper, WeUser> impleme
public boolean insert2Data(WeUser weUser) {
List<WeUser> list = new ArrayList<>(16);
list.add(weUser);
return SqlHelper.retBool(this.weUserMapper.saveOrUpdateBatch(list));
this.weUserMapper.insertBatch(list);
return true;
}
/**
......@@ -207,7 +208,7 @@ public class WeUserServiceImpl extends ServiceImpl<WeUserMapper, WeUser> impleme
if (CollectionUtil.isNotEmpty(weUsers)) {
List<List<WeUser>> lists = Lists.partition(weUsers, 500);
for(List<WeUser> list : lists){
this.weUserMapper.saveOrUpdateBatch(list);
this.weUserMapper.insertBatch(list);
}
}
......
......@@ -9,7 +9,7 @@
SELECT
wg.chat_id,
wg.group_name,
wg.create_time,
wg.add_time,
wg.notice,
wu.user_name as groupLeaderName,
(SELECT COUNT(*) FROM we_group_member wgm WHERE wgm.chat_id=wg.chat_id) as memberNum,
......@@ -22,11 +22,11 @@
<if test="groupName != null and groupName != ''"> and wg.group_name like concat('%', #{groupName}, '%')</if>
<if test="groupLeader != null and groupLeader != ''"> and wu.user_name like concat('%', #{groupLeader}, '%')</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
AND date_format(wg.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
AND date_format(wg.add_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
AND date_format(wg.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
AND date_format(wg.add_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
</if>
<if test="userIds != null and userIds !=''">
<if test="userIds.indexOf(',') != -1">
......@@ -61,4 +61,15 @@
</select>
<insert id="insertBatch">
insert into we_group (chat_id, group_name, owner, add_time, notice, status, create_by, update_by,create_time,update_time)
values
<foreach collection="weGroups" item="weGroup" index="index" separator=",">
(#{weGroup.chatId},#{weGroup.groupName},#{weGroup.owner},#{weGroup.addTime},#{weGroup.notice},#{weGroup.status},
#{weGroup.createBy},#{weGroup.createTime},#{weGroup.updateBy},#{weGroup.updateTime})
</foreach>
on duplicate key update group_name= values(group_name),owner= values(owner),
notice= values(notice),status= values(status),
update_by= values(update_by),update_time= values(update_time)
</insert>
</mapper>
\ No newline at end of file
......@@ -55,4 +55,18 @@
</where>
</select>
<insert id="insertBatch">
insert into we_group_member (chat_id, user_id, union_id, join_time, join_scene, `type`,
create_by, update_by,create_time,update_time)
values
<foreach collection="weGroupMember" item="weGroupMembers" index="index" separator=",">
(#{weGroupMember.chatId},#{weGroupMember.userId},#{weGroupMember.unionId},
#{weGroupMember.joinTime},#{weGroupMember.joinScene},#{weGroupMember.type},
#{weGroupMember.createBy},#{weGroupMember.createTime},
#{weGroupMember.updateBy},#{weGroupMember.updateTime})
</foreach>
on duplicate key update
join_time= values(join_time),join_scene= values(join_scene),
`type`= values(`type`),update_by= values(update_by),update_time= values(update_time)
</insert>
</mapper>
\ No newline at end of file
......@@ -73,7 +73,7 @@
</where>
</select>
<insert id="saveOrUpdateBatch">
<insert id="insertBatch">
insert into we_user (head_image_url, user_name, alias,
user_id, gender, mobile, email, wx_account,
department, position, is_leader_in_dept,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册