Blame view

项目文档相关/scripts/sh/seed_attendance_punch_week.sh 7.33 KB
f075068f   “wangming”   对考勤这块功能进行开发
1
2
3
4
  #!/bin/zsh
  
  set -euo pipefail
  
8daf47d0   “wangming”   修改访问地址
5
  BASE_URL="${BASE_URL:-http://localhost:2015}"
f075068f   “wangming”   对考勤这块功能进行开发
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  ACCOUNT="${ACCOUNT:-admin}"
  PASSWORD="${PASSWORD:-e10adc3949ba59abbe56e057f20f883e}"
  START_DATE="${1:-2026-03-16}"
  DAYS="${DAYS:-7}"
  USER_COUNT="${USER_COUNT:-5}"
  GROUP_ID="${GROUP_ID:-}"
  
  export BASE_URL ACCOUNT PASSWORD START_DATE DAYS USER_COUNT GROUP_ID
  
  python3 - <<'PY'
  import json
  import os
  import subprocess
  import sys
  from datetime import datetime, timedelta
  from urllib.parse import urlencode
  
  base = os.environ['BASE_URL']
  account = os.environ['ACCOUNT']
  password = os.environ['PASSWORD']
  start_date = os.environ['START_DATE']
  days = int(os.environ['DAYS'])
  user_count = int(os.environ['USER_COUNT'])
  group_id = os.environ.get('GROUP_ID') or ''
  
  
  def call_api(method, path, *, token=None, json_body=None, form_body=None):
      cmd = ['curl', '-s', '-X', method, f'{base}{path}']
      if token:
          cmd += ['-H', f'Authorization: {token}']
      if json_body is not None:
          cmd += ['-H', 'Content-Type: application/json', '-d', json.dumps(json_body, ensure_ascii=False)]
      if form_body is not None:
          cmd += ['-H', 'Content-Type: application/x-www-form-urlencoded', '-d', urlencode(form_body)]
      raw = subprocess.check_output(cmd, text=True)
      try:
          data = json.loads(raw)
      except json.JSONDecodeError:
          raise RuntimeError(f'接口返回非 JSON:{raw}')
      if data.get('code') != 200:
          raise RuntimeError(f'接口调用失败:{path}\n{json.dumps(data, ensure_ascii=False)}')
      return data
  
  
  print('===> 登录获取 token')
  login_res = call_api('POST', '/api/oauth/Login', form_body={
      'account': account,
      'password': password,
  })
  token = (login_res.get('data') or {}).get('token')
  if not token:
      raise RuntimeError(f'登录失败:{json.dumps(login_res, ensure_ascii=False)}')
  
  print('===> 获取考勤分组')
  info_res = call_api('GET', '/api/Extend/LqAttendanceSetting/Info', token=token)
  setting_data = info_res.get('data') or {}
  groups = [g for g in (setting_data.get('groups') or []) if g.get('isEnabled') == 1]
  if not groups:
      raise RuntimeError('未找到启用中的考勤分组,请先在考勤设置中心保存分组')
  
  if not group_id:
      group_id = groups[0]['id']
  group_name = next((g.get('groupName') for g in groups if g.get('id') == group_id), group_id)
  print(f'使用考勤分组:{group_name}({group_id})')
  
  
  def get_group_users():
      res = call_api(
          'GET',
          f'/api/Extend/LqAttendanceSetting/GroupUsers?GroupId={group_id}&OnJobStatus=1&currentPage=1&pageSize=100',
          token=token,
      )
      return (res.get('data') or {}).get('list') or []
  
  
  selected_users = []
  for item in get_group_users():
      if not item.get('id'):
          continue
      selected_users.append({
          'id': item['id'],
          'name': item.get('realName') or item.get('account') or item['id'],
          'storeId': item.get('storeId'),
      })
      if len(selected_users) >= user_count:
          break
  
  if len(selected_users) < user_count:
      print('===> 当前分组人数不足,尝试通过用户接口补充绑定成员')
      users_res = call_api('GET', '/api/permission/Users?currentPage=1&pageSize=200&enabledMark=1', token=token)
      candidates = (users_res.get('data') or {}).get('list') or []
      selected_ids = {u['id'] for u in selected_users}
      for candidate in candidates:
          if len(selected_users) >= user_count:
              break
          user_id = candidate.get('id')
          if not user_id or user_id in selected_ids:
              continue
          user_info_res = call_api('GET', f'/api/permission/Users/{user_id}', token=token)
          user_info = user_info_res.get('data') or {}
          if not user_info.get('id'):
              continue
          user_info['attendanceGroupId'] = group_id
          call_api('PUT', f'/api/permission/Users/{user_id}', token=token, json_body=user_info)
          selected_users.append({
              'id': user_id,
              'name': user_info.get('realName') or user_info.get('account') or user_id,
              'storeId': user_info.get('mdid'),
          })
          selected_ids.add(user_id)
          print(f'已绑定考勤分组:{user_info.get("realName") or user_id}')
  
  if len(selected_users) < user_count:
      raise RuntimeError(f'可用员工不足,仅找到 {len(selected_users)} 人,无法生成 {user_count} 人测试数据')
  
  selected_users = selected_users[:user_count]
  print('选中的员工:')
  for item in selected_users:
      print(f'  - {item["name"]} ({item["id"]})')
  
  
  def build_address(name, mode):
      if mode == 0:
          return f'{name} 门店正常上班打卡'
      if mode == 1:
          return f'{name} 门店迟到测试打卡'
      if mode == 2:
          return f'{name} 门店早退测试打卡'
      return f'{name} 外勤上门服务测试打卡'
  
  
  def build_punch_payload(user, attendance_date, mode, is_in):
      if mode == 0:
          punch_in = '08:55:00'
          punch_out = '19:05:00'
          punch_type = 1
      elif mode == 1:
          punch_in = '09:02:00'
          punch_out = '19:03:00'
          punch_type = 1
      elif mode == 2:
          punch_in = '08:57:00'
          punch_out = '18:40:00'
          punch_type = 1
      else:
          punch_in = '09:01:00'
          punch_out = '18:52:00'
          punch_type = 2
  
      clock_time = punch_in if is_in else punch_out
      photo_suffix = 'IN' if is_in else 'OUT'
      return {
          'UserId': user['id'],
          'PunchDirection': 1 if is_in else 2,
          'PunchType': punch_type,
          'PunchTime': f'{attendance_date} {clock_time}',
          'Longitude': 104.065735,
          'Latitude': 30.656149,
          'Address': build_address(user['name'], mode),
          'PhotoUrl': f'https://dummyimage.com/320x240/409eff/ffffff.png&text={user["name"]}-{attendance_date}-{photo_suffix}',
          'Remark': '脚本生成测试打卡数据',
      }
  
  
  print('===> 开始生成打卡数据')
  start = datetime.strptime(start_date, '%Y-%m-%d')
  created = []
  for user_index, user in enumerate(selected_users):
      for offset in range(days):
          attendance_date = (start + timedelta(days=offset)).strftime('%Y-%m-%d')
          mode = (user_index + offset) % 4
          in_payload = build_punch_payload(user, attendance_date, mode, True)
          out_payload = build_punch_payload(user, attendance_date, mode, False)
          call_api('POST', '/api/Extend/LqAttendanceRecord/Punch', token=token, json_body=in_payload)
          call_api('POST', '/api/Extend/LqAttendanceRecord/Punch', token=token, json_body=out_payload)
          created.append({
              'userId': user['id'],
              'name': user['name'],
              'date': attendance_date,
              'mode': mode,
          })
          print(f'已生成:{user["name"]} {attendance_date}')
  
  month = start.strftime('%Y-%m')
  verify_res = call_api(
      'GET',
      f'/api/Extend/LqAttendanceRecord/MonthReport?month={month}&currentPage=1&pageSize=100',
      token=token,
  )
  verify_data = verify_res.get('data') or {}
  verify_list = verify_data.get('list') or []
  matched_names = {item.get('employeeName') for item in verify_list}
  matched_users = [item for item in selected_users if item['name'] in matched_names]
  
  print('===> 生成完成')
  print(json.dumps({
      'groupId': group_id,
      'groupName': group_name,
      'startDate': start_date,
      'days': days,
      'selectedUsers': selected_users,
      'verifiedUserCount': len(matched_users),
      'verifiedUserNames': [item['name'] for item in matched_users],
      'createdCount': len(created),
  }, ensure_ascii=False, indent=2))
  PY