6.13.0: Переменные $name и $subtaskName в сообщениях награды
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m19s

This commit is contained in:
poignatov
2026-03-12 15:28:25 +03:00
parent 02c8b7537a
commit 0b5106458a
5 changed files with 29 additions and 17 deletions

View File

@@ -1 +1 @@
6.12.1 6.13.0

View File

@@ -8570,7 +8570,7 @@ func (a *App) createTaskHandler(w http.ResponseWriter, r *http.Request) {
// Если сообщение награды не указано или пустое, устанавливаем "Выполнить желание: {TITLE}" // Если сообщение награды не указано или пустое, устанавливаем "Выполнить желание: {TITLE}"
if req.RewardMessage == nil || strings.TrimSpace(*req.RewardMessage) == "" { if req.RewardMessage == nil || strings.TrimSpace(*req.RewardMessage) == "" {
rewardMsg := fmt.Sprintf("Выполнить желание: %s", wishlistName) rewardMsg := "Выполнить желание: $name"
req.RewardMessage = &rewardMsg req.RewardMessage = &rewardMsg
} }
@@ -9972,7 +9972,7 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error
} }
// Функция для замены плейсхолдеров в сообщении награды // Функция для замены плейсхолдеров в сообщении награды
replaceRewardPlaceholders := func(message string, rewardStrings map[int]string) string { replaceRewardPlaceholders := func(message string, rewardStrings map[int]string, taskName string, subtaskName string) string {
result := message result := message
// Сначала сохраняем экранированные плейсхолдеры \$0, \$1 и т.д. во временные маркеры // Сначала сохраняем экранированные плейсхолдеры \$0, \$1 и т.д. во временные маркеры
escapedMarkers := make(map[string]string) escapedMarkers := make(map[string]string)
@@ -9984,6 +9984,12 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error
result = strings.ReplaceAll(result, escaped, marker) result = strings.ReplaceAll(result, escaped, marker)
} }
} }
// Заменяем $subtaskName именем подзадачи (если задано)
if subtaskName != "" {
result = strings.ReplaceAll(result, "$subtaskName", subtaskName)
}
// Заменяем $name именем задачи
result = strings.ReplaceAll(result, "$name", taskName)
// Заменяем ${0}, ${1}, и т.д. // Заменяем ${0}, ${1}, и т.д.
for i := 0; i < 100; i++ { // Максимум 100 плейсхолдеров for i := 0; i < 100; i++ { // Максимум 100 плейсхолдеров
placeholder := fmt.Sprintf("${%d}", i) placeholder := fmt.Sprintf("${%d}", i)
@@ -10025,7 +10031,7 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error
// Подставляем в reward_message основной задачи // Подставляем в reward_message основной задачи
var mainTaskMessage string var mainTaskMessage string
if task.RewardMessage != nil && *task.RewardMessage != "" { if task.RewardMessage != nil && *task.RewardMessage != "" {
mainTaskMessage = replaceRewardPlaceholders(*task.RewardMessage, rewardStrings) mainTaskMessage = replaceRewardPlaceholders(*task.RewardMessage, rewardStrings, task.Name, "")
} else { } else {
// Если reward_message пустой, используем имя задачи // Если reward_message пустой, используем имя задачи
mainTaskMessage = task.Name mainTaskMessage = task.Name
@@ -10117,7 +10123,7 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error
} }
// Подставляем в reward_message подзадачи // Подставляем в reward_message подзадачи
subtaskMessage := replaceRewardPlaceholders(subtaskRewardMessage.String, subtaskRewardStrings) subtaskMessage := replaceRewardPlaceholders(subtaskRewardMessage.String, subtaskRewardStrings, task.Name, subtaskName)
subtaskMessages = append(subtaskMessages, subtaskMessage) subtaskMessages = append(subtaskMessages, subtaskMessage)
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "play-life-web", "name": "play-life-web",
"version": "6.12.1", "version": "6.13.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -291,7 +291,7 @@ const formatTelegramMessage = (task, rewards, subtasks, selectedSubtasks, progre
}) })
// Функция для замены плейсхолдеров // Функция для замены плейсхолдеров
const replacePlaceholders = (message, rewardStrings) => { const replacePlaceholders = (message, rewardStrings, taskName, subtaskName) => {
let result = message let result = message
// Сначала защищаем экранированные плейсхолдеры // Сначала защищаем экранированные плейсхолдеры
const escapedMarkers = {} const escapedMarkers = {}
@@ -303,6 +303,12 @@ const formatTelegramMessage = (task, rewards, subtasks, selectedSubtasks, progre
result = result.replace(new RegExp(escaped.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), marker) result = result.replace(new RegExp(escaped.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), marker)
} }
} }
// Заменяем $subtaskName именем подзадачи (если задано)
if (subtaskName) {
result = result.replace(/\$subtaskName/g, subtaskName)
}
// Заменяем $name именем задачи
result = result.replace(/\$name/g, taskName || '')
// Заменяем ${0}, ${1}, и т.д. // Заменяем ${0}, ${1}, и т.д.
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {
const placeholder = `\${${i}}` const placeholder = `\${${i}}`
@@ -327,7 +333,7 @@ const formatTelegramMessage = (task, rewards, subtasks, selectedSubtasks, progre
// Формируем сообщение основной задачи // Формируем сообщение основной задачи
let mainTaskMessage = task.reward_message && task.reward_message.trim() !== '' let mainTaskMessage = task.reward_message && task.reward_message.trim() !== ''
? replacePlaceholders(task.reward_message, rewardStrings) ? replacePlaceholders(task.reward_message, rewardStrings, task.name)
: task.name : task.name
// Формируем сообщения подзадач // Формируем сообщения подзадач
@@ -361,7 +367,7 @@ const formatTelegramMessage = (task, rewards, subtasks, selectedSubtasks, progre
subtaskRewardStrings[reward.position] = scoreStr subtaskRewardStrings[reward.position] = scoreStr
}) })
const subtaskMessage = replacePlaceholders(subtask.task.reward_message, subtaskRewardStrings) const subtaskMessage = replacePlaceholders(subtask.task.reward_message, subtaskRewardStrings, task.name, subtask.task.name)
subtaskMessages.push(subtaskMessage) subtaskMessages.push(subtaskMessage)
}) })

View File

@@ -12,7 +12,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
const { authFetch } = useAuth() const { authFetch } = useAuth()
const [name, setName] = useState('') const [name, setName] = useState('')
const [progressionBase, setProgressionBase] = useState('') const [progressionBase, setProgressionBase] = useState('')
const [rewardMessage, setRewardMessage] = useState('') const [rewardMessage, setRewardMessage] = useState('$name')
const [repetitionPeriodValue, setRepetitionPeriodValue] = useState('') const [repetitionPeriodValue, setRepetitionPeriodValue] = useState('')
const [repetitionPeriodType, setRepetitionPeriodType] = useState('day') const [repetitionPeriodType, setRepetitionPeriodType] = useState('day')
const [repetitionMode, setRepetitionMode] = useState('after') // 'after' = Через, 'each' = Каждое const [repetitionMode, setRepetitionMode] = useState('after') // 'after' = Через, 'each' = Каждое
@@ -108,7 +108,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
// Функция сброса формы // Функция сброса формы
const resetForm = () => { const resetForm = () => {
setName('') setName('')
setRewardMessage('') setRewardMessage('$name')
setProgressionBase('') setProgressionBase('')
setRepetitionPeriodValue('') setRepetitionPeriodValue('')
setRepetitionPeriodType('day') setRepetitionPeriodType('day')
@@ -156,7 +156,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
} }
// Предзаполняем сообщение награды // Предзаполняем сообщение награды
if (data.name) { if (data.name) {
setRewardMessage(`Выполнить желание: ${data.name}`) setRewardMessage('Выполнить желание: $name')
} }
} }
} catch (err) { } catch (err) {
@@ -181,7 +181,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
} }
const data = await response.json() const data = await response.json()
setName(data.task.name) setName(data.task.name)
setRewardMessage(data.task.reward_message || '') setRewardMessage(data.task.reward_message || '$name')
setProgressionBase(data.task.progression_base ? String(data.task.progression_base) : '') setProgressionBase(data.task.progression_base ? String(data.task.progression_base) : '')
setGroupName(data.task.group_name ?? '') setGroupName(data.task.group_name ?? '')
@@ -359,7 +359,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
setSubtasks(data.subtasks.map((st, index) => ({ setSubtasks(data.subtasks.map((st, index) => ({
id: st.task.id, id: st.task.id,
name: st.task.name || '', name: st.task.name || '',
reward_message: st.task.reward_message || '', reward_message: st.task.reward_message || '$subtaskName',
position: st.task.position !== undefined && st.task.position !== null ? st.task.position : index, position: st.task.position !== undefined && st.task.position !== null ? st.task.position : index,
rewards: st.rewards.map(r => ({ rewards: st.rewards.map(r => ({
position: r.position, position: r.position,
@@ -539,7 +539,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
setSubtasks([...subtasks, { setSubtasks([...subtasks, {
id: null, id: null,
name: '', name: '',
reward_message: '', reward_message: '$subtaskName',
position: subtasks.length, position: subtasks.length,
rewards: [] rewards: []
}]) }])
@@ -1018,7 +1018,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
<textarea <textarea
value={subtask.reward_message} value={subtask.reward_message}
onChange={(e) => handleSubtaskRewardMessageChange(index, e.target.value)} onChange={(e) => handleSubtaskRewardMessageChange(index, e.target.value)}
placeholder="Сообщение награды (опционально)" placeholder="Используйте $subtaskName для имени подзадачи, $name для имени задачи"
className="form-textarea" className="form-textarea"
rows={2} rows={2}
/> />
@@ -1335,7 +1335,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
id="reward_message" id="reward_message"
value={rewardMessage} value={rewardMessage}
onChange={(e) => setRewardMessage(e.target.value)} onChange={(e) => setRewardMessage(e.target.value)}
placeholder="Используйте ${0}, $0 для указания проектов (\\$0 для экранирования)" placeholder="Используйте $name для имени задачи, ${0}, $0 для проектов (\\$0 для экранирования)"
className="form-textarea" className="form-textarea"
rows={3} rows={3}
/> />